LoginSignup
1
0

cv2.VideoCapture(0)は700番(cv2.CAP_DSHOW)を使え

Posted at

cv2.VideoCapture(0)が遅い

最近GStreamer付きOpenCVをビルドして日常使いしているのだが、Webカメラの起動が妙に遅い(3秒ほどかかる)。この3秒の間に、「指定されたDLLが見つかりません」のようなエラーが出るんじゃないかと精神衛生に悪い。
あと、毎回毎回GStreamerのWARNがでてうるさいというのもある。今日、この対処方法を知ったのでここに書き残しておく。
image.png

cv2.VideoCapture(0,cv2.CAP_DSHOW)を使え

結論から言えば、

cv2.VideoCapture(0,cv2.CAP_DSHOW)

または

cv2.VideoCapture(0,700)

を使えばよいだけの話である。
ほとんどの人はVideoCaptureの第二引数を意識したことがないだろうが、GStreamerのパイプラインを記述するときにはcv2.CAP_GSTREAMERをよく使う。で、僕が知っていたのはcv2.CAP_GSTREAMER(=1800)とcv2.CAP_FFMPEG(=1900)だけだったので、てっきりwebカメラのキャプチャにもこのいずれかを使用しているものだと思い込んでいたのだが、何やらたくさんあるようだ。(数字としては、CAP_ANYが最小値0で、CAP_OBSENSORが最大値2600である。)
image.png

調査

第二引数を省略するとデフォルトでcv2.CAP_ANY(=0)が指定され、以下の中から使えるものを自動的に選ぶという仕様だそうだ。ここで、cv2.CAP_GSTREAMERやcv2.CAP_FFMPEGをWebカメラに対して使用したらどうなるのか?を確認しておく。

>>> cap=cv2.VideoCapture(0,cv2.CAP_FFMPEG)
>>> cap.read()
(False, None)
>>> cap=cv2.VideoCapture(0,cv2.CAP_GSTREAMER)
[ WARN:0@1278.266] global cap_gstreamer.cpp:1173 cv::GStreamerCapture::isPipelinePlaying OpenCV | GStreamer warning: GStreamer: pipeline have not been created
[ WARN:0@1278.266] global cap.cpp:344 cv::VideoCapture::open VIDEOIO(GSTREAMER): backend is generally available but can't be used to capture by index
>>> cap.read()
(False, None)
>>>

といった感じで、cap.read()の第一戻り値がFalseになってしまい、captureできていないことがわかる。では、実際には何が使われているのだろうか?VideoCaptureの第二引数に1から2600の数字を入れ、cap.read()の第一戻り値がTrueになるところを観測する。以下のコードを書いてみた。

import cv2
for i in range(1,2601): #0を含まず2600まで
    print(i,end=",") #何が起こるかわからないので処理前に数字だけ出しておく    
    cap=cv2.VideoCapture(0,i) #cv2.CAP_XXXXの代わりに数字で
    ret,frame=cap.read()
    if ret: #ret==True
        print(f"\n\n{i} {ret}\n") #表示
    cap.release() #解放

結果は以下である(冗長なところは省略した)

出力
1,2,3,...,700,

700 True

701,702,703,...,1400,

1400 True

1401,1402,...,1800,
[ WARN:0@6.563] global cap_gstreamer.cpp:1173 cv::GStreamerCapture::isPipelinePlaying OpenCV | GStreamer warning: GStreamer: pipeline have not been created
[ WARN:0@6.563] global cap.cpp:344 cv::VideoCapture::open VIDEOIO(GSTREAMER): backend is generally available but can't be used to capture by index
1801,1802,...,2000,
[ WARN:0@6.581] global cap.cpp:344 cv::VideoCapture::open VIDEOIO(CV_IMAGES): backend is generally available but can't be used to capture by index
2001,2002,...,2200,
[ WARN:0@6.596] global cap.cpp:344 cv::VideoCapture::open VIDEOIO(CV_MJPEG): backend is generally available but can't be used to capture by index
2201,2202,...,2600,
[ERROR:0@6.629] global obsensor_uvc_stream_channel.cpp:158 cv::obsensor::getStreamChannelGroup Camera index out of range
[ WARN:0@6.629] global cap.cpp:344 cv::VideoCapture::open VIDEOIO(OBSENSOR): backend is generally available but can't be used to capture by index

なるほど、700番(=cv2.CAP_DSHOW)と1400番(=cv2.CAP_MSMF)でキャプチャに成功していることが分かった。1800番のCAP_GSTREAMERでは当然の権利のようにWARNを吐き、CAP_IMAGES = 2000、CAP_OPENCV_MJPEG = 2200、CAP_OBSENSOR = 2600でそれぞれ違うWARNを吐いている。

700番(DSHOW)か1400番(MSMF)か

とにかく、Webカメラのキャプチャには700番と1400番が使えることが分かったので、それぞれのパフォーマンスを測ってみたい

import cv2
import time

def calcTakenTimeAvg(num): #10回平均
    save=[]
    save2=[]
    for i in range(10):
        start=time.time()
        cap=cv2.VideoCapture(0,num)
        take_time=time.time()-start #かかった時間
        save.append(take_time)

        start2=time.time()
        ret,frame=cap.read()
        take_time2=time.time()-start2 #かかった時間2
        save2.append(take_time2)
        cap.release()
        print(f"{ret}",end=",")
    print()
    print(num)
    print(f"VideoCapture所要 平均時間 {sum(save)/10}、最大 {max(save)}、最小 {min(save)}")
    print(f"cap.read() 所要 平均時間 {sum(save2)/10}、最大 {max(save2)}、最小 {min(save2)}")
    print()

calcTakenTimeAvg(700)
calcTakenTimeAvg(1400)
出力
True,True,True,True,True,True,True,True,True,True,
700
VideoCapture所要 平均時間 0.5267948865890503、最大 0.569263219833374、最小 0.512610912322998
cap.read() 所要 平均時間 0.8471105575561524、最大 0.8586256504058838、最小 0.8365640640258789

True,True,True,True,True,True,True,True,True,True,
1400
VideoCapture所要 平均時間 2.6704511404037476、最大 3.006239175796509、最小 2.3922278881073
cap.read() 所要 平均時間 1.2015816688537597、最大 1.216357946395874、最小 1.1960184574127197

700番ではVideoCaptureが完了するのに0.5秒、cap.readに0.8秒(遅くね??)かかるのに対し、
1400番ではVideoCaptureに3秒ほど、cap.readに1.2秒もかかっているようだ。
この記事の最初でVideoCaptureに3秒かかると書いたが、この結果を見ると、デフォでは1400番が使われていると考えられる。どういう順番なのかは見当もつかないが、最初のスクショのWARNを見る限り、どうやらCAP_ANYでは
CAP_GSTREAMER(=1800番)を試してから、1400番(=MSMF)で再生しているようだ。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0