WEBカメラなどUVC規格のカメラから、Pythonで画像を取得する方法で一番有名なのは、OpenCVのVideoCaptureクラスを使う方法ではいでしょうか。
以下のような簡単なプログラムで画像が取得できます。(事前にpip install opencv-python
しておいてください)
>>> import cv2
>>> cap = cv2.VideoCapture(0) # 複数ある場合は適切なIDを指定してください
>>> ret, img = cap.read() # ret必須です
表示を行いたい時は、以下を実行してください。
>>> cv2.imshow("img", img)
>>> cv2.waitKey(1)
さて、ret, img = VideoCapture.read()
は、ret = VideoCapture.grab()
とret, img = VideoCapture.retrieve()
が一度ずつ行われます。それぞれのメソッドの特徴を以下にあげます。
- VideoCapture.grab()
- ・カメラから次のフレームを取得し、バッファーに入れます。
- VideoCapture.retrieve()
- ・バッファにあるフレームを画像配列(NumPyの配列)にして取得します。
- ・バッファが空の時、
ret = False
、img = None
。 - ・バッファが空ではない時には画像を取り込みますが、キューではないので空にしたりはしません。
grab()
せずにretrieve()
を連続実行すると同じ画像が撮り込まれます。(OpenCV4.1.0)
grab()
してから、retrieve()
した場合。
>>> import cv2
>>> cap = cv2.VideoCapture(0)
>>> cap.grab()
True ←撮像成功
>>> ret, img = cap.retrieve()
>>> ret
True ←画像として取り込み成功
>>> ret, img = cap.retrieve()
>>> ret
True ←画像として取り込み成功、ただし上と同じ画像
grab()
せずに、retrieve()
した場合。
>>> import cv2
>>> cap = cv2.VideoCapture(0)
>>> ret, img = cap.retrieve()
>>> ret
False ←取り込み失敗
>>> img is None
True ←imgはNone
マルチスレッドなどで実行すると、撮像が追随しない場合があります。つまり古い画像が取り込まれる場合があります。常に新しい画像を取得したい場合には工夫が必要です。解決方法が以下のページにありました。
how to get the latest frame from capture device (camera) in opencv [python]
Queueモジュールを利用します。まず、別スレッドで以下を常時繰り返します。
VideoCapture.read()
で画像を撮り込む ⇒ キューに画像が入っている時は画像を取り出し、空の時はキューに画像を入れる
次に、メインスレッドからキューに入っている画像を撮りだします。常に新しい画像になっているはずです。仮にキューが空だった時は、キューに画像が入るまで待機してくれます。(Queue.get()
の機能)
こちらに自作サンプル「camera_uvc.py」を置いておきます。ダウンロードして、Libフォルダにコピーしてください。以下のような感じで使います。
>>> import camera_uvc import *
>>> cap = BufferlessCapture()
>>> img = cap.read()
>>>
>>> help(BufferlessCapture) ← Helpでメソッドの一覧が見れます
Help on class BufferlessCapture in module camera_uvc:
class BufferlessCapture(builtins.object)
| Get the latest frame from capture device (camera).
|
| Methods defined here:
|
| __init__(self, id=0, width=640, height=480, exposure=-6)
| Initialize
|
| read(self)
| Read
ひとこと
ライブラリによって撮像の考え方がずいぶん異なるな~と思いました(例えば、opencv-pythonとpypylon)。理解するのが大変。