web-dev-qa-db-ja.com

opencv 3.4.2でフレームレートを変更する

Webカメラで1秒あたりに取得されるフレームの数を減らしたい、これは私が使用しているコードです

_#!/usr/bin/env python

import cv2

cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FPS, 10)
fps = int(cap.get(5))
print("fps:", fps)

while(cap.isOpened()):

    ret,frame = cap.read()
    if not ret:
        break

    cv2.imshow('frame', frame)

    k = cv2.waitKey(1)
    if k == 27:
        break
_

しかし、効果はありません。cap.set(cv2.CAP_PROP_FPS, 10)で設定した10 fpsの代わりに、デフォルトでは30 fpsのままです。各フレームの処理にかなりの時間がかかる手の検出器があるため、フレームレートを下げたいと思います。以前の位置で手を検出するため、フレームをバッファに格納できません。タイマーなどを使用して検出器を実行することはできましたが、fpsを変更する方が簡単な方法だと思いましたが、機能せず、理由もわかりません。

Windows 8.1でOpencv 3.4.2をPython 3.6.3で使用しています。

9
Mr. C

フレームレートの設定は、必ずしも期待どおりに機能するとは限りません。それは次の2つに依存します。

  1. あなたのカメラが出力できるもの。
  2. 現在使用しているキャプチャバックエンドがフレームレートの変更をサポートしているかどうか。

したがって、ポイント(1)です。カメラには、キャプチャデバイス(コンピュータなど)に配信できるフォーマットのリストがあります。これは、1920x1080 @ 30 fpsまたは1920x1080 @ 60 fpsであり、ピクセル形式も指定します。民生用カメラのほとんどは、それ以上の細かさでフレームレートを変更できません。また、ほとんどのキャプチャライブラリは、カメラがアドバタイズしていないキャプチャ形式への変更を拒否します。

はるかに細かい制御が可能なマシンビジョンカメラでも、通常はフレームレートの選択のみを提供します(1、2、5、10、15、25、30など)。ハードウェアレベルでサポートされていないフレームレートが必要な場合、通常それを行う唯一の方法は、ハードウェアトリガーを使用することです。

そしてポイント(2)。 _cv.VideoCapture_を使用すると、DirectShowやV4L2などのプラットフォーム固有のライブラリを実際に呼び出すことになります。これをバックエンドと呼びます。次のようなものを使用して、使用中のバックエンドを正確に指定できます。

cv2.VideoCapture(0 + cv2.CAP_DSHOW)

定義されている_CAP_X_はたくさんありますが、ご使用のプラットフォームに適用されるのは一部だけです(たとえば、_CAP_V4L2_はLinux専用です)。 Windowsでは、DirectShowを使用するようにシステムを強制することはかなり良い策です。ただし、上記のように、カメラが30fpsと60fpsを出力できることだけを報告する場合、10fpsを要求しても意味がありません。さらに悪いことに、多くの設定は、実際に実装されていない場合にOpenCVでTrueを報告するだけです。ただし、ほとんどの場合、パラメーターを読み取ると適切な結果が得られますが、パラメーターが実装されていない場合(たとえば、露出が一般的なものではない場合)は、意味がありません。

しばらく待ってから最後の画像を読む方がよいでしょう。

この戦略に注意してください。これを行わないでください:

_while capturing:
    res, image = cap.read()
    time.sleep(1)
_

カメラのフレームバッファーを継続的にパージしていることを確認する必要があります。そうしないと、ビデオに遅れが出始めます。次のようなものが機能するはずです。

_frame_rate = 10
prev = 0

while capturing:

    time_elapsed = time.time() - prev
    res, image = cap.read()

    if time_elapsed > 1./frame_rate:
        prev = time.time()

        # Do something with your image here.
        process_image()
_

ハンドディテクターのようなアプリケーションの場合、うまく機能するのは、画像をキャプチャするスレッドと、別のスレッド(GUIも制御する)でディテクターを実行することです。検出器は最後にキャプチャされた画像を取得し、実行して結果を表示します(画像バッファーの読み取り/書き込み中は、画像バッファーへのアクセスをロックする必要がある場合があります)。この方法では、ボトルネックは検出器であり、カメラのパフォーマンスではありません。

12
Josh

カメラにFPSを設定できなかったため、時間に基づいてFPSを制限し、1秒あたり1フレームだけが残りのコードに組み込まれるようにしました。正確ではありませんが、正確である必要はありません。30fpsの代わりにリミッターを使用するだけです。 HTH

import time

fpsLimit = 1 # throttle limit
startTime = time.time()
cv = cv2.VideoCapture(0)
While True:
    frame = cv.read
    nowTime = time.time()
    if (int(nowTime - startTime)) > fpsLimit:
        # do other cv2 stuff....
        startTime = time.time() # reset time
3
Jeff Blumenthal