手持ちのラズパイ4にカメラモジュールV2.1を付けたので、試しに簡単なプログラムを作成してみました。その際色々苦労したので、調べ直す必要がないようにメモを残します。
#openCVを使ったプログラム
openCVにはカメラ取り込む機能もあり、また画面表示の機能もあるので非常に便利です。
import cv2
camera = cv2.VideoCapture(0)
camera.set(cv2.CAP_PROP_FRAME_WIDTH,640)
camera.set(cv2.CAP_PROP_FRAME_HEIGHT,480)
while True:
_,image = camera.read()
#エフェクトを追加する行
cv2.imshow('camera',image)
key = cv2.waitKey(1)
if key != -1:
break
camera.release()
cv2.destroyAllWindows()
ウィンドウ上でキーを押すと、停止するようになっています。
##プログラムの説明
カメラの初期化は下の部分で行っています。画面サイズは特定の値を入れないと画像が崩れます。またVideoCapture
の引数はデバイスIDなので環境により変化するかもしれません。
camera = cv2.VideoCapture(0)
camera.set(cv2.CAP_PROP_FRAME_WIDTH,640)
camera.set(cv2.CAP_PROP_FRAME_HEIGHT,480)
連続して画像を撮るのは下の部分で行っています。camera.read
メソッドによりループが回る度にframe
に新しい画像データを入れています。
while True:
_,image = camera.read()
ウィンドウ表示は下の部分で行っています。waitKey
メソッドがないと表示されません。
cv2.imshow('camera',image)
key = cv2.waitKey(1)
開いたウィンドウを閉じる処理は下の部分で行っています。
camera.release()
cv2.destroyAllWindows()
#picameraとpygameを使ったプログラム
openCVだけもよいのですが、同じウィンドウ上にアイコン表示やマウス操作も考えるとpygameを使った方が便利そうです。(ついでに、画像取り込みをpicamera
モジュールにしてみました。)ネットではcapture
メソッドを使っているサイトが多々ありましたが、今回はcapture_continuous
メソッドを使っています。
import picamera
from picamera.array import PiRGBArray
import pygame
import cv2 #エフェクト用
width = 480
height = 640
camera = picamera.PiCamera()
camera.resolution = (height,width)
pygame.init()
screen = pygame.display.set_mode((width,height))
rawCapture = PiRGBArray(camera,size=(height,width))
for frame in camera.capture_continuous(rawCapture,format='rgb',use_video_port=True):
image = frame.array
#エフェクトを追加する行
surf = pygame.surfarray.make_surface(image)
screen.blit(surf,(0,0))
pygame.display.flip()
rawCapture.truncate(0)
終了する際はCtrl+Cでプログラムを止めてください。
##プログラムの説明
カメラの初期化は下の部分で行っています。resolution
で取り込む画像の大きさを決めていますが、何故か縦と横の並びが逆になっています。
camera = picamera.PiCamera()
camera.resolution = (height,width)
pygameのウィンドウ表示は下の部分で行っています。
pygame.init()
screen = pygame.display.set_mode((width,height))
連続して画像を撮るのは下の部分で行っています。capture_continuous
メソッドはgenerator
を作成し、ループが回る度にframe
に新しい画像データを入れています。なお、use_video_port=True
は直にビデオポートからデータを取り出すことにより高速化を図るものです。また、最後のtruncate
メソッドがないと新しい画像を取り込むことができません。
rawCapture = PiRGBArray(camera,size=(height,width))
for frame in camera.capture_continuous(rawCapture,format='rgb',use_video_port=True):
....
....
rawCapture.truncate(0)
pygameの描写に関しては下の部分で行っています。frame.array
の部分で画像をRGBの3次元配列(480,640,3)にしています。それをpygame.surfarray.make_surface
メソッドでpygameに使えるsurface
形式に変換し、blit
メソッドで画面に書き込み、flip
メソッドで画面更新をしています。
image = frame.array
surf = pygame.surfarray.make_surface(image)
screen.blit(surf,(0,0))
pygame.display.flip()
#エフェクトの追加(openCV、picamera+pygame共通)
(picamera
モジュールにもエフェクトがありますが)ここではopenCVのエフェクトを入れてみます。プログラムの#エフェクトを追加する行
を下のように変更すると、エッジ検出の画像に変えることができます。
image = cv2.Canny(image,100,200)
画像データを受け取ったimage
変数はRGBの配列形式のデータになっておりnumpyの配列と同じように演算が可能なので、直接RGBの数値を操作し画像編集をすることもできます。
#さいごに
どの方法でも画像読み込みが遅いのが気になります。もっと高速化できる方法がないかを調べたいと思います。