opencvでの動画再生について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
抹茶
記事: 15
登録日時: 10年前

opencvでの動画再生について

#1

投稿記事 by 抹茶 » 9年前

動画ファイルを取り込んで、それに対して処理を加えるプログラムを作成しました。
しかし、出力された動画は元の動画よりも時間が長くなっており、再生がすごくゆっくりしたものになっています。
元の動画とほぼ同速で出力させるにはどのようにすればよいでしょうか。
動画ファイルでなく、USBカメラから取り込む場合は速度そのままに処理できていたのですが、ファイルの動画から処理しようとすると遅くなっています。

コード:

//サーマルカメラを考慮

#include <C:/opencv2411/build/include\opencv/highgui.h>
#include <C:/opencv2411/build/include\opencv/cv.h>
#include <C:/opencv2411/build/include\opencv/cxcore.h>

//opencvの関数名省略のため [cv::]省略
using namespace std;
using namespace cv;

int main(int argc, char* argv[]){
	

	CvCapture* capture;
	// フレーム単位データ
	IplImage* frame;

	char* fname = "output.avi";
    capture = cvCreateFileCapture(fname);
	if(capture == NULL)return 0;

	// 縦横サイズ
	double height = 240;
	double width = 320;
	// 入力キー受け付け用
	int c;
	int cnt = 0;

	///
	// eye検出器の読み込み
	CvHaarClassifierCascade* cvHCC2 = (CvHaarClassifierCascade*)cvLoad("C:/image/haarcascade_eye_tree_eyeglasses.xml");
	CvMemStorage* cvMStr2 = cvCreateMemStorage(0);
	CvSeq* eye;
	///

	cvNamedWindow ("capture_face_detect", CV_WINDOW_AUTOSIZE);

	// 停止キーが押されるまでカメラキャプチャを続ける
	while (1) {

		frame = cvQueryFrame (capture);
		if(frame == NULL)break;

		// 画像中から検出対象の情報を取得する
		eye = cvHaarDetectObjects(frame, cvHCC2, cvMStr2);
		
		for (int i = 0; i < eye->total; i++) {

			// 検出情報から顔の位置情報を取得
			CvRect* eyeRect = (CvRect*)cvGetSeqElem(eye, i);

//						
			// 取得した顔の位置情報に基づき、矩形描画を行う
			cvRectangle(frame,
				cvPoint(eyeRect->x, eyeRect->y),
				cvPoint(eyeRect->x + eyeRect->width, eyeRect->y + eyeRect->height),
				CV_RGB(0, 255 ,0),
				3, CV_AA);

			if(eyeRect != nullptr) cnt++;				
		}

		cvShowImage ("capture_face_detect", frame);
		cout << cnt << endl;



		// 終了キー入力待ち(タイムアウト付き)
		c = cvWaitKey (1);
		if (c == 'e') {
			break;
		}
	}

	// 生成したメモリストレージを解放
	cvReleaseMemStorage(&cvMStr2);

	// キャプチャの解放
	cvReleaseCapture (&capture);
	
	// ウィンドウの破棄
	cvDestroyWindow("capture_face_detect");

	// カスケード識別器の解放
	cvReleaseHaarClassifierCascade(&cvHCC2);
	
	return 0;

}

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: opencvでの動画再生について

#2

投稿記事 by usao » 9年前

>出力された動画は元の動画よりも時間が長くなっており、再生がすごくゆっくりしたものになっています

ここで「出力された動画」とは何でしょうか?
(処理結果を動画ファイルに保存するような箇所を見つけることができません)

(63行目で表示しているもののことを指しているのであれば…
 単に,45行目等で行っている処理に時間がかかっているとかいうこと?)

抹茶
記事: 15
登録日時: 10年前

Re: opencvでの動画再生について

#3

投稿記事 by 抹茶 » 9年前

usao さんが書きました:>出力された動画は元の動画よりも時間が長くなっており、再生がすごくゆっくりしたものになっています

