使用OpenCV进行人脸检测(Viola-Jones人脸检测方法)
擴(kuò)展閱讀:
OpenCV用于人臉檢測
參考文獻(xiàn):Paul Viola, Michael J. Jones. Robust Real-Time Face Detection[J]. International Journal of Computer Vision,2004,57(2):137-154.
優(yōu)點(diǎn):
1.積分圖像(integral image)快速計算Haar-like特征。
2.利用Adaboost算法進(jìn)行特征選擇和分類器訓(xùn)練,把弱分類器組合成強(qiáng)分類器。
3.采用分類器級聯(lián)提高效率。
檢測步驟:
Step1 加載分類器
讀入xml格式的模型文件,其中haarcascade_frontalface_atl.xml和haarcascade_frontalface_atl2.xml效果較好。文件在OpenCV安裝目錄下的“data/haarcascades/”路徑下。
Step2 讀入待檢測圖像(或者視頻解碼后的圖像)
Step3 調(diào)用用函數(shù)檢測人臉。
代碼1:
#include "opencv2/core/core.hpp" #include "opencv2/objdetect/objdetect.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> #include <stdio.h> using namespace std; using namespace cv; string face_cascade_name = "haarcascade_frontalface_alt.xml"; //該文件存在于OpenCV安裝目錄下的\sources\data\haarcascades內(nèi),需要將該xml文件復(fù)制到當(dāng)前工程目錄下 CascadeClassifier face_cascade; void detectAndDisplay( Mat frame ); int main( int argc, char** argv ){ Mat image; image =imread("face.jpg",1); //當(dāng)前工程的image目錄下的mm.jpg文件,注意目錄符號if( !face_cascade.load( face_cascade_name ) ){ printf("級聯(lián)分類器錯誤,可能未找到文件,拷貝該文件到工程目錄下!\n"); return -1; } detectAndDisplay(image); //調(diào)用人臉檢測函數(shù)waitKey(0); //暫停顯示一下。 } void detectAndDisplay( Mat face ){ std::vector<Rect> faces; Mat face_gray; cvtColor( face, face_gray, CV_BGR2GRAY ); //rgb類型轉(zhuǎn)換為灰度類型equalizeHist( face_gray, face_gray ); //直方圖均衡化face_cascade.detectMultiScale( face_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(1, 1) ); for( int i = 0; i < faces.size(); i++ ){ Point center( faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5 ); ellipse( face, center, Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 0), 2,7, 0 ); } imshow("人臉識別", face ); }代碼1效果:
代碼2:
#include "cv.h" #include "highgui.h"#include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <math.h> #include <float.h> #include <limits.h> #include <time.h> #include <ctype.h>static CvMemStorage* storage = 0; static CvHaarClassifierCascade* cascade = 0;void detect_and_draw( IplImage* image );const char* cascade_name = "haarcascade_frontalface_alt.xml"; /* "haarcascade_profileface.xml";*/int main( int argc, char** argv ) { cascade_name = "haarcascade_frontalface_alt2.xml"; cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 ); if( !cascade ) { fprintf( stderr, "ERROR: Could not load classifier cascade\n" ); return -1; } storage = cvCreateMemStorage(0); cvNamedWindow( "result", 1 ); const char* filename = "face.jpg"; IplImage* image = cvLoadImage( filename, 1 );if( image ) { detect_and_draw( image ); cvWaitKey(0); cvReleaseImage( &image ); }cvDestroyWindow("result"); return 0; }void detect_and_draw(IplImage* img ) { double scale=1.2; static CvScalar colors[] = { {{0,0,255}},{{0,128,255}},{{0,255,255}},{{0,255,0}}, {{255,128,0}},{{255,255,0}},{{255,0,0}},{{255,0,255}} };//Just some pretty colors to draw with//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); cvRectangle(img, cvPoint(r->x*scale,r->y*scale), cvPoint((r->x+r->width)*scale,(r->y+r->height)*scale), colors[i%8]); } for( int i = 0; i < (objects? objects->total : 0); i++ ) { CvRect* r = (CvRect*)cvGetSeqElem( objects, i ); CvPoint center; int radius; center.x = cvRound((r->x + r->width*0.5)*scale); center.y = cvRound((r->y + r->height*0.5)*scale); radius = cvRound((r->width + r->height)*0.25*scale); cvCircle( img, center, radius, colors[i%8], 3, 8, 0 ); }cvShowImage( "result", img ); cvReleaseImage(&gray); cvReleaseImage(&small_img); }
代碼2效果
?
從效果看,代碼1的效果較好。原因使用的函數(shù)不同,內(nèi)部的實(shí)現(xiàn)和參數(shù)也有區(qū)別。請根據(jù)實(shí)際情況子集選擇。
代碼3,OpenCV? 原版附帶眼睛檢測
#include "opencv2/objdetect/objdetect.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp"#include <cctype> #include <iostream> #include <iterator> #include <stdio.h>using namespace std; using namespace cv;static void help() {cout << "\nThis program demonstrates the cascade recognizer. Now you can use Haar or LBP features.\n""This classifier can recognize many kinds of rigid objects, once the appropriate classifier is trained.\n""It's most known use is for faces.\n""Usage:\n""./facedetect [--cascade=<cascade_path> this is the primary trained classifier such as frontal face]\n"" [--nested-cascade[=nested_cascade_path this an optional secondary classifier such as eyes]]\n"" [--scale=<image scale greater or equal to 1, try 1.3 for example>]\n"" [--try-flip]\n"" [filename|camera_index]\n\n""see facedetect.cmd for one call:\n""./facedetect --cascade=\"../../data/haarcascades/haarcascade_frontalface_alt.xml\" --nested-cascade=\"../../data/haarcascades/haarcascade_eye.xml\" --scale=1.3\n\n""During execution:\n\tHit any key to quit.\n""\tUsing OpenCV version " << CV_VERSION << "\n" << endl; }void detectAndDraw( Mat& img, CascadeClassifier& cascade,CascadeClassifier& nestedCascade,double scale, bool tryflip );string cascadeName = "../../data/haarcascades/haarcascade_frontalface_alt.xml"; string nestedCascadeName = "../../data/haarcascades/haarcascade_eye_tree_eyeglasses.xml";int main( int argc, const char** argv ) {CvCapture* capture = 0;Mat frame, frameCopy, image;const string scaleOpt = "--scale=";size_t scaleOptLen = scaleOpt.length();const string cascadeOpt = "--cascade=";size_t cascadeOptLen = cascadeOpt.length();const string nestedCascadeOpt = "--nested-cascade";size_t nestedCascadeOptLen = nestedCascadeOpt.length();const string tryFlipOpt = "--try-flip";size_t tryFlipOptLen = tryFlipOpt.length();string inputName;bool tryflip = false;help();CascadeClassifier cascade, nestedCascade;double scale = 1;for( int i = 1; i < argc; i++ ){cout << "Processing " << i << " " << argv[i] << endl;if( cascadeOpt.compare( 0, cascadeOptLen, argv[i], cascadeOptLen ) == 0 ){cascadeName.assign( argv[i] + cascadeOptLen );cout << " from which we have cascadeName= " << cascadeName << endl;}else if( nestedCascadeOpt.compare( 0, nestedCascadeOptLen, argv[i], nestedCascadeOptLen ) == 0 ){if( argv[i][nestedCascadeOpt.length()] == '=' )nestedCascadeName.assign( argv[i] + nestedCascadeOpt.length() + 1 );if( !nestedCascade.load( nestedCascadeName ) )cerr << "WARNING: Could not load classifier cascade for nested objects" << endl;}else if( scaleOpt.compare( 0, scaleOptLen, argv[i], scaleOptLen ) == 0 ){if( !sscanf( argv[i] + scaleOpt.length(), "%lf", &scale ) || scale < 1 )scale = 1;cout << " from which we read scale = " << scale << endl;}else if( tryFlipOpt.compare( 0, tryFlipOptLen, argv[i], tryFlipOptLen ) == 0 ){tryflip = true;cout << " will try to flip image horizontally to detect assymetric objects\n";}else if( argv[i][0] == '-' ){cerr << "WARNING: Unknown option %s" << argv[i] << endl;}elseinputName.assign( argv[i] );}if( !cascade.load( cascadeName ) ){cerr << "ERROR: Could not load classifier cascade" << endl;help();return -1;}if( inputName.empty() || (isdigit(inputName.c_str()[0]) && inputName.c_str()[1] == '\0') ){capture = cvCaptureFromCAM( inputName.empty() ? 0 : inputName.c_str()[0] - '0' );int c = inputName.empty() ? 0 : inputName.c_str()[0] - '0' ;if(!capture) cout << "Capture from CAM " << c << " didn't work" << endl;}else if( inputName.size() ){image = imread( inputName, 1 );if( image.empty() ){capture = cvCaptureFromAVI( inputName.c_str() );if(!capture) cout << "Capture from AVI didn't work" << endl;}}else{image = imread( "lena.jpg", 1 );if(image.empty()) cout << "Couldn't read lena.jpg" << endl;}cvNamedWindow( "result", 1 );if( capture ){cout << "In capture ..." << endl;for(;;){IplImage* iplImg = cvQueryFrame( capture );frame = iplImg;if( frame.empty() )break;if( iplImg->origin == IPL_ORIGIN_TL )frame.copyTo( frameCopy );elseflip( frame, frameCopy, 0 );detectAndDraw( frameCopy, cascade, nestedCascade, scale, tryflip );if( waitKey( 10 ) >= 0 )goto _cleanup_;}waitKey(0);_cleanup_:cvReleaseCapture( &capture );}else{cout << "In image read" << endl;if( !image.empty() ){detectAndDraw( image, cascade, nestedCascade, scale, tryflip );waitKey(0);}else if( !inputName.empty() ){/* assume it is a text file containing thelist of the image filenames to be processed - one per line */FILE* f = fopen( inputName.c_str(), "rt" );if( f ){char buf[1000+1];while( fgets( buf, 1000, f ) ){int len = (int)strlen(buf), c;while( len > 0 && isspace(buf[len-1]) )len--;buf[len] = '\0';cout << "file " << buf << endl;image = imread( buf, 1 );if( !image.empty() ){detectAndDraw( image, cascade, nestedCascade, scale, tryflip );c = waitKey(0);if( c == 27 || c == 'q' || c == 'Q' )break;}else{cerr << "Aw snap, couldn't read image " << buf << endl;}}fclose(f);}}}cvDestroyWindow("result");return 0; }void detectAndDraw( Mat& img, CascadeClassifier& cascade,CascadeClassifier& nestedCascade,double scale, bool tryflip ) {int i = 0;double t = 0;vector<Rect> faces, faces2;const static Scalar colors[] = { CV_RGB(0,0,255),CV_RGB(0,128,255),CV_RGB(0,255,255),CV_RGB(0,255,0),CV_RGB(255,128,0),CV_RGB(255,255,0),CV_RGB(255,0,0),CV_RGB(255,0,255)} ;Mat gray, smallImg( cvRound (img.rows/scale), cvRound(img.cols/scale), CV_8UC1 );cvtColor( img, gray, CV_BGR2GRAY );resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR );equalizeHist( smallImg, smallImg );t = (double)cvGetTickCount();cascade.detectMultiScale( smallImg, faces,1.1, 2, 0//|CV_HAAR_FIND_BIGGEST_OBJECT//|CV_HAAR_DO_ROUGH_SEARCH|CV_HAAR_SCALE_IMAGE,Size(30, 30) );if( tryflip ){flip(smallImg, smallImg, 1);cascade.detectMultiScale( smallImg, faces2,1.1, 2, 0//|CV_HAAR_FIND_BIGGEST_OBJECT//|CV_HAAR_DO_ROUGH_SEARCH|CV_HAAR_SCALE_IMAGE,Size(30, 30) );for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); r++ ){faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height));}}t = (double)cvGetTickCount() - t;printf( "detection time = %g ms\n", t/((double)cvGetTickFrequency()*1000.) );for( vector<Rect>::const_iterator r = faces.begin(); r != faces.end(); r++, i++ ){Mat smallImgROI;vector<Rect> nestedObjects;Point center;Scalar color = colors[i%8];int radius;double aspect_ratio = (double)r->width/r->height;if( 0.75 < aspect_ratio && aspect_ratio < 1.3 ){center.x = cvRound((r->x + r->width*0.5)*scale);center.y = cvRound((r->y + r->height*0.5)*scale);radius = cvRound((r->width + r->height)*0.25*scale);circle( img, center, radius, color, 3, 8, 0 );}elserectangle( img, cvPoint(cvRound(r->x*scale), cvRound(r->y*scale)),cvPoint(cvRound((r->x + r->width-1)*scale), cvRound((r->y + r->height-1)*scale)),color, 3, 8, 0);if( nestedCascade.empty() )continue;smallImgROI = smallImg(*r);nestedCascade.detectMultiScale( smallImgROI, nestedObjects,1.1, 2, 0//|CV_HAAR_FIND_BIGGEST_OBJECT//|CV_HAAR_DO_ROUGH_SEARCH//|CV_HAAR_DO_CANNY_PRUNING|CV_HAAR_SCALE_IMAGE,Size(30, 30) );for( vector<Rect>::const_iterator nr = nestedObjects.begin(); nr != nestedObjects.end(); nr++ ){center.x = cvRound((r->x + nr->x + nr->width*0.5)*scale);center.y = cvRound((r->y + nr->y + nr->height*0.5)*scale);radius = cvRound((nr->width + nr->height)*0.25*scale);circle( img, center, radius, color, 3, 8, 0 );}}cv::imshow( "result", img );cv::waitKey(0); }
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀
總結(jié)
以上是生活随笔為你收集整理的使用OpenCV进行人脸检测(Viola-Jones人脸检测方法)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用OpenCV进行人脸识别的三种方法
- 下一篇: 使用OpenCV进行人脸关键点检测