年前在OpenCV论坛上看到Shiqi Yu发布的免费的高性能的人脸检测库,于是down下来做了一下效果测试。感兴趣的同学,也可以做一下检测速度的比较。
本人才疏学浅,只是将它与OpenCV自带的人脸检测库函数做了一个粗浅的比较,欢迎各位大神提点。
程序功能简介:
程序实现环境:VS2010 + OpenCV 2.4.11
程序退出:在窗口中敲击回车键即可;
旋转图像:鼠标拖动窗口中的Angle轴滑块即可;
缩放图像:鼠标拖动窗口中的Scale轴滑块即可;
平移图像:在窗口中任意位置,鼠标左键拖拽图像即可;
平移图像后复原:在窗口中任意位置,单击鼠标右键即可;
切换人脸检测库函数:鼠标拖动窗口中的Mode轴滑块即可。
对于Mode值的说明:
- 当 0≤Mode≤4 时,检测函数采用的是OpenCV自带的级联检测模块CascadeClassifier(如何使用级联分类器做人脸检测,可以参见OpenCV的Tutorial,这里有相应的中文翻译版)。具体说明如下:
当mode=0时,加载的是lbpcascade_frontalface.xml;
当mode=1时,加载的是haarcascade_frontalface_alt.xml;
当mode=2时,加载的是haarcascade_frontalface_alt2.xml;
当mode=3时,加载的是haarcascade_frontalface_default.xml;
当mode=4时,加载的是haarcascade_frontalface_alt_tree.xml;
- 当 5≤Mode≤8 时,检测函数采用的是Shiqi Yu发布的[免费的高性能的人脸检测库](使用方法可参见它自带的示例程序)。具体说明如下:
当mode=5时,调用的是facedetect_frontal();
当mode=6时,调用的是facedetect_frontal_surveillance();
当mode=7时,调用的是facedetect_multiview();
当mode=8时,调用的是facedetect_multiview_reinforce();
程序代码:
#include <time.h>
#include <stdio.h>
#include <vector>
#include <iostream>
#include <opencv.hpp>
#include "facedetect-dll.h"
using namespace cv;
using namespace std;
#pragma comment(lib,"libfacedetect.lib")
//#pragma comment(lib,"libfacedetect-x64.lib")
//Do not change the buffer size!
#define DETECT_BUFFER_SIZE 0xC004
static Mat onRot(int pos, int rat, Mat* im);
static Mat onAffine(Mat* im, Point2f dif);
static void onMouse(int Event, int x, int y, int drag, Mat* im);
static int Detect_Display(Mat& im, int mod);
void main(int argc, char* argv[])
{
cout<<"Hello, VS10. I'm back!"<<endl;
Mat Pic = imread("Friends2.jpg"), Cam(Pic), dst;
namedWindow("Video"); int pos = 36, rat = 10, mod = 0;
createTrackbar("Angle","Video", &pos,72);
createTrackbar("Scale","Video", &rat,40);
createTrackbar("Mode","Video", &mod,8);
setMouseCallback("Video", (MouseCallback)onMouse, &Cam);
//VideoCapture cap(0);
while((waitKey(100)&255)!=13) //Enter=13
{
dst = onRot(pos, rat, &Cam);
Detect_Display(dst, mod);
imshow("Video", dst);
}//end while
}//end main
static int Detect_Display(Mat& im, int mod)
{
Mat gray; cvtColor(im, gray, CV_BGR2GRAY); //must gray
vector<Rect> faces, eyes; equalizeHist(gray, gray); //normalization
int *pResults = NULL; //!!! DO NOT RELEASE pResults !!!
//pBuffer is used in the facedetect_XXX functions:
unsigned char* pBuffer = (unsigned char*)malloc(DETECT_BUFFER_SIZE);
if(!pBuffer) {fprintf(stderr, "Can not alloc buffer.\n"); return 0;}
CascadeClassifier Eyes("haarcascade_eye_tree_eyeglasses.xml"), Face;
switch(mod)
{
case 0: if(!Face.load("lbpcascade_frontalface.xml")) return 0;
Face.detectMultiScale(gray, faces, 1.1, 2, CV_HAAR_SCALE_IMAGE|0, Size(30,30)); break;
case 1: if(!Face.load("haarcascade_frontalface_alt.xml")) return 0;
Face.detectMultiScale(gray, faces, 1.1, 2, CV_HAAR_SCALE_IMAGE|0, Size(30,30)); break;
case 2: if(!Face.load("haarcascade_frontalface_alt2.xml")) return 0;
Face.detectMultiScale(gray, faces, 1.1, 2, CV_HAAR_SCALE_IMAGE|0, Size(30,30)); break;
case 3: if(!Face.load("haarcascade_frontalface_default.xml")) return 0;
Face.detectMultiScale(gray, faces, 1.1, 2, CV_HAAR_SCALE_IMAGE|0, Size(30,30)); break;
case 4: if(!Face.load("haarcascade_frontalface_alt_tree.xml")) return 0;
Face.detectMultiScale(gray, faces, 1.1, 2, CV_HAAR_SCALE_IMAGE|0, Size(30,30)); break;
//frontal face detection: it's fast, but cannot detect side view faces.
case 5: pResults = facedetect_frontal(pBuffer, (unsigned char*)(gray.ptr(0)),
gray.cols, gray.rows, (int)gray.step, 1.2f, 2, 48); break;
//frontal face detection for video surveillance: it can detect faces with bad illumination.
case 6: pResults = facedetect_frontal_surveillance(pBuffer, (unsigned char*)(gray.ptr(0)),
gray.cols, gray.rows, (int)gray.step, 1.2f, 2, 48); break;
//multiview face detection: it can detect side view faces, but slower than facedetect_frontal().
case 7: pResults = facedetect_multiview(pBuffer, (unsigned char*)(gray.ptr(0)),
gray.cols, gray.rows, (int)gray.step, 1.2f, 2, 48); break;
//reinforced multiview face detection: it's better but slower than facedetect_multiview().
case 8: pResults = facedetect_multiview_reinforce(pBuffer, (unsigned char*)(gray.ptr(0)),
gray.cols, gray.rows, (int)gray.step, 1.2f, 2, 48); break;
}//end switch
if(mod>4) faces.resize(pResults?(*pResults):0); //for facedetect_XXX functions
cout<<faces.size()<<" faces detected!\n";
for(int i=0; i<faces.size(); ++i) //mark each face
{
if(mod>4) //for facedetect_XXX functions
{ short* p = ((short*)(pResults+1)) + 6*i;
faces[i].x = p[0]; faces[i].width = p[2];
faces[i].y = p[1]; faces[i].height = p[3];
cout<<"face_rect = "<<faces[i]<<", neighbors = "<<p[4]<<".\n";
}//end if
rectangle(im, faces[i], Scalar(255,0,255), 2); //mark with rectangle
Mat faceROI = gray(faces[i]); //In each face, detect eyes
Eyes.detectMultiScale(faceROI, eyes, 1.1, 2, CV_HAAR_SCALE_IMAGE|0, Size(30,30));
for(int j=0; j<eyes.size(); ++j) //mark each eye
{
Point center(faces[i].x + eyes[j].x + eyes[j].width*0.5, faces[i].y + eyes[j].y + eyes[j].height*0.5);
int radius = cvRound((eyes[j].width + eyes[j].height)/4);
circle(im, center, radius, Scalar(255,0,0), 2); //mark with circle
}//end for
}//end for
free(pBuffer); return faces.size(); //release pBuffer
}//end Detect_Display
static Mat onRot(int pos, int rat, Mat* im)
{
Point center(im->cols/2, im->rows/2);
double angle = 5*pos-180, scale = 0.1*rat;
Mat rot = getRotationMatrix2D(center, angle, scale), dst;
warpAffine(*im, dst, rot, im->size()); return dst;
}//end onRot
static void onMouse(int Event, int x, int y, int drag, Mat* im)
{ //only effective for Picture, not fit for Cam.
static Mat res = im->clone(); static const Point ini(0,0);
static Point seed(ini), tdf(ini); Point now(x,y);
switch(Event)
{
case CV_EVENT_LBUTTONDOWN: seed = now; break;
case CV_EVENT_LBUTTONUP: tdf += (now-seed); break;
case CV_EVENT_RBUTTONUP: res.copyTo(*im); tdf = ini; break;
}//end switch
if(drag==CV_EVENT_FLAG_LBUTTON) *im = onAffine(&res, tdf+(now-seed));
}//end onMouse
static Mat onAffine(Mat* im, Point2f dif)
{
Point2f org[3],tri[3]; org[1] = Point2f(im->cols/2, 0);
org[0] = Point2f(0,0); org[2] = Point2f(0, im->rows/2);
for(int i=0; i<3; ++i) tri[i] = org[i] + dif;
Mat warp = getAffineTransform(org, tri), dst;
warpAffine(*im, dst, warp, im->size()); return dst;
}//end onAffine
程序效果图: