20
26

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Python KivyでOpencvやPillowで画像を表示する方法

Last updated at Posted at 2017-10-09

PythonのGUIライブラリKivyでOpenCVで読み込んだ画像を表示する方法です。
またPillowでの表示する方法についても説明します

結果画像
test.jpg

補足

OpenCVで画像を表示する方法については@IMUさんのツィートを参考にしてこちらでの検証結果を追加したものになります。

今回使用した画像ですがぱたくそから借りました。

ハーブから吸蜜する働き蜂

サンプルコードについて

今回の内容をGithubにあげました。

Github:https://github.com/okajun35/kivy_show_opencv_pillow

OpenCVで読み込んだ画像を表示する

大きく分けて次の2つの方法があると思います。

  • 一時的に画像ファイルに書き出したしてkivy.uix.image() で表示する
  • メモリ上に読み込んだ画像 をblit_buffer() を使用して表示する

一時的に画像ファイルに書き出したして kivy.uix.image() で表示する

この方法はさほど難しくなくOpenCVで読み込んだ画像をcv2.imwrite()を使用して保存します。
その後その保存した画像をkivy.uix.image()を使用して表示します。

KivyのAppクラスにはuser_data_dirでconfig.iniで設定されたデータを保存するパスを格納しています。
user_data_dirを使用して画像を保存する場所を指定して保存します。
あとはImageを使用して保存された画像を表示します。
保存された画像に関してはAppクラスにはon_end()といって終了時に呼ぶメソッドがあるので、
on_end()内で保存した画像を削除します。

参考

メモリ上に読み込んだ画像をblit_buffer()を使用して表示する

一時的に画像ファイルに書き出さずメモリ上のやり取りで済ませたい場合は、blit_buffer()を使用することでTextureオブジェクトにバイト列の情報を吐き出すことが可能です。
blit_buffer()を使用すればOpenCVで読み込んだ画像を表示することが可能ですが次の3点に注意することが必要です。

  • OpenCVの画像の幅と高さは画像オブジェクトのshape[]に入っているが、**shapeに格納されている情報は「高さ」、「横幅」、「チャンネル」の順で、Kivyのsize()は「横幅」、「高さ」**なので順番が違う。
  • OpenCVの画像の色の並びはBGRでKivyのblit_bufferでの色の並びはデフォルトではRGBなので並びが違う。
  • OpenCVの原点座標は左上だが、Kivyの原点座標は左下なのでそのままだと画像が上下反転される。

この3点の対応ですがOpenCVで対応するのとKivyで対応する2パターンがあります。

OpenCVで対応する方法

コードは以下の通りです。


import numpy as np
import cv2

from PIL import Image

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics.texture import Texture
from kivy.graphics import Rectangle


class MyApp(App):
        title = "opencv on kivy"

        def build(self):
            img = cv2.imread('kai_058Kazukiya17103_TP_V.jpg',1)

            if img is None:
                print('load image')
                sys.exit(1)
        
            # 表示確認用
            cv2.imshow('opencv_normal', img)


            widget = Widget()

            ''' pattern1 (openCVの機能で表示)  '''
            img2 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # openCVの色の並びはBGRなのでRGBに直す
            img2 = cv2.flip(img2, 0)    # Kivyの座標の原点は左下なので上下反転する
            
            # OpenCVの座標shapeは「高さ」、「幅」、「チャンネル」の順番 Kivyのsizeは(幅、高さ)なので逆にする必要がある
            texture = Texture.create(size=(img2.shape[1], img2.shape[0]))
            texture.blit_buffer(img2.tostring())

            with widget.canvas: # 描画
                Rectangle(texture=texture ,pos=(0, 0), size=(img2.shape[1], img2.shape[0]))

まず、読み込んだ画像をcvtColor()の「COLOR_BGR2RGB」で色の並びをBGRからRGBに変更します。
次にflip(<読み込んだ画像>, 0) で画像を上下反転します。
次にKivyでテクスチャーで表示しますが、Texture.create()でテクスチャの設定をします。
その際、size=(img2.shape[1], img2.shape[0])で画像の横幅と高さを指定します。
あとはblit_buffer()で画像情報をバイト列で吐き出します。

後はcanvasで、画像と同じ大きさの矩形を描画してそのテクスチャーにblit_buffer()を行ったテクスチャーを指定することで表示できるようになります。

Kivyで対応する方法

OpenCVで表示の下準備をすることもできますが、Kivyで表示するのであればKivyで表示の準備をした方がよいかと思います。kivyで表示する場合は以下の方法になります。

''' pattern2 (kivyの機能のみで表示)  '''

texture = Texture.create(size=(img.shape[1], img.shape[0]), colorfmt='bgr', bufferfmt='ubyte') # BGRモードで用意,ubyteはデフォルト引数なので指定なくてもよい
texture.blit_buffer(img.tostring(),colorfmt='bgr', bufferfmt='ubyte')  # ★ここもここもBGRで指定しないとRGBになって色の表示がおかしくなる
texture.flip_vertical()    # 画像を上下反転する

with widget.canvas:
    Rectangle(texture=texture ,pos=(0, 0), size=(img.shape[1], img.shape[0]))

OpenCVの場合と違うのはテクスチャーを作成するcreate()で指定する際にcolorfmt='bgr'とすることで画像の並びをBGRに対応するようにします。※colorfmtのデフォルト値は'rgb'です。
またblit_buffer()実行時にもcolorfmt='bgr'を指定します。こうすることで画像の色の並びがBGRの画像でも表示できます。
さらにflip_vertical()で画像を上下反転させます。
以上でOpenCVで処理していたのと同じように画像を表示させることができます。

参考 グレースケール画像を表示させる場合

result.png

OpenCVで処理したグレースケール画像を表示させる場合ですが、Kivyではカラーチャンネルが1個の画像は表示できません。表示させる場合はOpenCV側で疑似的に3チャンネルに変換して表示させます。


# 画像をグレイスケールに変換
gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
gray_to_rgb_img = cv2.cvtColor(gray_img, cv2.COLOR_GRAY2RGB)    # bilt_bufferでは1チェンネルのグレイ画像は表示できないので3チャンネルの画像に変換する

Pillowで読み込んだ画像を表示する

test2.jpg

Pillowでの表示はOpenCVほど難しくはないです。
以下が該当部分のコードです。

pillow_img = Image.open('kai_058Kazukiya17103_TP_V.jpg', 'r')
texture = Texture.create(size=pillow_img.size) 

texture.blit_buffer(pillow_img.tobytes())

texture.flip_vertical()    # 
with widget.canvas:
    Rectangle(texture=texture ,pos=(0, 0), size=pillow_img.size)

OpenCVと違いPillowの場合は画像の色の並びがRGBであることと画像の「横幅」、「高さ」の並びもKivyと一緒なので変換はいりません。ただし座標の原点座標がPillowは左上に対してKivyは左下が原点なのでflip_vertical()を使用して画像を上下反転させる必要があります。

20
26
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
26

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?