OpenCV人脸识别的原理 完整版代码

OpenCV人脸识别的原理 完整版代码http://blog.csdn.net/yanming901012/article/details/8606183本程序首先利用从摄像头检测到的人脸图片,先进行直方图均衡化 并缩放到92*112的图片大小,然后根据train.txt的采集到的人脸模版 进行匹配识别(最好是在统一光照下,采集不同角度的人脸图片各一张) 注意:影响的极大因素在于光照,模版若与采集的图像光照不一样,识别率很低。…

大家好,又见面了,我是你们的朋友全栈君。

http://blog.csdn.net/yanming901012/article/details/8606183

本程序首先利用从摄像头检测到的人脸图片,先进行直方图均衡化  
并缩放到92*112的图片大小,然后根据train.txt的采集到的人脸模版  
进行匹配识别(最好是在统一光照下,采集不同角度的人脸图片各一张)  
注意:影响的极大因素在于光照,模版若与采集的图像光照不一样,识别率很低。  
经测试,模板若与检测的图像在同一光照下的话,侧脸,仰脸,正脸均可识别,且识别率较高  

//  
#include <stdio.h>  
#include <string.h>  
#include “cv.h”  
#include “cvaux.h”  
#include “highgui.h”  
#include <stdlib.h>  
#include <assert.h>    
#include <math.h>    
#include <float.h>    
#include <limits.h>    
#include <time.h>    
#include <ctype.h>    
  
定义几个重要的全局变量  
IplImage ** faceImgArr        = 0; // 指向训练人脸和测试人脸的指针(在学习和识别阶段指向不同)  
CvMat    *  personNumTruthMat = 0; // 人脸图像的ID号  
int nTrainFaces               = 0; // 训练图像的数目  
int nEigens                   = 0; // 自己取的主要特征值数目  
IplImage * pAvgTrainImg       = 0; // 训练人脸数据的平均值  
IplImage ** eigenVectArr      = 0; // 投影矩阵,也即主特征向量  
CvMat * eigenValMat           = 0; // 特征值  
CvMat * projectedTrainFaceMat = 0; // 训练图像的投影  
char *filename[5]={“face1.jpg”,”face2.jpg”,”face3.jpg”,”face4.jpg”,”face5.jpg”};  
  
static CvMemStorage* storage = 0;    
static CvHaarClassifierCascade* cascade = 0;    
int j=0;//统计记录的人脸数  
char a[512]={0};  
int a1,a2,a3,a4;  
time_t timeBegin, timeEnd;      
  int timeuse;    
函数原型  
void learn();  
void doPCA();  
void storeTrainingData();  
int  loadTrainingData(CvMat ** pTrainPersonNumMat);  
int  findNearestNeighbor(float * projectedTestFace);  
int  loadFaceImgArray(char * filename);  
void printUsage();  
int detect_and_draw( IplImage* image );    
int recognize(IplImage *faceimg);  
  
//主函数,主要包括学习和识别两个阶段,需要运行两次,通过命令行传入的参数区分  
int main( int argc, char** argv )  
{  
    CvCapture* capture = 0;    
    IplImage *frame, *frame_copy = 0;    
    int optlen = strlen(“–cascade=”);    
    char *cascade_name = “H://opencv-2.4.3//opencv//data//haarcascades//haarcascade_frontalface_alt2.xml”;    
        //opencv装好后haarcascade_frontalface_alt2.xml的路径,    
       //也可以把这个文件拷到你的工程文件夹下然后不用写路径名cascade_name= “haarcascade_frontalface_alt2.xml”;      
       //或者cascade_name =”C:\\Program Files\\OpenCV\\data\\haarcascades\\haarcascade_frontalface_alt2.xml”    
    cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 );    
     
    if( !cascade )    
    {    
        fprintf( stderr, “ERROR: Could not load classifier cascade\n” );    
        fprintf( stderr,    
        “Usage: facedetect –cascade=\”<cascade_path>\” [filename|camera_index]\n” );    
        return -1;    
    }    
    storage = cvCreateMemStorage(0);    
     capture = cvCreateCameraCapture(-1);    
    cvNamedWindow( “result”, 1 );    
     
    if( capture )    
    {     timeBegin = time(NULL);      
          learn();  
        for(;;)    
        {   timeEnd = time(NULL);      
    timeuse=timeEnd – timeBegin;//计算经过的时间,统计人数  
            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 );//如果图像的起点不在左上角,而在左下角时,进行X轴对称    
     
            detect_and_draw( frame_copy );  //检测并且识别  
            
            if( cvWaitKey( 10 ) >= 0 )    
                break;    
        }    
     
        cvReleaseImage( &frame_copy );    
        cvReleaseCapture( &capture );    
    }    
    else    
    {    
        printf(“Cannot read from CAM”);    
        return -1;    
    }    
     
    cvDestroyWindow(“result”);    
     
    return 0;    
}    
  
