搜档网
当前位置:搜档网 › 基于OPENCV的人脸识别程序 代码详解

基于OPENCV的人脸识别程序 代码详解

基于OPENCV的人脸识别程序 代码详解
基于OPENCV的人脸识别程序 代码详解

#include"cv.h"

#include"highgui.h"

#include

#ifdef_EiC

#define WIN32

#endif

static CvMemStorage*storage=0;

static CvHaarClassifierCascade*cascade=0;

void detect_and_draw(IplImage*image);

const char*cascade_name=

"haarcascade_frontalface_alt.xml";//人脸检测分类器

int main(int argc,char**argv)

{

CvCapture*capture=0;

IplImage*frame,*frame_copy=0;

int optlen=strlen("--cascade=");

const char*input_name;

if(argc>1&&strncmp(argv[1],"--cascade=",optlen)==0)

{

cascade_name=argv[1]+optlen;

input_name=argc>2?argv[2]:0;

}

else

{

cascade_name="E:\毕业设计\智能机器人动态人脸识别系统\陈建州程序.xml";//分类器路径

input_name=argc>1?argv[1]:0;

}

cascade=(CvHaarClassifierCascade*)cvLoad(cascade_name,0,0,0);

if(!cascade)//如果没有找到分类器,输出以下

{

fprintf(stderr,"ERROR:Could not load classifier cascade\n");

fprintf(stderr,

"Usage:facedetect--cascade=\"\"[filename|camera_index]\n");

return-1;

}

storage=cvCreateMemStorage(0);

capture=cvCaptureFromCAM(!input_name?0:input_name[0]-'0');//读取摄像头

if(!capture)//如果没有摄像头读取视频文件

capture=cvCaptureFromAVI("检测.avi");

cvNamedWindow("result",1);//创建窗口

if(capture)

{

for(;;)

{

if(!cvGrabFrame(capture))//从摄像头中抓取帧

break;

frame=cvRetrieveFrame(capture);//读取上边抓取的帧

if(!frame)

break;

if(!frame_copy)

frame_copy=cvCreateImage(cvSize(frame->width,frame->height),

IPL_DEPTH_8U,frame->nChannels);

if(frame->origin==IPL_ORIGIN_TL)

cvCopy(frame,frame_copy,0);

else

cvFlip(frame,frame_copy,0);

detect_and_draw(frame_copy);

if(cvWaitKey(10)>=0)

break;

}

cvReleaseImage(&frame_copy);

cvReleaseCapture(&capture);

}

else//没检测到视频文件或者摄像头

{

const char*filename=(char*)"检测.jpg";//读图片

IplImage*image=cvLoadImage(filename,1);

if(image)

{

detect_and_draw(image);

cvWaitKey(0);

cvReleaseImage(&image);

}

else

{

FILE*f=fopen(filename,"rt");

if(f)

{

char buf[1000+1];

while(fgets(buf,1000,f))

{

int len=(int)strlen(buf);

while(len>0&&isspace(buf[len-1]))

len--;

buf[len]='\0';

image=cvLoadImage(buf,1);

if(image)

{

detect_and_draw(image);

cvWaitKey(0);

cvReleaseImage(&image);

}

}

fclose(f);

}

}

}

cvDestroyWindow("result");

return0;

}

void detect_and_draw(IplImage*img)

{

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}}

};

double scale=1.3;

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);

int i;

cvCvtColor(img,gray,CV_BGR2GRAY);

cvResize(gray,small_img,CV_INTER_LINEAR);

cvEqualizeHist(small_img,small_img);

cvClearMemStorage(storage);

if(cascade)

{

double t=(double)cvGetTickCount();

CvSeq*faces=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.));

for(i=0;i<(faces?faces->total:0);i++)//找到矩形中心,把矩形转化为圆形

{

CvRect*r=(CvRect*)cvGetSeqElem(faces,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);

}

OpenCV的人脸检测主要是调用训练好的cascade(Haar分类器)来进行模式匹配。cvHaarDetectObjects,先将图像灰度化,根据传入参数判断是否进行canny边缘处理(默认不使用),再进行匹配。匹配后收集找出的匹配块,过滤噪声,计算相邻个数如果超过了规定值(传入的min_neighbors)就当成输出结果,否则删去。

