ページ 11

顔検出のOpenCVについて

Posted: 2015年11月10日(火) 15:23
by 抹茶
今目を検出して矩形で囲むPGを作っているのですが、同一カメラからの映像をcaptureに取り、frameでは矩形ありの動画、frame3では矩形なしの素の動画を表示させたいと考えています。(capture2やframe2は別のカメラからの動画を取り込むので無視してください。)

それぞれ別のcapture関数を用意すると動作が重くなってしまったため、1つのcaptureからframe,frame3にそれぞれ割り振り、frameにのみ矩形を描画するようにしたつもりなのですがframe3にも矩形が描画されてしまいます。

何か改善する方法はありますか?

コード:

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

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

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

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

	CvCapture *capture = 0;
	CvCapture *capture2 = 0;
//	CvCapture *capture3 = 0;
	// フレーム単位データ
	IplImage *frame = 0;
	IplImage *frame2 = 0;
	IplImage *frame3 = 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;
	///

	// 0番号のカメラに対するキャプチャ構造体を生成するる
	capture = cvCreateCameraCapture (0);
	capture2 = cvCreateCameraCapture (1);
//	capture3 = cvCreateCameraCapture (0);
	
	// キャプチャのサイズを設定する。ただし、この設定はキャプチャを行うカメラに依存するので注意
	cvSetCaptureProperty (capture, CV_CAP_PROP_FRAME_WIDTH, width);
	cvSetCaptureProperty (capture, CV_CAP_PROP_FRAME_HEIGHT, height);
	cvNamedWindow ("capture_face_detect", CV_WINDOW_AUTOSIZE);

	cvSetCaptureProperty (capture2, CV_CAP_PROP_FRAME_WIDTH, width);
	cvSetCaptureProperty (capture2, CV_CAP_PROP_FRAME_HEIGHT, height);
	cvNamedWindow ("capture_face_detect2", CV_WINDOW_AUTOSIZE);

	cvSetCaptureProperty (capture, CV_CAP_PROP_FRAME_WIDTH, width);
	cvSetCaptureProperty (capture, CV_CAP_PROP_FRAME_HEIGHT, height);
	cvNamedWindow ("capture_face_detect3", CV_WINDOW_AUTOSIZE);

	///
	double fps = 5.0;
	CvVideoWriter* VideoWriter = cvCreateVideoWriter("testimage.avi", CV_FOURCC('D','I','B',' '), fps, cvSize(width, height), 1 );
	CvVideoWriter* VideoWriter2 = cvCreateVideoWriter("testimage2.avi", CV_FOURCC('D','I','B',' '), fps, cvSize(width, height), 1 );
	CvVideoWriter* VideoWriter3 = cvCreateVideoWriter("testimage3.avi", CV_FOURCC('D','I','B',' '), fps, cvSize(width, height), 1 );
	///

	// 停止キーが押されるまでカメラキャプチャを続ける
	while (1) {
		frame = cvQueryFrame (capture);
		frame2 = cvQueryFrame (capture2);
		frame3 = cvQueryFrame (capture);

		// 画像中から検出対象の情報を取得する

		eye = cvHaarDetectObjects(frame, cvHCC2, cvMStr2);

		if(eye != nullptr) cnt++;
		
		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);
				
		}

		cvShowImage ("capture_face_detect", frame);
		cvWriteFrame(VideoWriter, frame);
		cvShowImage ("capture_face_detect2", frame2);
		cvWriteFrame(VideoWriter2, frame2);
		cvShowImage ("capture_face_detect3", frame3);
		cvWriteFrame(VideoWriter2, frame3);
		printf("%d\n",cnt);

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

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

	// キャプチャの解放
	cvReleaseCapture (&capture);
	cvReleaseCapture (&capture2);
//	cvReleaseCapture (&capture3);

	///
	cvReleaseVideoWriter(&VideoWriter);
	cvReleaseVideoWriter(&VideoWriter2);
	cvReleaseVideoWriter(&VideoWriter3);
	///
	
	// ウィンドウの破棄
	cvDestroyWindow("capture_face_detect");
	cvDestroyWindow("capture_face_detect2");
	cvDestroyWindow("capture_face_detect3");

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

}

Re: 顔検出のOpenCVについて

Posted: 2015年11月10日(火) 16:11
by usao
以前のトピック
http://dixq.net/forum/viewtopic.php?f=3&t=17179
の時には気づきませんでしたが,frameに矩形描画してはならないように思います.
リファレンスでcvQueryFrame()を見ると

It is not allowed to modify or release the image! You can copy the frame using cvCloneImage() and
then do whatever you want with the copy.

と書かれています.


で,今回の件ですが,
frameとframe3が同じ値になっている(同一の画像バッファを指してる)とかいうことはないのでしょうか.

Re: 顔検出のOpenCVについて

Posted: 2015年11月10日(火) 18:08
by 抹茶
>>usaoさん
何度もありがとうございます。
指摘していただいて思いついたのですが、frameに対してcloneをつくり、処理前のframeを表示するものと処理後のcloneを表示させる方法にした結果うまくできました。
ありがとうございました!