OpenCV C++ 動画保存時のフレーム欠損

VC++でのOpenCVのよくあるビデオカメラの読み込みと動画の保存のサンプルは、ほとんど空のプロジェクトを作成して、main() の中に全部入れてしまえ!ってやつですよね。

でも単純ループさせると、録画のフレームが全く時間管理できてない状態になってしまいます。

実際によくあるサンプルで録画したファイルを再生すると大抵早送り状態になってしまうと思います。そこで何かの参考や気づきになるかもと思い、ちょっと実験してみました。

 

カメラによる差

単純ループで、

cv::VideoWriter writer; //動画保存インスタンス

に対して、MATのインスタンス、大抵 frame といったネーミングになってます。

このようなループで出来たファイルを再生すると早送り状態になります。

じゃあ何がどうなんだろうという事で、OpenCVにかかわる時間を計測してみました。

計測点はそれぞれの関数の所。で2つのカメラで計測してみました。以下の結果テーブルは別の値も含んでいるので、まず  #1to2=005, #2to3=01, #3to4=02   #lap  という部分だけご覧ください。

#1to2 :  キャプチャにかかった時間

#2to3 : 1フレームをWindow表示にかかった時間

#3to4 : writerインスタンスに1フレームを書き込んだ時間

すべて mSec 単位

5秒間のキャプチャ

マシンは Corei3  3.5GHz 12Gメモリ で少々ダル、でもそれなりに動作するレベルなPC

 

カメラA   ELECOMの1.3Mpixelと書いてある一般的なWEBカメラ。

 

次に

カメラB  メーカー不明のMegaPixelと書いてある物。

 

この結果を見ると、まず、

#lap  これはfor一周にかかった時間で、30fpsなら33.33mSec以内でないとフレーム欠損している状況

つまり多量にフレーム落ちしています。カメラBの安物はまったく遅いですね。 でその処理の部分はと言えば、#1to2で表した、キャプチャの部分です。ここの数値が非常に大きくなっています。

特に1回目のループでは何をしているのかカメラBでは、1466mSec秒もかかっています。WindowsなのでOSがどのように時間配分したのか分りませんが、少なくともOpenCVは明らかに別スレッドで走っているので、Windowsアプリに組み込んでも邪魔はしません。でもかかり過ぎですね。カメラAでも459mSec。マシですが、10枚以上のフレームが落ちてます。

これをそのままビデオ保存して再生すると、5秒の録画時間が3秒程度に縮まります。

 

 

 

そこで、考えられるのは、タイマ割り込みで処理する方法。

これやってみました。例えば WM_TIMER で OnTimer() 云々の定番パターン。SetTIimeを1mSecとして33mSecをカウントしても、Timerそのものを33mSecにしても、結局キャプチャ時間が遅いシステムではコードが状態遷移したり複雑になるだけで、あまり意味が無いことに気付き始めました。なのでここでは全部割愛!(汗)

 

おそらくいろんなシステムで動作するであろうのは、実時間と録画フレーム数の関係を保ち続けることだと考え、以下の方針でコードを作成してみました。

 

Loop をキャプチャ回数とすれば、経過時間-(Loop*(1秒/fps)>0 なら
その値を1000/fpsで割った回数分、同じ画像を書き込んで辻褄を合わせ、必要回数Loopしたことにする。

何のことだ?と思われる方にはコードを見てもらった方が早いので、実験コードを掲示しておきます。

このコードでは、時間をスーパーインポーズして再生時にわかりやすくしています。

 

 

上の方の時間計測は、このコードの実行結果です。

#nShot は一周にかかった時間から何フレーム分の画像データを録画するか計算して、同じ画像ではありますが、必要枚数詰め込んで辻褄を合わせています。

 

5秒分のビデオ画像ですが、最初の一秒は止まってしまってます。ただ時間軸は正しく補正されているので、長時間録画しても実時間とのずれは無いようです。

 

実際のアプリケーションで使う場合は、動画のトリガとなるのが、キーボードであることは少なくて、Desktopアプリならマウスボタンのクリック、組み込みならBluetoothやらWi-Fi通信での端末からの指令というパターンが多いはず。あとはタイマー自動起動とかでしょうか。いずれの場合でもUIなど他のスレッドで動作しているプログラムが停止してしまうことは許されないはずなので、いろんな手段での工夫が必要なようです。

 

ずっとOpenCVを動画保存でも使っておられる方はもっとスマートな方法を使ってるのかもしれませんが、ひとまず人間が見て違和感のない範囲で許されるならこの程度の補正で大丈夫なようです。コストを掛けて良いなら、キャプチャデータをもっと高速で吐き出せるカメラを用意する方が先かもしれません。データキャプチャは高速で安定してできるなら、逆に時間待ちだけですべて処理できますからね。

ここまで実験した結果でした。

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です