匹配循环:将匹配分类器放大scale(传入值)倍,同时原图缩小scale倍,进行匹配,直到匹配分类器的大小大于原图,则返回匹配结果。匹配的时候调用cvRunHaarClassifierCascade 来进行匹配,将所有结果存入CvSeq*Seq(可动态增长元素序列),将结果传给cvHaarDetectObjects。

cvRunHaarClassifierCascade函数整体是根据传入的图像和cascade来进行匹配。并且可以根据传入的cascade类型不同(树型、stump(不完整的树)或其他的),进行不同的匹配方式。函数cvRunHaarClassifierCascade用于对单幅图片的检测。在函数调用前首先利用cvSetImagesForHaarClassifierCascade设定积分图和合适的比例系数(=>窗口尺寸)。当分析的矩形框全部通过级联分类器每一层的时返回正值(这是一个候选目标),否则返回0或负值。

为了了解OpenCV人脸检测中寻找匹配图像的详细过程,就把cvHaarDetectObjects和cvRunHaarClassifierCascade的源文件详细看了一遍,并打上了注释。方便大家阅读。

附cvHaarDetectObjects代码:

CV_IMPL CvSeq*

cvHaarDetectObjects(const CvArr*_img,

CvHaarClassifierCascade*cascade,

CvMemStorage*storage,double scale_factor,

int min_neighbors,int flags,CvSize min_size)