//学习阶段代码  
void learn()  
{  
    int i, offset;  
  
    //加载训练图像集  
    nTrainFaces = loadFaceImgArray(“train.txt”);  
    if( nTrainFaces < 2 )  
    {  
        fprintf(stderr,  
            “Need 2 or more training faces\n”  
            “Input file contains only %d\n”, nTrainFaces);  
          
        return;  
    }  
  
    // 进行主成分分析  
    doPCA();  
  
    //将训练图集投影到子空间中  
    projectedTrainFaceMat = cvCreateMat( nTrainFaces, nEigens, CV_32FC1 );  
    offset = projectedTrainFaceMat->step / sizeof(float);  
    for(i=0; i<nTrainFaces; i++)  
    {  
        //int offset = i * nEigens;  
        cvEigenDecomposite(  
            faceImgArr[i],  
            nEigens,  
            eigenVectArr,  
            0, 0,  
            pAvgTrainImg,  
            //projectedTrainFaceMat->data.fl + i*nEigens);  
            projectedTrainFaceMat->data.fl + i*offset);  
    }  
  
    //将训练阶段得到的特征值,投影矩阵等数据存为.xml文件,以备测试时使用  
    storeTrainingData();  
}  
  
  
//加载保存过的训练结果  
int loadTrainingData(CvMat ** pTrainPersonNumMat)  
{  
    CvFileStorage * fileStorage;  
    int i;  
  
      
    fileStorage = cvOpenFileStorage( “facedata.xml”, 0, CV_STORAGE_READ );  
    if( !fileStorage )  
    {  
        fprintf(stderr, “Can’t open facedata.xml\n”);  
        return 0;  
    }  
  
    nEigens = cvReadIntByName(fileStorage, 0, “nEigens”, 0);  
    nTrainFaces = cvReadIntByName(fileStorage, 0, “nTrainFaces”, 0);  
    *pTrainPersonNumMat = (CvMat *)cvReadByName(fileStorage, 0, “trainPersonNumMat”, 0);  
    eigenValMat  = (CvMat *)cvReadByName(fileStorage, 0, “eigenValMat”, 0);  
    projectedTrainFaceMat = (CvMat *)cvReadByName(fileStorage, 0, “projectedTrainFaceMat”, 0);  
    pAvgTrainImg = (IplImage *)cvReadByName(fileStorage, 0, “avgTrainImg”, 0);  
    eigenVectArr = (IplImage **)cvAlloc(nTrainFaces*sizeof(IplImage *));  
    for(i=0; i<nEigens; i++)  
    {  
        char varname[200];  
        sprintf( varname, “eigenVect_%d”, i );  
        eigenVectArr[i] = (IplImage *)cvReadByName(fileStorage, 0, varname, 0);  
    }  
  
      
    cvReleaseFileStorage( &fileStorage );  
  
    return 1;  
}  
  
//存储训练结果  
void storeTrainingData()  
{  
    CvFileStorage * fileStorage;  
    int i;  
    fileStorage = cvOpenFileStorage( “facedata.xml”, 0, CV_STORAGE_WRITE );  
  
    //存储特征值,投影矩阵,平均矩阵等训练结果  
    cvWriteInt( fileStorage, “nEigens”, nEigens );  
    cvWriteInt( fileStorage, “nTrainFaces”, nTrainFaces );  
    cvWrite(fileStorage, “trainPersonNumMat”, personNumTruthMat, cvAttrList(0,0));  
    cvWrite(fileStorage, “eigenValMat”, eigenValMat, cvAttrList(0,0));  
    cvWrite(fileStorage, “projectedTrainFaceMat”, projectedTrainFaceMat, cvAttrList(0,0));  
    cvWrite(fileStorage, “avgTrainImg”, pAvgTrainImg, cvAttrList(0,0));  
    for(i=0; i<nEigens; i++)  
    {  
        char varname[200];  
        sprintf( varname, “eigenVect_%d”, i );  
        cvWrite(fileStorage, varname, eigenVectArr[i], cvAttrList(0,0));  
    }  
    cvReleaseFileStorage( &fileStorage );  
}  
  