ここで「出力された動画」とは何でしょうか?
(処理結果を動画ファイルに保存するような箇所を見つけることができません)

(63行目で表示しているもののことを指しているのであれば…
 単に,45行目等で行っている処理に時間がかかっているとかいうこと?)
>>言われたとおり、63行目のcvShowImage ("capture_face_detect", frame);で出力しているもののことです。
誤解を招く言い方で申し訳ありません。

処理元の動画としてUSBカメラから直接取り込んだものだと処理もスムーズに行われるのですが、ファイルからだと数秒ほどの動画が数分間かけて出力される状態になっています。

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: opencvでの動画再生について

#4

投稿記事 by usao » 9年前

44~61行の処理を(コメントアウトするなどして)行わないようにしても
やはり表示に数分間かかるのでしょうか?

●かかる場合
 ちょっとわからないです.(cvQueryFrame()にめちゃくちゃ時間がかかる?)

●かからない場合
 >USBカメラから直接取り込んだものだと処理もスムーズ
 …というのは,詳細に言うとどういうことになりますか?
 例えばカメラから1秒間に30回絵が取れるとしたら,44~61行の処理は毎回 1/30 秒以内に終わるということでしょうか?
 44~61行の処理に要している時間を
 USBカメラの場合と,動画ファイルの場合とでそれぞれ計測してみてはいかがでしょう?



 例えば,44~61行の処理に毎回 1秒 かかるとして…

 カメラの場合,時刻tにキャプチャしたフレームを処理すると,次にカメラから画像がキャプチャされる時刻は tから1[秒]たった時刻です
 (つまり,処理している1秒の間にカメラが撮影していた画像群はキャプチャされず,処理もされない)
 対して,
 動画の場合では,処理にどれだけの時間がかかろうが,次にキャプチャしてくるフレーム画像というのは,常に前回のフレームの次のフレームです
 (つまり,動画ファイルの全てのフレーム画像を処理する)

 この辺のことでで,誤解があったりしないでしょうか?
 (実際は1秒もかからないので, カメラ使用時に フレームが飛ばされている ことを見ていて気付かない,みたいな)

抹茶
記事: 15
登録日時: 10年前

Re: opencvでの動画再生について

#5

投稿記事 by 抹茶 » 9年前

usao さんが書きました:44~61行の処理を(コメントアウトするなどして)行わないようにしても
やはり表示に数分間かかるのでしょうか?

●かからない場合
 >USBカメラから直接取り込んだものだと処理もスムーズ
 …というのは,詳細に言うとどういうことになりますか?
 例えばカメラから1秒間に30回絵が取れるとしたら,44~61行の処理は毎回 1/30 秒以内に終わるということでしょうか?
 44~61行の処理に要している時間を
 USBカメラの場合と,動画ファイルの場合とでそれぞれ計測してみてはいかがでしょう?



 例えば,44~61行の処理に毎回 1秒 かかるとして…

 カメラの場合,時刻tにキャプチャしたフレームを処理すると,次にカメラから画像がキャプチャされる時刻は tから1[秒]たった時刻です
 (つまり,処理している1秒の間にカメラが撮影していた画像群はキャプチャされず,処理もされない)
 対して,
 動画の場合では,処理にどれだけの時間がかかろうが,次にキャプチャしてくるフレーム画像というのは,常に前回のフレームの次のフレームです
 (つまり,動画ファイルの全てのフレーム画像を処理する)

 この辺のことでで,誤解があったりしないでしょうか?
 (実際は1秒もかからないので, カメラ使用時に フレームが飛ばされている ことを見ていて気付かない,みたいな)
