opencv人脸识别facedetect的代码注释

第一次接触计算机视觉,需要使用opencv,于是借了些资料,发现这个人脸识别的程序非常有趣,于是就加了些简单的注释,以备更深入的学习。PS:水好深啊~~~加油了。

#include "opencv2/objdetect/objdetect.hpp"	//物体检测库
#include "opencv2/highgui/highgui.hpp"		//图形视频处理库
#include "opencv2/imgproc/imgproc.hpp"		//brief The Image Processing

#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";
string cascadeName = "haarcascade_frontalface_alt.xml";				//人脸的训练数据
//string nestedCascadeName = "haarcascade_eye_tree_eyeglasses.xml";	//人眼的训练数据
string nestedCascadeName = "haarcascade_eye.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;
	
	//一下两行代码可以删掉~~~~~
	if(argc==1)
		inputName="lena.jpg";

	//初始化
    for( int i = 1; i < argc; i++ )
    {
		//return 0;
        cout << "Processing " << i << " " <<  argv[i] << endl;
		waitKey(0);
        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;
        }
        else
            inputName.assign( argv[i] );
    }

    if( !cascade.load( cascadeName ) )	//从指定的文件目录中加载人脸级联分类器
    {
        cerr << "ERROR: Could not load classifier cascade" << endl;
        help();
        return -1;
    }
	if(!nestedCascade.load(nestedCascadeName))	//从指定的文件目录中加载人眼级联分类器
	{
		cerr<<"ERROR: Could not load classifier nestedCascade"<<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(;;)
        {
			/*
				cvQueryFrame函数从摄像头或者视频文件中抓取并返回一帧。
				cvQueryFrame返回的指针总是指向同一块内存。
				建议cvQueryFrame后拷贝一份。
				而且返回的帧需要FLIP后才符合OPENCV的坐标系。
			*/
            IplImage* iplImg = cvQueryFrame( capture );		//从摄像头或文件中抓取一帧
            frame = iplImg;
            if( frame.empty() )
                break;
            if( iplImg->origin == IPL_ORIGIN_TL )
                frame.copyTo( frameCopy );		//拷贝一份
            else
                flip( 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 the
            list 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 );	//将尺寸缩小到1/scale,用线性插值
    equalizeHist( smallImg, smallImg );		//使灰度图象直方图均衡化

    t = (double)cvGetTickCount();	//获取时间
	/*
		检测人脸
		detectMultiScale函数中smallImg表示的是要检测的输入图像为smallImg,faces表示检测到的人脸目标序列,
		1.1表示每次图像尺寸减小的比例为1.1,2表示每一个目标至少要被检测到3次才算是真的目标(因为周围的像素
		和不同的窗口大小都可以检测到人脸),CV_HAAR_SCALE_IMAGE表示不是缩放分类器来检测,而是缩放图像,
		Size(30, 30)为目标的最小最大尺寸
	*/
    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 );	//画圆,标示人脸
        }
        else
            rectangle( 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 );	//显示结果
}




你可能感兴趣的:(opencv,人脸识别,计算机视觉,FaceDetect)