我现在的角色只是一个软件开发人员,所以暂时不深究算法问题,我的目的只有一个:以最快的方式完成项目框架搭建,从而进行进度评估。
说明
进行人脸鉴别(不关心是谁的脸)从代码量上来讲可以说非常少,我不再作具体说明,源码的注释已经足够详细,这里我使用的CascadeClassifier,大体分为三步:
int main( int argc, const char** argv )
{
test();
return 0;
}
void test()
{
VideoCapture cap(0);//为了方便,使用opencv自带的函数驱动摄像头,之后会移植v4l2过来
if(!cap.isOpened())
{
perror("fail to open camera");
return;
}
Mat image;
bool tryflip = false;
CascadeClassifier cascade, nestedCascade;
cascade.load( "/usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_alt.xml" );//加载主级联分类器
nestedCascade.load("/usr/local/share/OpenCV/haarcascades/haarcascade_eye_tree_eyeglasses.xml");//加载辅助级联分类器
double scale = 1.5;
image = imread( "./lena.jpg", 1 );//加载图片
while(1)
{
cap >> image;//获取一帧图像
detectAndDraw( image, cascade, nestedCascade, scale, tryflip );
waitKey(30);//每30ms检测一次
}
//detectAndDraw( image, cascade, nestedCascade, scale, tryflip );
//waitKey(0);
}
void detectAndDraw( Mat& img, CascadeClassifier& cascade,
CascadeClassifier& nestedCascade,
double scale, bool tryflip )
{
double t = 0;
vector faces, faces2;
const static Scalar colors[] =
{
Scalar(255,0,0),
Scalar(255,128,0),
Scalar(255,255,0),
Scalar(0,255,0),
Scalar(0,128,255),
Scalar(0,255,255),
Scalar(0,0,255),
Scalar(255,0,255)
};//定义一些颜色备用
Mat gray, smallImg;
cvtColor( img, gray, COLOR_BGR2GRAY );//转换颜色空间
double fx = 1 / scale;
resize( gray, smallImg, Size(), fx, fx, INTER_LINEAR );//重新调整大小
equalizeHist( smallImg, smallImg );
t = (double)getTickCount();//用于计算检测时间
cascade.detectMultiScale( smallImg, faces,
1.1, 2, 0
//|CASCADE_FIND_BIGGEST_OBJECT
//|CASCADE_DO_ROUGH_SEARCH
|CASCADE_SCALE_IMAGE,
Size(30, 30) );//主鉴别器进行检测,检测到的脸部位置保存在faces里
if( tryflip )//如果设置了翻转检测,就先翻转再检测
{
flip(smallImg, smallImg, 1);
cascade.detectMultiScale( smallImg, faces2,
1.1, 2, 0
//|CASCADE_FIND_BIGGEST_OBJECT
//|CASCADE_DO_ROUGH_SEARCH
|CASCADE_SCALE_IMAGE,
Size(30, 30) );
for( vector ::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)getTickCount() - t;
printf( "detection time = %g ms\n", t*1000/getTickFrequency());
for ( size_t i = 0; i < faces.size(); i++ )//对每一个脸的位置画上圆圈标记
{
Rect r = faces[i];
Mat smallImgROI;
vector 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
//|CASCADE_FIND_BIGGEST_OBJECT
//|CASCADE_DO_ROUGH_SEARCH
//|CASCADE_DO_CANNY_PRUNING
|CASCADE_SCALE_IMAGE,
Size(30, 30) );
for ( size_t j = 0; j < nestedObjects.size(); j++ )
{
Rect nr = nestedObjects[j];
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 );
}
}
imshow( "result", img );//显示这一帧的检测结果
}