1. 程式人生 > >基於opencv的檢測到人臉,便將人臉用骷髏頭代替。

基於opencv的檢測到人臉,便將人臉用骷髏頭代替。

工具:


/*Result window title*/
#define WND_RESULT "result"
static CvMemStorage* storage = 0;
static CvHaarClassifierCascade* cascade ;

const char* cascade_name ;

/*skull image*/
IplImage *g_skullImage;

/*Tarckbar initial value*/
int g_trackbar_value=5;
/*Trackbar total value*/
int g_trackbar_total = 10;

/*Alpha blend' alpha*/
double g_alpha = 0;

/*Trackba callback fuction*/
void switch_callback(int pos) {
	cout << "Trackbar event. pos:" << pos << endl;
	g_alpha = (double)pos / g_trackbar_total;
}
void detect_and_draw(IplImage* img)
{

	double scale = 1.2;
	//Image Preparation 
    IplImage* gray = cvCreateImage(cvSize(img->width, img->height), 8, 1);
    IplImage* small_img = cvCreateImage(
		cvSize(cvRound(img->width / scale), 
			cvRound(img->height / scale)), 
		8, 1);

	cvCvtColor(img, gray, CV_BGR2GRAY);
    cvResize(gray, small_img, CV_INTER_LINEAR);
    cvEqualizeHist(small_img, small_img);
	//直方圖均衡
    //Detect objects if any 
    cvClearMemStorage(storage);
    double t = (double)cvGetTickCount();
    CvSeq* objects = cvHaarDetectObjects(small_img,
        cascade,
        storage,
        1.1,
         2,
        0/*CV_HAAR_DO_CANNY_PRUNING*/,
        cvSize(30, 30));

    t = (double)cvGetTickCount() - t;
    printf("detection time = %gms\n", t / ((double)cvGetTickFrequency()*1000.));

    //Loop through found objects and draw boxes around them 
    for (int i = 0; i<(objects ? objects->total : 0); ++i)
	{
         CvRect* r = (CvRect*)cvGetSeqElem(objects, i);
         CvRect r_scale = cvRect(r->x * scale, r->y * scale, r->width * scale, r->height * scale);
		 // 改變骷髏頭影象大小
         IplImage * skullResize = cvCreateImage(
		cvSize(r_scale.width, r_scale.height),g_skullImage->depth, g_skullImage->nChannels);
        cvResize(g_skullImage, skullResize, CV_INTER_LINEAR);
        // 將人臉檢測區域用骷髏頭影象代替
        cvSetImageROI(img, r_scale);
        printf("Alpha: %f\t", g_alpha);
        cvAddWeighted(img, g_alpha, skullResize, 1.0 - g_alpha, 0.0, img);

		cvResetImageROI(img);
        cvReleaseImage(&skullResize);
     }

    cvShowImage(WND_RESULT, img);
    cvReleaseImage(&gray);
    cvReleaseImage(&small_img);

}

應用層:

void opencv_4_3::ans_8() {
    //獲取攝像頭
	VideoCapture capture(0);
	cascade_name = "E:\\opencv\\sources\\data\\haarcascades_cuda\\haarcascade_frontalface_alt2.xml";
	
	cascade = (CvHaarClassifierCascade*)cvLoad(cascade_name, 0, 0, 0);

	if (!cascade) {
		cout << "Error:Could not load classifier cascade" << endl;
		return;
	}

	storage = cvCreateMemStorage(0);
	cvNamedWindow(WND_RESULT, CV_WINDOW_AUTOSIZE);

	Mat frame;
	capture >> frame;
	
	IplImage * frame_c;
	frame_c = &IplImage(frame);

	IplImage *skullImage = cvLoadImage("..//..//skull.jpg");
	g_skullImage = cvCreateImage(cvGetSize(skullImage), 8, 3);
	skullImage->nChannels != 3 ? cvCvtColor(skullImage, g_skullImage, CV_GRAY2BGR) : cvCopy(skullImage, g_skullImage);

	cvCreateTrackbar("Switch", WND_RESULT, &g_trackbar_value,
		g_trackbar_total, switch_callback);

	g_alpha = (double)g_trackbar_value/ g_trackbar_total;

	char c;
	while (1) {
		capture >> frame;
		frame_c = &IplImage(frame);
		
		if (!frame_c) {
		return ;
		}
		
		detect_and_draw(frame_c);
		c = cvWaitKey(50);
		if (c == 27)
			break;
	}
	cvDestroyWindow(WND_RESULT);
	cvReleaseImage(&frame_c);
	//cvReleaseCapture(&capture);
	cvReleaseImage(&skullImage);
	cvReleaseImage(&g_skullImage);
}

碰到的麻煩:

原來我是用cvCreateCameraCapture獲取的攝像頭視訊,結果總是攝像頭燈亮,但是載入不了視訊。

於是參考了博友的這段:

VideoCapture capture(0);
	//0或-1表示筆記本內建攝像頭 
	Mat frame;  
	while(1)  
	{		
		capture  >> frame;
		imshow("讀取視訊", frame);
		char c=cvWaitKey(33);      
		if(c==27)break;		
		//等待按鍵ESC  
	}

後來就是這段:

cascade_name = "E:\\opencv\\sources\\data\\haarcascades_cuda\\haarcascade_frontalface_alt2.xml";
	
	cascade = (CvHaarClassifierCascade*)cvLoad(cascade_name, 0, 0, 0);

原先的路勁是E:\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt2.xml;

那麼(CvHaarClassifierCascade*)cvLoad(cascade_name, 0, 0, 0);就會報異常錯誤;