>>
USBカメラを使ってリアルタイムに処理を与えた場合はフレームが遅れた状態で出力はされていますが、ほとんど影響はありませんでした。(1秒間目を閉じるとしたら、出力されている映像も少し遅れるが1秒間目を閉じる)。
しかし、ファイルの動画の処理を実行したところ実際は1秒しか目を閉じていない動画が、再生速度の低下(?)によって5秒ほど目を閉じているといった様子です。
教えてもらった部分をコメントアウトしたところ、逆に再生速度が早くなりました。
他にもコメントアウトを試したところ、どうやら45行目をコメントアウトから外す(コメントアウトの範囲を46~61行に)と再生速度が極端に遅くなるようです。
目の検出に必要な部分なのですが、元の動画とほぼ同じような速度での処理は可能でしょうか?

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: opencvでの動画再生について

#6

投稿記事 by usao » 9年前

>例えば,44~61行の処理に毎回 1秒 かかるとして…
>
>カメラの場合,時刻tにキャプチャしたフレームを処理すると,次にカメラから画像がキャプチャされる時刻は tから1[秒]たった時刻です
>(つまり,処理している1秒の間にカメラが撮影していた画像群はキャプチャされず,処理もされない)
>対して,
>動画の場合では,処理にどれだけの時間がかかろうが,次にキャプチャしてくるフレーム画像というのは,常に前回のフレームの次のフレームです
>(つまり,動画ファイルの全てのフレーム画像を処理する)


↑の話を理解して頂けているのかどうか量り兼ねますが…



> 44~61行の処理に要している時間を
> USBカメラの場合と,動画ファイルの場合とでそれぞれ計測してみてはいかがでしょう?

まず,これを実際に行ってみていただけませんか?

動画ファイルの場合にだけ検出処理に要する時間が著しく長くなるわけではない
( {「動画ファイルだから」遅い,「カメラだから」早い}のではない )
のだと予想します.


>元の動画とほぼ同じような速度での処理は可能でしょうか?


目指すべきゴールは何なのか? ということによると思います.

【動画ファイルを単純に動画プレイヤ等で再生した場合と同じ速度で動いてほしい】ということであれば
検出処理部分自体をリアルタイムで動くように高速化するしかないように思います.
(検出処理アルゴリズムそのものをいじくる……のは大変難しいでしょうが,
 フレーム画像をそのまま検出処理に渡すのではなく,なにかしらの方法で検出処理範囲を絞るとか,
 縮小した画像でも検出精度が十分であれば縮小画像を渡すとか,何かそういう方策が取れれば)

そうではなくて,
【カメラを使った場合のように動いてほしい】ということであれば,
フレーム画像を単純に毎フレーム検出処理に渡すのをやめる(=カメラでフレーム落ちが起きていることをシミュレートする)
ようにすれば良いのではないかと思います.
(検出処理にかかった時間と動画ファイルのfpsの情報があれば,何フレーム飛ばせばよいかがわかりますよね)

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: opencvでの動画再生について

#7

投稿記事 by usao » 9年前

>例えば,44~61行の処理に毎回 1秒 かかるとして…
>
>カメラの場合,時刻tにキャプチャしたフレームを処理すると,次にカメラから画像がキャプチャされる時刻は tから1[秒]たった時刻です
>(つまり,処理している1秒の間にカメラが撮影していた画像群はキャプチャされず,処理もされない)
>対して,
>動画の場合では,処理にどれだけの時間がかかろうが,次にキャプチャしてくるフレーム画像というのは,常に前回のフレームの次のフレームです
>(つまり,動画ファイルの全てのフレーム画像を処理する)

この話に関して,絵を描いてみました.
cam_timing.png
cam_timing.png (5.41 KiB) 閲覧数: 9284 回
一番上の行のカラフルな縦棒のタイミングでカメラが撮影を行っています.
(例えば,30fpsで動作するのであれば,縦棒の間隔は 1/3 秒です)

時刻aでカメラが撮影した画像を取得して検出処理を行ったとき,
その検出処理結果が表示されるのは,時刻aから検出処理に要する時間だけ後の時刻になります.(表示の遅延)
次に取得される画像は,時刻bやcに撮影された絵ではなくて,時刻dに撮影された絵になります.
同様に,その次に処理対象になる絵は,時刻gで撮影された絵になります.
処理される絵は 時刻{a,d,g,...}に撮影された絵だけであり,その間に撮影されたフレームは処理できません.
しかし,撮影時刻から処理結果が表示される時刻までの差(遅延時間)は一定です.

