人脸识别系统主要包括四个组成部分,分别为:人脸图像采集及检测、人脸图像预处理、人脸图像特征提取以及匹配与识别。
以上摘自维基百科,虽然很普通的过程,却不失一般性,顾一个完整的系统,基本要靠这几步来完成,是否能开发出更好更快的而非这种结构的系统也是一个很值得深入的话题,比如一幅包含人脸和复杂背景的图片,是否能不通过分割而直接识别出人脸是谁,或者识别一个物体不是通过现有特征描述而是使用更符合人脑识别机制的其他描述,这些都值得我们深入研究。
其次,我们要区分人脸检测和人脸识别,所谓检测是区分人脸和非人脸,而识别是要得出已知人脸术属于谁,这从意义和用途上都有区别,而现在很多人将人脸识别和人脸检测混为一谈,包括知名专家(上过研究生的人都知道,有些老板根本不干活)。
或者我们可以更简单的把检测当做是分割(segment)的过程,即对物体进行识别最基本的过程:分割+识别。检测过程为输入一张复杂的图像,输出是其中人脸的部分,而识别是输入一张人脸的图像,输出的是这个人的身份信息或其他的只和此人有关的信息。
检测算法和识别算法的结构多为:特征描述+分类算法。
特征描述给出不同物体间不同的表示,该描述应该具有一定的性质,包括特异性,即不同物体特征值不同,并对旋转,缩放,光照,形变等不敏感。好的特征描述能够使识别更加准确,而好的分类算法也能提高准确度和计算速度,分类算法多为机器学习算法,即需要训练,才能用于识别工作。
目前比较常用的特征描述有:Haar-like,LBP,SIFT,SURF等常见特征描述。
人脸识别算法分类:
后来又衍生了很多种Haar-like特征的计算方法,但计算法则不变,都是白色框内的像素总和减去黑色的,如下:
以下为图4.1描述的Haar-like特征在不同尺寸图像中的数量(窗口大小就是图像大小)
4.3
优化Haar-like计算速度的方法是使用积分图像,积分图像的简单描述为:对于单通道图像F(x,y),其积分图像G(x,y)与F(x,y)具有相同尺寸大小,且点G(x0,y0)处的值为SUM(F(i,j))其中(i<=x0&&j<=y0),公式描述为下图,ii为积分图像G,i为原始图像F。
所以我们有下列结构,点4的值为ABCD区域像素值的总和,1为A区域的像素值总和,2,3同理:
4.4
所以区域D内像素和的值为:4-2-3+1,这个不难理解,因为2,3都包括1,所以多减了一次,要加回来。这样就很容易的计算局部区域的像素和,从而方便了Haar-like特征值的求解。
#include "adaboost.h" void initStrongCl(StrongCl *strongwl,int t){ WeakCl* weakcl=(WeakCl*)malloc(sizeof(WeakCl)*t); if(weakcl==NULL) exit(0); strongwl->T=t; strongwl->weakcl=weakcl; } void releaseStrongCl(StrongCl *strongwl){ free(strongwl->weakcl); } //get data and label from input TrainData* getTrainData(int *Data_Size){ printf("Input your datasize:"); scanf("%d",Data_Size); TrainData *data=(TrainData *)malloc(sizeof(TrainData)*(*Data_Size)); if(data!=NULL) printf("Memory allocation succeeds\n"); else printf("Memory allocation failed\n"); printf("input property and label(positive 1 and nagitive 0):\n"); for(int i=0;i<(*Data_Size);i++){ scanf("%d,%d",&data[i].property,&data[i].label); } return data; } //free memory void freeTrainData(TrainData* data){ free(data); } //showdata void showTrainData(TrainData* data,int Data_Size){ printf("property1 \n"); for(int i=0;i<Data_Size;i++) printf("%d\n",data[i].property); } // double getBeta(double erro){ return erro/(1.0-erro); } double getAlpha(double beta){ return log(1.0/beta); } void updataWi(TrainData *data,double beta,int Data_Size){ for(int i=0;i<Data_Size;i++){ if(data[i].status==HIT) data[i].w=data[i].w*beta; else if(data[i].status==MISS) data[i].w=data[i].w; } } void nomalization(TrainData *data,int Data_Size){ double sum=0.0; for(int i=0;i<Data_Size;i++){ sum+=data[i].w; } //printf("Sum of w:%lf\n",sum); for(int i=0;i<Data_Size;i++){ data[i].w=data[i].w/sum; } } void InitWi(TrainData *data,int Data_Size){ double positive=0.0; for(int i=0;i<Data_Size;i++) if(data[i].label==1) positive++; for(int i=0;i<Data_Size;i++){ if(data[i].label==1) data[i].w=1.0/(2.0*positive); else data[i].w=1.0/(2.0*(Data_Size-positive)); } } void InitStatus(TrainData *data,int Data_Size){ for(int i=0;i<Data_Size;i++) data[i].status=HIT; } double getError(TrainData *data,int Data_Size){ double error=0.0; for(int i=0;i<Data_Size;i++) if(data[i].status==MISS) error+=data[i].w; return error; } void Adaboost(TrainData *data,int Data_Size,StrongCl *dst){ int T=dst->T; InitWi(data,Data_Size); int temptheta=0,theta1=0; double error,beta; int p=0; //p=0 <=> '<' p=0 <=> '>' double min; //////////////left is positive & right is nagitive////////////// for(int i=0;i<T;i++){ //get theta first p=0; min=DBL_MAX;//////Be careful nomalization(data,Data_Size); for(int j=0;j<Data_Size;j++){ InitStatus(data,Data_Size); temptheta=data[j].property; for(int k=0;k<Data_Size;k++){ if((data[k].property<=temptheta)&&(data[k].label==0)) data[k].status=MISS; if((data[k].property>temptheta)&&(data[k].label)) data[k].status=MISS; } error=getError(data,Data_Size); if(error<=min&&error<0.5){ theta1=temptheta; min=error; } } //////////////right is positive & right is nagitive////////////// temptheta=0.0; int theta2=0.0; for(int j=0;j<Data_Size;j++){ InitStatus(data,Data_Size); temptheta=data[j].property; for(int k=0;k<Data_Size;k++){ if((data[k].property>=temptheta)&&(data[k].label==0)) data[k].status=MISS; if((data[k].property<temptheta)&&(data[k].label)) data[k].status=MISS; } error=getError(data,Data_Size); if(error<=min){ theta2=temptheta; min=error; p=1; } } ////////////////////////////////////////////////////////////////////////// InitStatus(data,Data_Size); int theta=p?theta2:theta1; if(p) for(int k=0;k<Data_Size;k++){ if((data[k].property>=theta)&&(data[k].label==0)) data[k].status=MISS; if((data[k].property<theta)&&(data[k].label)) data[k].status=MISS; } else for(int k=0;k<Data_Size;k++){ if((data[k].property<=theta)&&(data[k].label==0)) data[k].status=MISS; if((data[k].property>theta)&&(data[k].label)) data[k].status=MISS; } error=getError(data,Data_Size); beta=getBeta(error); updataWi(data, beta,Data_Size); if(p){ printf("|>=| |Threshold:%9d|error:%9lf |Alpha:%9lf|\n",theta,error,getAlpha(beta)); dst->weakcl[i].p=MORETHAN; dst->weakcl[i].alpha=getAlpha(beta); dst->weakcl[i].threshold=theta; } else{ printf("|<=| |Threshold:%9d|error:%9lf |Alpha:%9lf|\n",theta,error,getAlpha(beta)); dst->weakcl[i].p=LESSTHAN; dst->weakcl[i].alpha=getAlpha(beta); dst->weakcl[i].threshold=theta; } if(error>=0.5) break; } ////////let the sum of alpha==1; double alphasum=0.0; for(int i=0;i<dst->T;i++){ alphasum+=dst->weakcl[i].alpha; } for(int i=0;i<dst->T;i++){ dst->weakcl[i].alpha/=alphasum; } }
《Rapid_Object_Detection_using_a_Boosted_Cascade_of_Simple_Features》
《Robust Real-Time Face Detection》
人脸检测之Haar-like,Adaboost,级联(cascade)
原文:http://blog.csdn.net/tonyshengtan/article/details/41862855