##はじめに
在宅勤務がはじまって、WEBカメラの価格が高騰しました。
この期間に買ったへなちょこカメラでopenCVでキャプチャするときの解像度とフレームレートの変更に苦労したのでまとめておきます。
##やったこと
Jetsonで、openCVを用いるときに、WEBカメラのコーデックを変えようとしたらCAP_PROP_FOURCCのsetでunhandled propertyといわれたので、v4l2srcを入力、appsinkを出力にgstreamerを利用して、これをvideoCaptureの引数文字列として指定することで、カメラのコーデックと解像度を変更しました。
##OpenCVでのフレームレート変更
通常は
【Python】OpenCVでWebカメラのフレームサイズ、FPS設定にあるように
cap=videoCapture(0)
video_input.set(cv2.CAP_PROP_FPS, 30)
video_input.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
video_input.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
とかやると解像度の変更ができます。
このとき、変更先の解像度とFPSはカメラでサポートされているものである必要があり、このリストはv4l2-ctlコマンドなどで取得できます。以下は今回の対象のへなちょこカメラの出力です。
XavierNX:~/docker/darknet/work$ v4l2-ctl -d /dev/video1 --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
Index : 0
Type : Video Capture
Pixel Format: 'MJPG' (compressed)
Name : Motion-JPEG
Size: Discrete 1920x1080
Interval: Discrete 0.033s (30.000 fps)
Size: Discrete 1280x720
Interval: Discrete 0.033s (30.000 fps)
Size: Discrete 640x360
Interval: Discrete 0.033s (30.000 fps)
Size: Discrete 320x180
Interval: Discrete 0.033s (30.000 fps)
Size: Discrete 1920x1080
Interval: Discrete 0.033s (30.000 fps)
Index : 1
Type : Video Capture
Pixel Format: 'YUYV'
Name : YUYV 4:2:2
Size: Discrete 640x360
Interval: Discrete 0.033s (30.000 fps)
Size: Discrete 640x360
Interval: Discrete 0.033s (30.000 fps)
Size: Discrete 640x360
Interval: Discrete 0.033s (30.000 fps)
Size: Discrete 640x360
Interval: Discrete 0.033s (30.000 fps)
Size: Discrete 640x360
Interval: Discrete 0.033s (30.000 fps)
XavierNX:~/docker/darknet/work$
v4l2-ctlがなければ、apt install v4l-utilsでインストールが可能です。
##問題点
- 問題点1:OpenCVがYUYVでカメラをオープンしようとする
上記の出力例だと、OPENCVは、YUYVの1個目(1個目かどうかは自信ないです)の640x360-30FPSでオープンしようとすることにあります。
この挙動を変更し、MJPG形式にカメラを切り替えない限り、このへなちょこカメラでは640x360以外の解像度が設定できません。 - 問題点2:VideoCapturePropertiesではCAP_PROP_FOURCC でフォーマット変更ができることになっていますが、やってみるとunhandled propertyとなりJetson上では変更できません。
問題点2について
OpenCVのカメラ読み込みを高速化し、遅延時間も短くするなどを参照すると
import cv2
cap=cv2.VideoCapture(1)
cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'));
video_input.set(cv2.CAP_PROP_FPS, 30)
video_input.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
video_input.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
while True:
ret, frame_read = cap.read()
cv2.imshow('Read',frame_read )
cv2.waitKey(30)
cap.release()
ってやると動く気がします。
しかしなぜか、やってみるとJETSON上では
[ WARN:0] global /home/nvidia/host/build_opencv/nv_opencv/modules/videoio/src/cap_gstreamer.cpp (1184) setProperty OpenCV | GStreamer warning: GStreamer: unhandled property
っていわれ、MJPGに切り替えることができません。
実際にOpenCV4.11のgitのCAP_gstreamer.cppを見ると set関数ではCAP_PROP_FORCCは定義されておらずunhandled propertyにおちるようにかかれている気がします。
MACとかでやると動くのでvideoCapture でVIDEOデバイスをあけるときの実装が別のコードを利用するような気もしますが、Jetsonでの動作はコード上は As designedな動作に見えます。
#解決策
この道をすすむことはあきらめ、v4l2srcとappsinkをgstreamerで指定することで、コーデック解像度、FPSの変更を行いました。
import cv2
src = 'v4l2src device=/dev/video1 ! image/jpeg,width=1280, height=720, framerate=(fraction)30/1 !jpegdec !videoconvert ! appsink'
cap=cv2.VideoCapture(src)
while(cap.isOpened()):
ret, frame_read = cap.read()
cv2.imshow('Read',frame_read )
cv2.waitKey(30)
cap.release()
~
他にもgstreamerのvideoinput部分を書き換えるといろいろできて楽しそうです。
v4l2srcのドキュメント
とか、gst-launch-1.0にのせるパラメータで検索するといろいろ出てきます。