対して,動画ファイルを使った場合はどうでしょうか?
絵の一番の行の「カメラの撮影タイミング」を「動画ファイルのフレーム」に読み替えて考えてみてください.
フレームaに対する結果はカメラの場合と同じことになります(結果表示は,処理時間分だけ遅延する)が,
次に取得されてくる絵はフレームbです.
ここがカメラの場合とは違います.
遅延時間は累積していき,
動画ファイルを単に再生した場合と比較すると,結果表示は実時間上でどんどん遅れていきます.

抹茶
記事: 15
登録日時: 10年前

Re: opencvでの動画再生について

#8

投稿記事 by 抹茶 » 9年前

usao さんが書きました: ↑の話を理解して頂けているのかどうか量り兼ねますが…
>>図を交えての説明ありがとうございました。分かっていた気ではありましたが、カメラだと間のフレームを無視していたのを処理が早いと勘違いしていたのですね・・・・・・

> 44~61行の処理に要している時間を
> USBカメラの場合と,動画ファイルの場合とでそれぞれ計測してみてはいかがでしょう?
まず,これを実際に行ってみていただけませんか?

動画ファイルの場合にだけ検出処理に要する時間が著しく長くなるわけではない
( {「動画ファイルだから」遅い,「カメラだから」早い}のではない )
のだと予想します.

>>言われたとおり、処理の時間(プロンプトに表示される数字が10個目になるまでの時間)はどちらもほとんど変わりませんでした。

>元の動画とほぼ同じような速度での処理は可能でしょうか?
目指すべきゴールは何なのか? ということによると思います.
【カメラを使った場合のように動いてほしい】ということであれば,
フレーム画像を単純に毎フレーム検出処理に渡すのをやめる(=カメラでフレーム落ちが起きていることをシミュレートする)
ようにすれば良いのではないかと思います.
(検出処理にかかった時間と動画ファイルのfpsの情報があれば,何フレーム飛ばせばよいかがわかりますよね)

>>現状はカメラのように動かしたいため、間のフレームを飛ばす処理についてネットで探して見ます

抹茶
記事: 15
登録日時: 10年前

Re: opencvでの動画再生について

#9

投稿記事 by 抹茶 » 9年前

動画ファイルのfpsが15で処理時間は大体0.8秒程度なのですが、間の12フレームを飛ばして処理したい場合はどのようにすればよいでしょうか

fpsという変数を用意して12で割ったあまりが0のときのみ処理するようif文を作ろうとしたのですがあまりうまくいきませんでした。

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: opencvでの動画再生について

#10

投稿記事 by usao » 9年前

とりあえずこんな感じでいいんじゃないでしょうか.

#cvQueryFrame()を繰り返すよりも
 cvSetCaptureProperty()だったかで動画のフレーム位置を
 次に処理すべきフレーム位置に変更する方が効率良いかもしれませんけど.

コード:

int skip_count = 0;  //読み飛ばすべきフレーム数
while(1)
{
  frame = cvQueryFrame( capture );
  if( !frame )break;

  if( skip_count == 0 )
  {
    //・検出処理と,その処理時間を計測
    ...
    //・処理時間と動画ファイルfpsとから,読み飛ばすべきフレーム数を算出
    skip_count = ...;

    //・処理結果の描画と表示等
    ...
  }
  else
  {  --skip_count;  }
}

抹茶
記事: 15
登録日時: 10年前

Re: opencvでの動画再生について

#11

投稿記事 by 抹茶 » 9年前

usaoさんありがとうございました。
修正を重ねたところ、動作が今までより大幅に改善されました。

閉鎖

“C言語何でも質問掲示板” へ戻る