日々ブログ

当サイトは、アフィリエイトプログラムにより商品をご紹介しています

【プログラミングのお話】kivyとopencvを使ってカメラアプリを作る

pythonopencvは画像処理を試すのに非常に便利なのですが、たまにUIが欲しくなります。
なので、今回はkivyで映像の表示と画像の保存まで行おうと思います。

kivyとopencvのインストール

pip からインストールします。

pip install kivy

次にopencvのインストールです。

pip install opencv-python

opencvと連携して映像を表示する

基本的にkivyはアプリの内容を初回実行時に画面部品をビルドしたあとは再度実行されません。
そこで、ビルド時に画面部品の枠組みを作って、画面部品のテクスチャデータだけを更新することで、動画を表示させたいと思います。
作成したコードは下記のようになりました。

from logging import getLogger,StreamHandler, DEBUG

logger=getLogger(__name__)
handler=StreamHandler()
handler.setLevel(DEBUG)
logger.setLevel(DEBUG)
logger.addHandler(handler)
logger.propagate=False

import cv2

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
from kivy.graphics.texture import Texture
from kivy.graphics import Rectangle
from kivy.clock import Clock
from kivy.core.window import Window


# デバイスIDは0
cap_camera = cv2.VideoCapture(0)
Window.size=(1920,1080)


class CameraApp(App):
    def __init__(self,):
        super().__init__()
        self.widget_camera=[]
        Clock.schedule_interval(self.update,0.01)

    def build(self,):
        app_layout=BoxLayout(orientation="vertical")
        self.widget_camera=Widget()
        app_layout.add_widget(self.widget_camera)
        with self.widget_camera.canvas:
            self.camera_rectangle=Rectangle(pos=(200,200),size=(640,480))
        return app_layout
    
    def update(self,dt):
        try:
            ret,frame=cap_camera.read()
            if ret:
                frame_resize=cv2.resize(cv2.flip(frame,0),(640,480))

                camera_texture = Texture.create(size=(640,480),colorfmt='bgr',bufferfmt='ubyte')
                camera_texture.blit_buffer(frame_resize.tobytes(),colorfmt='bgr',bufferfmt='ubyte')
                self.camera_rectangle.texture=camera_texture
        except KeyboardInterrupt:
            logger.info("Keyboard interrupt")
        pass


if __name__=="__main__":
    CameraApp().run()
    cap_camera.release()

実行すると、下記のような映像が表示されます。
遅延時間は少々あるけどフレームレートは落ちておらず、全然使えるレベル。

あとは画面上にパーツを付け足して関数と関連付けるだけ

あとは画面上にパーツを付け加えていきます。 kivyの仕様上、build関数内で定義していきます。

button_save=Button(on_press=self.save_frame,text="save",size=(100,50),size_hint=(None,None),pos=(300,300))
app_layout.add_widget(self.widget_camera)

save_frame関数はしたのように記述しました。

   def save_frame(self,btn):
        try:
            logger.info("save latest frame")
            cv2.imwrite("sample.png",self.latest_frame)
        except Exception as e:
            logger.error(e)
        return

ちなみに、ボタンサイズの変更はsize だけでなくsize_hintも合わせて指定しないと、sizeの指定が有効にならないので注意が必要です。
このあたり、htmlとかに親しみがあると口説い感じがする。
htmlが画面設計に適した言語であること実感します。

kivyのパッケージ方法

kivyで作成したアプリケーションは基本的にPyinstallerで行います。
プラットフォームによってはそもそもパッケージできないものもあるので、クロスプラットフォームを実現するのは難しいかも。

pip install pyinstaller

パッケージのコマンドは下記です。

python -m PyInstaller --name package_name app_path/main.py

プラットフォームごとの詳細は下記の公式サイトにまとめてありました。

kivy.org