//寻找最接近的图像  
int findNearestNeighbor(float * projectedTestFace)  
{  
  
    double leastDistSq = DBL_MAX;       //定义最小距离,并初始化为无穷大  
    int i, iTrain, iNearest = 0;  
  
    for(iTrain=0; iTrain<nTrainFaces; iTrain++)  
    {  
        double distSq=0;  
  
        for(i=0; i<nEigens; i++)  
        {  
            float d_i =  
                projectedTestFace[i] –  
                projectedTrainFaceMat->data.fl[iTrain*nEigens + i];  
        distSq += d_i*d_i / eigenValMat->data.fl[i];  // Mahalanobis算法计算的距离,差的距离的平方除以平均脸的特征值  
        //  distSq += d_i*d_i; // Euclidean算法计算的距离  
        }  
  
        if(distSq < leastDistSq)  
        {  
            leastDistSq = distSq;  
            iNearest = iTrain;  
        }  
    }  
    //printf(“leastdistsq==%f”,leastDistSq);  
    return iNearest;  
}  
  
  
  
//主成分分析  
void doPCA()  
{  
    int i;  
    CvTermCriteria calcLimit;  
    CvSize faceImgSize;  
  
    // 自己设置主特征值个数  
    nEigens = nTrainFaces-1;  
  
    //分配特征向量存储空间  
    faceImgSize.width  = faceImgArr[0]->width;  
    faceImgSize.height = faceImgArr[0]->height;  
    eigenVectArr = (IplImage**)cvAlloc(sizeof(IplImage*) * nEigens);    //分配个数为住特征值个数  
    for(i=0; i<nEigens; i++)  
        eigenVectArr[i] = cvCreateImage(faceImgSize, IPL_DEPTH_32F, 1);  
  
    //分配主特征值存储空间  
    eigenValMat = cvCreateMat( 1, nEigens, CV_32FC1 );  
  
    // 分配平均图像存储空间  
    pAvgTrainImg = cvCreateImage(faceImgSize, IPL_DEPTH_32F, 1);  
  
    // 设定PCA分析结束条件  
    calcLimit = cvTermCriteria( CV_TERMCRIT_ITER, nEigens, 1);//最大迭代次数为nEigens  
  
    // 计算平均图像,特征值,特征向量  
    cvCalcEigenObjects(  
        nTrainFaces,  
        (void*)faceImgArr,  
        (void*)eigenVectArr,  
        CV_EIGOBJ_NO_CALLBACK,  
        0,  
        0,  
        &calcLimit,  
        pAvgTrainImg,  
        eigenValMat->data.fl//存储求得的eigenvalue  
        );  
  
    cvNormalize(eigenValMat, eigenValMat, 1, 0, CV_L1, 0);  
}  
  
  
  
//加载txt文件的列举的图像  
int loadFaceImgArray(char * filename)  
{  
    FILE * imgListFile = 0;  
    char imgFilename[512];  
    int iFace, nFaces=0;  
  
  
    if( !(imgListFile = fopen(filename, “r”)) )  
    {  
        fprintf(stderr, “Can\’t open file %s\n”, filename);  
        return 0;  
    }  
  
    // 统计人脸数  
    while( fgets(imgFilename, 512, imgListFile) ) ++nFaces;//char *fgets(char *buf, int bufsize, FILE *stream);从文件结构体指针stream中读取数据,每次读取一行。读取的数据保存在buf指向的字符数组中,每次最多读取bufsize-1个字符(第bufsize个字符赋’\0’),如果文件中的该行,不足bufsize个字符,则读完该行就结束。如果函数读取成功,则返回指针buf,失败则返回NULL。  
    rewind(imgListFile);//将文件内部的位置指针重新指向一个流(数据流/文件)的开头  
  
    // 分配人脸图像存储空间和人脸ID号存储空间  
    faceImgArr        = (IplImage **)cvAlloc( nFaces*sizeof(IplImage *) );  
    personNumTruthMat = cvCreateMat( 1, nFaces, CV_32SC1 );//CvMat* cvCreateMat( int rows, int cols, int type );  
  
    for(iFace=0; iFace<nFaces; iFace++)  
    {  
        // 从文件中读取序号和人脸名称  
        fscanf(imgListFile,  
            “%d %s”, personNumTruthMat->data.i+iFace, imgFilename);// fscanf(FILE *stream, char *format,[argument…])功 能: 从一个流中执行格式化输入,fscanf遇到空格和换行时结束  
  
        // 加载人脸图像  
        faceImgArr[iFace] = cvLoadImage(imgFilename, CV_LOAD_IMAGE_GRAYSCALE);  
  
        if( !faceImgArr[iFace] )  
        {  
            fprintf(stderr, “Can\’t load image from %s\n”, imgFilename);  
            return 0;  
        }  
    }  
  
    fclose(imgListFile);  
  
    return nFaces;  
}  
  
  
  
