人脸检测的C/C++源代码,曾发表于 OPENCV 的 MAILING LIST,主要是对OPENCV 3.1 版本发布的代码做了一些速度上的优化,并且解决了内存泄漏的问题。这个程序所使用的 Paul Viola 提出(该论文“Rapid Object Detection using a Boosted Cascade of Simple Features”发表在 CVPR01)的 Ada Boosted Cascade 算法可以说是目前最好最快的目标检测算法。
下面是算法的简单描述:
Rapid Object Detection using a Boosted Cascade of Simple Features
This method entails a machine learning approach for visual object detection, which is capable of processing images extremely rapidly and achieving high detection rates.
First it introduces a new image representation called “ Integral Image” which allows the features used by detector to be computed very quickly. The integral image can be computed from an image using a few operations per pixel. Once computed, any one of these Harr-like features can be computed at any scale or location in constant time.
The second is a learning algorithm, based on AdaBoost, which selects a small number of critical visual features from a large set and yields extremely efficient classifiers.
The third is a method for combining increasingly more complex classifiers in a “cascade” which allows background regions of the image to be quickly discarded while spending more computation on promising object-like regions.
The object detection classifies images based on the value of simple features. The simple features used are reminiscent of Haar basis functions. Here it uses three kinds of features: two-rectangle feature, three-rectangle feature and four-rectangle. Rectangle features are somewhat primitive when compared with alternatives such as steerable filters. Steerable filters are excellent for the detailed analysis of boundaries, image compression, and texture analysis. In order to use a small number of features to form an effective classifier, the weak learning algorithm is designed to select the single rectangle feature which best separates the positive and negative examples. For each feature, the weak learner determines the optimal threshold classification function, such that the minimum
number of examples is misclassified. The overall form of the detection process is that of a degenerate decision tree, called a “cascade”.
A positive result from the first classifier triggers the evaluation of a second classifier, which has also been adjusted to achieve very high detection rates. A positive result from the second classifier triggers a third classifiers, and so on. The cascade training process involves two types of tradeoffs. In most cases classifiers with more features will achieve higher detection rates and lower false positive rates. At the same time classifiers with more features require more time to compute.
在OPENCV 3.1 版本,VC6.0下编译通过
====
===
#ifdef _CH_
#define WIN32
#error The file needs cvaux, which is not wrapped yet. Sorry
#endif
#ifndef _EiC
#include cv.h
#include cvaux.h
#include highgui.h
#endif
#ifdef _EiC
#define WIN32
#endif
#define ORIG_WIN_SIZE 24
static CvMemStorage* storage = 0;
static CvHidHaarClassifierCascade* hid_cascade = 0;
#define WINNAME Result
void detect_and_draw( IplImage* image, IplImage* TempImage );
int main( int argc, char** argv )
{
CvCapture* capture = 0;
CvHaarClassifierCascade* cascade =
cvLoadHaarClassifierCascade( ,
cvSize( ORIG_WIN_SIZE, ORIG_WIN_SIZE ));
hid_cascade = cvCreateHidHaarClassifierCascade( cascade, 0, 0, 0, 1 );
cvReleaseHaarClassifierCascade( &cascade );
cvNamedWindow( WINNAME, 1 );
storage = cvCreateMemStorage(0);
if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))
capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - 0 : 0 );
else if( argc == 2 )
capture = cvCaptureFromAVI( argv[1] );
if( capture )
{
IplImage *frame, *temp;
cvGrabFrame( capture );
frame = cvRetrieveFrame( capture );
temp = cvCreateImage( cvSize(frame->width/2,frame->height/2), 8, 3 );
for(;;)
{
if( !cvGrabFrame( capture ))
break;
frame = cvRetrieveFrame( capture );
if( !frame )
break;
detect_and_draw( frame, temp );
if( cvWaitKey( 10 ) >= 0 )
{
//cvReleaseImage( &frame );
//cvReleaseImage( &temp );
cvReleaseCapture( &capture );
cvDestroyWindow(WINNAME);
return 0;
}
}
}
else
{
char* filename = argc == 2 ? argv[1] : (char*)lena.jpg;
IplImage* image = cvLoadImage( filename, 1 );
IplImage* temp = cvCreateImage( cvSize(image->width/2,image->height/2), 8, 3 );
if( image )
{
cvFlip( image, image, 0 );
image->origin = IPL_ORIGIN_BL;
detect_and_draw( image, temp );
cvWaitKey(0);
cvReleaseImage( &image );
cvReleaseImage( &temp );
}
cvDestroyWindow(WINNAME);
return 0;
}
return 0;
}
void detect_and_draw( IplImage* img, IplImage* temp )
{
int scale = 2;
CvPoint pt1, pt2;
int i;
cvPyrDown( img, temp, CV_GAUSSIAN_5x5 );
#ifdef WIN32
cvFlip( temp, temp, 0 );
#endif
cvClearMemStorage( storage );
if( hid_cascade )
{
CvSeq* faces = cvHaarDetectObjects( temp, hid_cascade, storage,
1.2, 2, CV_HAAR_DO_CANNY_PRUNING );
for( i = 0; i < (faces ? faces->total : 0); i++ )
{
CvRect* r = (CvRect*)cvGetSeqElem( faces, i, 0 );
pt1.x = r->x*scale;
pt2.x = (r->x+r->width)*scale;
#ifdef WIN32
pt1.y = img->height - r->y*scale;
pt2.y = img->height - (r->y+r->height)*scale;
#else
pt1.y = r->y*scale;
pt2.y = (r->y+r->height)*scale;
#endif
cvRectangle( img, pt1, pt2, CV_RGB(255,255,0), 3 );
}
}
cvShowImage(WINNAME, img );
//cvReleaseImage( &temp );
}
#ifdef _EiC
main(1,facedetect.c);
#endif