KivyでOpenCV

2017-12-05(火)

他のGUIで表示してみる

OpenCVのPythonモジュールではQtが絡むと色々と厄介になる。 ビルド時のライブラリの依存の問題でシステムに入ってるQtやAnacondaに入ってるQtやその他諸々のQtをCMakeが拾ってきて,何も考えずにビルドするとビルドは問題なく終わるのに参照次第ではimportすら出来ない。(当たり前) という訳でQt抜きのパッケージになるケースが非常に多い。

PyQtPySideかという選択肢もあるが,試しにKivyを使ってみたら結構簡単だった。 頑張ればOpenCVでのQt-highguiみたいにSaveボタンを付けたり(これは簡単),拡大して画素値を出したりも出来そうだ。

サンプル

こんな感じ

こんな感じでWebCAM-スライダ-ボタンという並び。KivyのSliderは何故かラベルが無いのでちょっと工夫して付け足してる。

構造としてはAppを継承したメインのクラスがあり,buildでUIの構築(と初期設定),SliderとButtonにbindしたコールバック,Clock.schedule_intervalで指定してるupdateで更新。 update内でOpenCV周りの処理を行なってImageのtextureを書き換えて表示といった流れになる。

# -*- coding: utf-8 -*-
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.slider import Slider
from kivy.uix.image import Image
from kivy.uix.label import Label
from kivy.graphics.texture import Texture
from kivy.clock import Clock
import cv2

class CvCamera(App):
    def build(self): #UIの構築等
        self._cap = cv2.VideoCapture(0)
        # ButtonやSlider等は基本size_hintでサイズ比率を指定(絶対値の時はNoneでsize=)
        # Verticalの中に置くhorizontalなBoxLayout (ここだけ2column)
        layout2 = BoxLayout(orientation='horizontal', size_hint=(1.0, 0.1))
        self.s1Label = Label(text = 'Slider', size_hint=(0.3, 1.0), halign='center')
        slider1 = Slider(size_hint=(0.7, 1.0))
        slider1.bind(value=self.slideCallback)
        # 日本語フォントを使いたいときはfont_nameでフォントへのパス
        button1 = Button(text='ボタン', size_hint=(1.0, 0.1), font_name='/usr/local/texlive/texmf-local/fonts/truetype/cjk-gs-integrate/ipag.ttf')
        button1.bind(on_press = self.buttonCallback) #bindでイベントごとにコールバック指定
        # Imageに後で画像を描く
        self.img1 = Image(size_hint=(1.0, 0.7))
        # Layoutを作ってadd_widgetで順次モノを置いていく(並びは置いた順)
        layout = BoxLayout(orientation='vertical')
        layout.add_widget(self.img1)
        # ここだけ2columnでLabelとSliderを並べる
        layout.add_widget(layout2)
        layout2.add_widget(self.s1Label)
        layout2.add_widget(slider1)
        # 1columnに戻る
        layout.add_widget(button1)
        #カメラ待ち
        while not self._cap.isOpened(): 
            pass
        # 更新スケジュールとコールバックの指定
        Clock.schedule_interval(self.update, 1.0/30.0)
        return layout

    def slideCallback(self, instance, value):
        # Slider横のLabelをSliderの値に
        self.s1Label.text = 'Slider %s' % int(value)

    def buttonCallback(self, instance):
        # 何かのフラグに使える
        print('Buttn <%s> is pressed.' % (instance))

    def update(self, dt):
        # 基本的にここでOpenCV周りの処理を行なってtextureを更新する
        ret, img = self._cap.read()
        img = cv2.flip(img, 0)
        texture1 = Texture.create(size=(img.shape[1], img.shape[0]), colorfmt='bgr')
        texture1.blit_buffer(img.tostring(), colorfmt='bgr', bufferfmt='ubyte')
        self.img1.texture = texture1

if __name__ == '__main__':
    CvCamera().run()

Category: Memo Tagged: Kivy OpenCV Python