Python3

Pythonをはじめよう 第5回 cameraサンプルを快適に動作させる

更新日:

はじめに

前回の第4回でサンプルプログラムのカメラを動作させてみましたが、カメラの映像がスムーズに表示されませんでした。

そこで少し改良をほどこして快適に動作させようというのが今回のテーマです。

gstreamerをインストールしてみたものの特に改善される事がなかったため別の方法を実施することにしました。

Pythonのバージョンも影響しているような気がします。

改良のポイント

考えるところの問題点は、kivyのCameraコントロール部品では無いかと思ったので、これをImageコントロールに変更しOpenCVで取得したカメラ映像をImageコントロールに出力してあげることで解決できるに違いない。

ということで早速カメラサンプルプログラムを改良していきます。

元のソース

'''
Camera Example
==============

This example demonstrates a simple use of the camera. It shows a window with
a buttoned labelled 'play' to turn the camera on and off. Note that
not finding a camera, perhaps because gstreamer is not installed, will
throw an exception during the kv language processing.

'''

# Uncomment these lines to see all the messages
# from kivy.logger import Logger
# import logging
# Logger.setLevel(logging.TRACE)

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
import time
Builder.load_string('''
<CameraClick>:
    orientation: 'vertical'
    Camera:
        id: camera
        resolution: (640, 480)
        play: False
    ToggleButton:
        text: 'Play'
        on_press: camera.play = not camera.play
        size_hint_y: None
        height: '48dp'
    Button:
        text: 'Capture'
        size_hint_y: None
        height: '48dp'
        on_press: root.capture()
''')


class CameraClick(BoxLayout):
    def capture(self):
        '''
        Function to capture the images and give them the names
        according to their captured time and date.
        '''
        camera = self.ids['camera']
        timestr = time.strftime("%Y%m%d_%H%M%S")
        camera.export_to_png("IMG_{}.png".format(timestr))
        print("Captured")


class TestCamera(App):

    def build(self):
        return CameraClick()


TestCamera().run()

 

修正後のソース

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
import time
import cv2
from kivy.uix.image import Image
from kivy.graphics.texture import Texture
from kivy.properties import StringProperty, ObjectProperty
from kivy.clock import Clock

Builder.load_string('''
<CameraClick>:
    orientation: 'vertical'
    #Camera:
    #    id: camera
    #    index: 0
    #    resolution: (640, 480)
    #    play: False
    Image:
        id: camera
        size_hint: None, None
        size: 640, 480
    ToggleButton:
        text: 'Play'
        #on_press: camera.play = not camera.play
        on_press: root.play()
        size_hint_y: None
        height: '48dp'
    Button:
        text: 'Capture'
        size_hint_y: None
        height: '48dp'
        on_press: root.capture()
''')


class CameraClick(BoxLayout):
    image_texture = ObjectProperty(None)
    image_capture = ObjectProperty(None)
    def play(self):
        global flg
        flg = not flg
        if flg == True:
            self.image_capture = cv2.VideoCapture(0)
            Clock.schedule_interval(self.update, 1.0 / 30)
        else:
            Clock.unschedule(self.update)
            self.image_capture.release()
    def update(self, dt):
            ret, frame = self.image_capture.read()
            if ret:
                buf = cv2.flip(frame, 0)
                image_texture = Texture.create(size=(frame.shape[1], frame.shape[0]), colorfmt='bgr')
                image_texture.blit_buffer(buf.tostring(), colorfmt='bgr', bufferfmt='ubyte')
                camera = self.ids['camera']
                camera.texture = image_texture
    def capture(self):
        '''
        Function to capture the images and give them the names
        according to their captured time and date.
        '''
        camera = self.ids['camera']
        timestr = time.strftime("%Y%m%d_%H%M%S")
        camera.export_to_png("IMG_{}.png".format(timestr))
        print("Captured")


class TestCamera(App):

    def build(self):
        return CameraClick()

flg = False
TestCamera().run()

いろいろと参考にしながら改良したので無駄な部分などあるかもしれませんが、ご了承ください。

 

ちょこっと解説

kv言語側 Cameraコントロールの撤去とImageコントロールの設置

・14行目から18行目までのCameraコントロールをコメントにします。

・19行目から22行目までが追加したImageコントロールです。IDをcameraとしたのがミソです。

・PLAYボタン(ToggleButton)がクリックされたときにCameraコントロールのplayプロパティをセットする処理(25行目)をPython側のplayメソッドを実行するように(26行目)に書き換えます。

 

Python側 playメソッドの実装

・40行目から48行目までがplayメソッドで、PLAYToggleButtonが押されるたびに実行されます。

ToggleButtonの状態を保持するために flg を利用しています。押されていない状態は False 押されると Trueに変化します。

Trueの場合1番目のカメラ映像を取り込む準備をします。また、1/30秒間隔で映像を更新するようにスケジュールします。

Falseの場合スケジュールをキャンセルしカメラ映像取込を終了します。

Python側 updateメソッドの実装

・49行目から56行目までがカメラ映像を取り込んでImageコントロールに出力する処理になります。

OpenCVの画像をそのままkiviのImageに出力すると上下が反転してしまうためこれを修正(52行目)

テクスチャを作成しますが、kiviのImageの高さと幅の指定がOpenCVと逆になるそうです。色指定もRGBではなくBGRになります。(53行目)

反転の修正した画像情報bufをバイト列でテクスチャに出力します。(54行目)

kv言語で追加したImageコントロールのID:cameraを取得します。(55行目)

このテクスチャをImageコントロールのテクスチャプロパティにセットします。(56行目)

python側 その他

・処理の開始前にflgをFalseで初期化しておきます。(73行目)

・5行目から9行目まで、import文を追加します。

 

最後に

PLAYボタンを押したときに若干時間を要しますが、カメラの映像はスムーズに表示できるようになりました。

 

お行儀の悪いところとか指摘いただけるとうれしく思います。

 

 

スポンサードリンク

スポンサードリンク

-Python3
-, ,

Copyright© あきらちんの技術メモ , 2024 All Rights Reserved Powered by STINGER.