{

int split_stage=2;

CvMat stub,*img=(CvMat*)_img; //CvMat多通道矩阵*img=_img指针代换传入图

CvMat*temp=0,*sum=0,*tilted=0,*sqsum=0,*norm_img=0,*sumcanny=0, *img_small=0;

CvSeq*seq=0;

CvSeq*seq2=0; //CvSeq可动态增长元素序列

CvSeq*idx_seq=0;

CvSeq*result_seq=0;

CvMemStorage*temp_storage=0;

CvAvgComp*comps=0;

int i;

#ifdef_OPENMP

CvSeq*seq_thread[CV_MAX_THREADS]={0};

int max_threads=0;

#endif

CV_FUNCNAME(“cvHaarDetectObjects”);

__BEGIN__;

double factor;

int npass=2,coi; //npass=2

int do_canny_pruning=flags&CV_HAAR_DO_CANNY_PRUNING; //true做canny边缘处理

if(!CV_IS_HAAR_CLASSIFIER(cascade))

CV_ERROR(!cascade?CV_StsNullPtr:CV_StsBadArg,“Invalid classifier cascade”);

if(!storage)

CV_ERROR(CV_StsNullPtr,“Null storage pointer”);

CV_CALL(img=cvGetMat(img,&stub,&coi));

if(coi)

CV_ERROR(CV_BadCOI,“COI is not supported”); //一些出错代码

if(CV_MAT_DEPTH(img->type)!=CV_8U)

CV_ERROR(CV_StsUnsupportedFormat,“Only8-bit images are supported”);

CV_CALL(temp=cvCreateMat(img->rows,img->cols,CV_8UC1));

CV_CALL(sum=cvCreateMat(img->rows+1,img->cols+1,CV_32SC1));

CV_CALL(sqsum=cvCreateMat(img->rows+1,img->cols+1,CV_64FC1));

CV_CALL(temp_storage=cvCreateChildMemStorage(storage));

#ifdef_OPENMP

max_threads=cvGetNumThreads();

for(i=0;i

{

CvMemStorage*temp_storage_thread;

CV_CALL(temp_storage_thread=cvCreateMemStorage(0)); //CV_CALL就是运行,假如出错就报错。

CV_CALL(seq_thread[i]=cvCreateSeq(0,sizeof(CvSeq),//CvSeq 可动态增长元素序列

sizeof(CvRect),temp_storage_thread));

}

#endif

if(!cascade->hid_cascade)

CV_CALL(icvCreateHidHaarClassifierCascade(cascade));

if(cascade->hid_cascade->has_tilted_features)

tilted=cvCreateMat(img->rows+1,img->cols+1,CV_32SC1);//多通道矩阵图像长宽+14通道

seq=cvCreateSeq(0,sizeof(CvSeq),sizeof(CvRect),temp_storage);//创建序列seq矩形

seq2=cvCreateSeq(0,sizeof(CvSeq),sizeof(CvAvgComp),temp_storage);//创建序列seq2矩形和邻近

result_seq=cvCreateSeq(0,sizeof(CvSeq),sizeof(CvAvgComp),storage);//创建序列result_seq矩形和邻近

if(min_neighbors==0)

seq=result_seq;

if(CV_MAT_CN(img->type)>1)

{

cvCvtColor(img,temp,CV_BGR2GRAY); //img转为灰度

img=temp;

}

if(flags&CV_HAAR_SCALE_IMAGE) //flag&&匹配图

{

CvSize win_size0=cascade->orig_window_size; //CvSize win_size0为分类器的原始大小

int use_ipp=cascade->hid_cascade->ipp_stages!=0&&

icvApplyHaarClassifier_32s32f_C1R_p!=0;//IPP 相关函数

if(use_ipp)

CV_CALL(norm_img=cvCreateMat(img->rows,img->cols,CV_32FC1)); //图像的矩阵化4通道.

CV_CALL(img_small=cvCreateMat(img->rows+1,img->cols+1,CV_8UC1)); //小图矩阵化单通道长宽+1

for(factor=1;;factor*=scale_factor) //成scale_factor倍数匹配

{

int positive=0;

int x,y;

CvSize win_size={cvRound(win_size0.width*factor),

cvRound(win_size0.height*factor)}; //winsize分类器行列(扩大factor倍)

CvSize sz={cvRound(img->cols/factor),cvRound(img->rows/factor)}; //sz图像行列(缩小factor倍)三个Cvsize

CvSize sz1={sz.width–win_size0.width,sz.height–win_size0.height}; //sz1图像减分类器行列

CvRect rect1={icv_object_win_border,icv_object_win_border,

win_size0.width–icv_object_win_border*2, //icv_object_win_border(int)初始值=1

win_size0.height–icv_object_win_border*2}; //矩形框rect1

CvMat img1,sum1,sqsum1,norm1,tilted1,mask1; //多通道矩阵

CvMat*_tilted=0;

if(sz1.width<=0||sz1.height<=0) //图片宽或高小于分类器–>跳出

break;

if(win_size.width继续

continue;

//CV_8UC1见定义.

//#define CV_MAKETYPE(depth,cn)((depth)+(((cn)-1)<

//深度+(cn-1)左移3位depth,depth+8,depth+16,depth+24.

img1=cvMat(sz.height,sz.width,CV_8UC1,img_small->data.ptr); //小图的矩阵化img1单通道

sum1=cvMat(sz.height+1,sz.width+1,CV_32SC1,sum->data.ptr); //长宽+14通道8位多通道矩阵

sqsum1=cvMat(sz.height+1,sz.width+1,CV_64FC1,sqsum->data.ptr); //长宽+14通道16位

if(tilted)

{

tilted1=cvMat(sz.height+1,sz.width+1,CV_32SC1,tilted->data.ptr);//长宽+14通道8位

_tilted=&tilted1; //长宽+14通道8位

}

norm1=cvMat(sz1.height,sz1.width,CV_32FC1,norm_img? norm_img->data.ptr:0);//norm1图像减分类器行列4通道

mask1=cvMat(sz1.height,sz1.width,CV_8UC1,temp->data.ptr); //mask1灰度图

cvResize(img,&img1,CV_INTER_LINEAR); //img双线性插值输出到img1

cvIntegral(&img1,&sum1,&sqsum1,_tilted); //计算积分图像

if(use_ipp&&icvRectStdDev_32s32f_C1R_p(sum1.data.i,sum1.step,

sqsum1.data.db,sqsum1.step,norm1.data.fl,norm1.step,sz1,rect1)<0)

use_ipp=0;

if(use_ipp) //如果ipp=true(intel视频处理加速等的函数库)

{

positive=mask1.cols*mask1.rows; //mask1长乘宽–>positive

cvSet(&mask1,cvScalarAll(255)); //mask1赋值为255

for(i=0;icount;i++)

{

if(icvApplyHaarClassifier_32s32f_C1R_p(sum1.data.i,sum1.step,

norm1.data.fl,norm1.step,mask1.data.ptr,mask1.step,

sz1,&positive,cascade->hid_cascade->stage_classifier[i].threshold,

cascade->hid_cascade->ipp_stages[i])<0)

{

use_ipp=0; //ipp=false;

break;

}

if(positive<=0)

break;

}

}

if(!use_ipp) //如果ipp=false

{

cvSetImagesForHaarClassifierCascade(cascade,&sum1,&sqsum1,0,1.);

for(y=0,positive=0;y

for(x=0;x

{

mask1.data.ptr[mask1.step*y+x]=

cvRunHaarClassifierCascade(cascade,cvPoint(x,y),0)>0; //匹配图像.

positive+=mask1.data.ptr[mask1.step*y+x];

}

}

if(positive>0)

{

for(y=0;y

for(x=0;x

if(mask1.data.ptr[mask1.step*y+x]!=0)

{

CvRect obj_rect={cvRound(y*factor),cvRound(x*factor),

win_size.width,win_size.height};

cvSeqPush(seq,&obj_rect); //将匹配块放到seq中

}

}

}

}

else

//!(flag&&匹配图)

{

cvIntegral(img,sum,sqsum,tilted);

if(do_canny_pruning)

{

sumcanny=cvCreateMat(img->rows+1,img->cols+1,CV_32SC1); //如果做canny边缘检测

cvCanny(img,temp,0,50,3);

cvIntegral(temp,sumcanny);

}

if((unsigned)split_stage>=(unsigned)cascade->count||

cascade->hid_cascade->is_tree)

{

split_stage=cascade->count;

npass=1;

}

for(factor=1;factor*cascade->orig_window_size.widthcols–10&& //匹配

factor*cascade->orig_window_size.heightrows–10;

factor*=scale_factor)

{

const double ystep=MAX(2,factor);

CvSize win_size={cvRound(cascade->orig_window_size.width*factor),

cvRound(cascade->orig_window_size.height*factor)};

CvRect equ_rect={0,0,0,0};

int*p0=0,*p1=0,*p2=0,*p3=0;

int*pq0=0,*pq1=0,*pq2=0,*pq3=0;

int pass,stage_offset=0;

int stop_height=cvRound((img->rows–win_size.height)/ystep);

if(win_size.width

continue;

cvSetImagesForHaarClassifierCascade(cascade,sum,sqsum,tilted,factor); //匹配

cvZero(temp); //清空temp数组

if(do_canny_pruning) //canny边缘检测

{

equ_rect.x=cvRound(win_size.width*0.15);

equ_rect.y=cvRound(win_size.height*0.15);

equ_rect.width=cvRound(win_size.width*0.7);

equ_rect.height=cvRound(win_size.height*0.7);

p0=(int*)(sumcanny->data.ptr+equ_rect.y*sumcanny->step)+equ_rect.x;

p1=(int*)(sumcanny->data.ptr+equ_rect.y*sumcanny->step)

+equ_rect.x+equ_rect.width;

p2=(int*)(sumcanny->data.ptr+(equ_rect.y+ equ_rect.height)*sumcanny->step)+equ_rect.x;

p3=(int*)(sumcanny->data.ptr+(equ_rect.y+ equ_rect.height)*sumcanny->step)

+equ_rect.x+equ_rect.width;

pq0=(int*)(sum->data.ptr+equ_rect.y*sum->step)+equ_rect.x;

pq1=(int*)(sum->data.ptr+equ_rect.y*sum->step)

+equ_rect.x+equ_rect.width;

pq2=(int*)(sum->data.ptr+(equ_rect.y+equ_rect.height)*sum->step)+ equ_rect.x;

pq3=(int*)(sum->data.ptr+(equ_rect.y+equ_rect.height)*sum->step)

+equ_rect.x+equ_rect.width;

}

cascade->hid_cascade->count=split_stage; //分裂级

for(pass=0;pass

{

#ifdef_OPENMP

人脸识别在opencv下作人脸检测(转)OPENCV2010-03-0415:17:51阅读103评论0字号:大中小

人脸识别的第一步,就是人脸检测。把人的脸部从一张照片中用计算机自动识别出来,作为下一步人脸识别的基础。

在opencv中,库中自带了一个利用harr特征的人脸检测训练及检测函数:cvHaarDetectObjects。它利用训练好的检测器,在图片中间检测你想要的物体,如人脸。opencv 自带了很多检测器,在%opencv%data/haarcascades目录下,你可以随意取用。或者你也可以自己用图片训练自己的检测器,之后拿来使用。

下面是检测人脸的源代码:

//Usage:DetectFaces

#include

#include"cv.h"

#include"highgui.h"

//***Change this to your install location!***

//*********************************************

#define OPENCV_ROOT"C:/Program Files/OpenCV"

//*********************************************

void displayDetections(IplImage*pInpImg,CvSeq*pFaceRectSeq,char*FileName); int main(int argc,char**argv)

{

//variables

IplImage*pInpImg=0;

CvHaarClassifierCascade*pCascade=0;//the face detector

CvMemStorage*pStorage=0;//memory for detector to use

CvSeq*pFaceRectSeq;//memory-access interface

//usage check

if(argc<2)

{

printf("Missing name of image file!\n"

"Usage:%s\n",argv[0]);

exit(-1);

}

//initializations

pInpImg=(argc>1)?cvLoadImage(argv[1],CV_LOAD_IMAGE_COLOR):0; pStorage=cvCreateMemStorage(0);

pCascade=(CvHaarClassifierCascade*)cvLoad

((OPENCV_ROOT"/data/haarcascades/haarcascade_frontalface_default.xml"), 0,0,0);

//validate that everything initialized properly

if(!pInpImg||!pStorage||!pCascade)

{

printf("Initialization failed:%s\n",

(!pInpImg)?"can't load image file":

(!pCascade)?"can't load haar-cascade--"

"make sure path is correct":

"unable to allocate memory for data storage",argv[1]);

exit(-1);

}

//detect faces in image

pFaceRectSeq=cvHaarDetectObjects

(pInpImg,pCascade,pStorage,

1.1,//increase search scale by10%each pass

3,//merge groups of three detections

CV_HAAR_DO_CANNY_PRUNING,//skip regions unlikely to contain a face cvSize(40,40));//smallest size face to detect=40x40

//display detected faces

displayDetections(pInpImg,pFaceRectSeq,argv[1]);

//clean up and release resources

cvReleaseImage(&pInpImg);

if(pCascade)cvReleaseHaarClassifierCascade(&pCascade);

if(pStorage)cvReleaseMemStorage(&pStorage);

return0;

}

void displayDetections(IplImage*pInpImg,CvSeq*pFaceRectSeq,char*FileName) {

const char*DISPLAY_WINDOW="Haar Window";

int i;

//create a window to display detected faces

cvNamedWindow(DISPLAY_WINDOW,CV_WINDOW_AUTOSIZE);

//draw a rectangular outline around each detection

for(i=0;i<(pFaceRectSeq?pFaceRectSeq->total:0);i++)

{

CvRect*r=(CvRect*)cvGetSeqElem(pFaceRectSeq,i);

CvPoint pt1={r->x,r->y};

CvPoint pt2={r->x+r->width,r->y+r->height};

cvRectangle(pInpImg,pt1,pt2,CV_RGB(0,255,0),3,4,0);

cvSetImageROI(pInpImg,*r);

//char*FileName=argv[1];

IplImage*dst=cvCreateImage(cvSize(92,112),pInpImg->depth,pInpImg->nChannels); cvResize(pInpImg,dst,CV_INTER_LINEAR);

strcat(FileName,".pgm");

cvSaveImage(FileName,dst);

}

//display face detections

cvShowImage(DISPLAY_WINDOW,pInpImg);

cvWaitKey(0);

cvDestroyWindow(DISPLAY_WINDOW);

}

程序会将人脸检测出来,显示在屏幕上,并存回原来的文件将其覆盖。在window xp,devcpp4.9.9.2下编译通过。

相关主题