//  
void printUsage()  
{  
    printf(“Usage: eigenface <command>\n”,  
        ”  Valid commands are\n”  
        ”    train\n”  
        ”    test\n”);  
}  
  
int detect_and_draw( IplImage* img )    
{    
 CvFont font;  
 cvInitFont( &font, CV_FONT_VECTOR0,1, 1, 0, 1, 8);  
    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,personnum=0;    
     
    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.) );    
         IplImage* temp_img=cvCreateImage(cvSize(92,112),8,1);    
        for( i = 0; i < (faces ? faces->total : 0); i++ )    
        {    
            CvRect* r = (CvRect*)cvGetSeqElem( faces, i );    
            
            IplImage *dst=cvCreateImage(cvSize(r->width,r->height),8,1);//cvsize只能选取r->width,r->height不能再后面*scale或+100    
          CvPoint p1;    
          p1.x=cvRound((r->x)*scale);    
          p1.y=cvRound((r->y)*scale);    
          CvPoint p2;    
          p2.x=cvRound((r->x+r->width)*scale);    
          p2.y=cvRound((r->y+r->height)*scale);    
            cvRectangle(img,p1,p2,colors[i%8],3,8,0);    
            cvSetImageROI(small_img,*r);    
            cvCopy(small_img,dst);    
            cvResize(dst,temp_img);    
        cvEqualizeHist( temp_img, temp_img );    
             cvResetImageROI(small_img);       
            cvSaveImage(filename[i],temp_img);    
              cvReleaseImage(&dst);    
              //开始识别temp_img  
            
              personnum=recognize(temp_img);  
              if(personnum==1)  
               cvPutText(img, “Yanming” , cvPoint(20, 20), &font, CV_RGB(255,255,255));//将正确识别的人的姓名显示在屏幕上  
                 
        }    
    }    
     
    cvShowImage( “result”, img );    
    cvReleaseImage( &gray );    
    cvReleaseImage( &small_img );    
 return -1;  
}    
  
int recognize(IplImage *faceimg)  
{  
    int i, nTestFaces  = 0;         // 测试人脸数  
    CvMat * trainPersonNumMat = 0;  // 训练阶段的人脸数  
    float * projectedTestFace = 0;  
    // 加载保存在.xml文件中的训练结果  
    if( !loadTrainingData( &trainPersonNumMat ) ) return -3;  
  
    projectedTestFace = (float *)cvAlloc( nEigens*sizeof(float) );  
      
    int iNearest, nearest;  
  
        //将测试图像投影到子空间中  
        cvEigenDecomposite(  
            faceimg,  
            nEigens,  
            eigenVectArr,  
            0, 0,  
            pAvgTrainImg,  
            projectedTestFace);  
        //cvNormalize(projectedTestFace, projectedTestFace, 1, 0, CV_L1, 0);  
        iNearest = findNearestNeighbor(projectedTestFace);  
        nearest  = trainPersonNumMat->data.i[iNearest];  
        printf(“nearest = %d”, nearest);  
        if(timeuse<=10)  
        {  
              
        if((nearest==1)|(nearest==11)|(nearest==111))//可以更改train.txt中训练图片的编号,这里将侧脸,仰脸,正脸都归为一起  
            a1++;  
        if(nearest==2)  
            a2++;  
        if(nearest==3)  
            a3++;  
        if(nearest==4)  
            a4++;  
          
                  
        if(a1>7)//如果10s中识别的次数为6则认定为a1  
        {  
        printf(“yanming\n”);  
        return 1;  
        }  
        if(a2>6)  
        {printf(“others\n”);}  
        if(a3>6)  
        {printf(“ma\n”);}  
        if(a4>6)  
        {printf(“ba\n”);}  
        }  
        else  
            {  
                timeBegin=time(NULL);  
                a1=0;  
                a2=0;  
                a3=0;  
                a4=0;  
                return 0;  
            }  
    return -1;  
}  

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/134463.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号