OpenCV人脸检测+识别

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lzcggg/article/details/9950419


/*

特别说明:
1.笔者使用的opencv 2.4.3,其他版本未测试


2.本程序涉及使用人脸图库,路径是c:\face\s[x]\[y].jpg 其中x是从1开始,最大值由文中的limit设定,同理于y


3.其中程序有几个按键操作,纯属娱乐,其中s是保存人脸,q是切换保存位置(人脸库/程序牡蛎),a是初始化人脸库路径,相当于每按一次切一个人

4.默认阈值为5W

5.有很多东西没有标注,比如tellwho 是一个输入ID,返回人名的函数,只是一个DEMO,没多写

6.视频标注人脸只标注我自己~哈哈

*/

#include "cv.h"
#include "highgui.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#include <time.h>
#include <ctype.h>

//begin 识别用
#include "cxcore.h"
#include <iostream>
//end 识别用
 
#ifdef _EiC
#define WIN32
#endif


//begin识别用
#define CV_COMP_CORREL 0
#define CV_COMP_CHISQR 1
#define CV_COMP_INTERSECT 2
#define CV_COMP_BHATTACHARYYA 3


int HistogramBins = 256;
float HistogramRange1[2]={0,255};
float *HistogramRange[1]={&HistogramRange1[0]};
//end识别用

 
static CvMemStorage* storage = 0;
static CvHaarClassifierCascade* cascade = 0;
 
void detect_and_draw( IplImage* image );

 
const char* cascade_name =
    "haarcascade_frontalface_alt.xml";
/*    "haarcascade_profileface.xml";*/


int isOwen=0,isSave=0;
char who[20][20]={"1\\","2\\","3\\","4\\","5\\","6\\"};   //c:\\face\\s1\\//
char s[11][3]={"1","2","3","4","5","6","7","8","9","10"};      //c:\\face\\s1\\1


int main( int argc, char** argv )
{
    CvCapture* capture = 0;
    IplImage *frame, *frame_copy = 0;
 
 //IplImage* image;//87
    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 = "C:\\OpenCV\\data\\haarcascades\\haarcascade_frontalface_alt2.xml";
        //opencv装好后haarcascade_frontalface_alt2.xml的路径,
        //也可以把这个文件拷到你的工程文件夹下然后不用写路径名cascade_name= "haarcascade_frontalface_alt2.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=\"<cascade_path>\" [filename|camera_index]\n" );
        return -1;
    }
    storage = cvCreateMemStorage(0);
 
    if( !input_name || (isdigit(input_name[0]) && input_name[1] == '\0') )
        capture = cvCaptureFromCAM( !input_name ? 0 : input_name[0] - '0' ); //cvcam类,用于
    else
 {
  //image=cvLoadImage( input_name,1 );//87
  //if(!image)//image=0//87
     capture = cvCaptureFromAVI( input_name ); 

 }
          //获取捕捉源
 
    cvNamedWindow( "result", 1 );//0可以改大小//1默认大小//4支持OPENGL
 
    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;
        }
  //cvWaitKey(0);         //for exit?//87
        cvReleaseImage( &frame_copy );
        cvReleaseCapture( &capture );
    }
    else
    {
        const char* filename = input_name ? input_name : (char*)"lena.jpg"; //needless in 87
        IplImage* image = cvLoadImage( filename, 1 );      //needless in 87
 
        if( image )
        {
            detect_and_draw( image );
           // cvWaitKey(0);//88
            cvReleaseImage( &image );
        }
        else
        {
            /* assume it is a text file containing the
               list of the image filenames to be processed - one per line */
            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);  //88
                        cvReleaseImage( &image );
                    }
                }
                fclose(f);
            }
        }
 
    }
 
    cvDestroyWindow("result");
 
    return 0;
}
 

void tellwho(int id)
{
 char *ans="";
 switch(id)
 {
 case 0:{ans="陆zc(LIGHT)";break;}
 case 1:{ans="陆zc(DARK)";break;}
 case 2:{ans="白人男3";break;}
 case 3:{ans="白人男4";break;}
 case 4:{ans="白人男5";break;}
 case 5:{ans="白人女6";break;}
 case 6:{ans="亚洲女1";break;}
 default:ans="ioi";
 } 
 printf("%s",ans);
}

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 = 5.0;//图像大小-直接影响速率
    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,     //检测人脸方法cvHaarDetectObjects
                                            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,Lp,Rp;
            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 );
   */
   //以矩形标出人脸
   Lp.x=cvRound((r->x)*scale);//87
   Lp.y=cvRound((r->y)*scale);
   Rp.x=cvRound((r->x + r->width)*scale);
   Rp.y=cvRound((r->y + r->width)*scale);
   CvRect Region;
   Region.x=r->x*scale;
   Region.y=r->y*scale;
   Region.height=r->height*scale;
   Region.width=r->width*scale;
   Region=cvRect(Region.x,Region.y,Region.width,Region.height);//87
   cvRectangle( img, Lp,Rp, colors[i%8], 3, 8, 0 );//在视频框中画方框

   

   /**///以下程序为提取&保存人脸图片(未做其他处理)
   //begin
   static int nFileNameCount=0,nFolder=0;
   static char Path2Save[20]="c:\\face\\s",oPath[20]="c:\\face\\s",tPath[20]="c:\\face\\s";

   int key;
   key=cvWaitKey(5);
   
   if(key=='s')
   {
    printf("Save\n");
    cvSetImageROI(img, Region);
    CvRect Temp_region= cvGetImageROI(img);
    IplImage* Image1=cvCreateImage(cvSize(Temp_region.width,Temp_region.height),img->depth,3);
    cvCopy(img,Image1,0);
    IplImage* OutImage=cvCreateImage(cvSize(96,96),8,3);//(cvSize(96,96),8,3);////保存的图片大小250*250 depth=8 channel=3
    cvResize(Image1,OutImage);

    char strCount[10]="";
    nFileNameCount++;//存N张
    //nFileNameCount=1;//存1张
    itoa(nFileNameCount,strCount,10);
    IplImage* image= cvCreateImage( cvGetSize(OutImage), 8, 1 ); //创建灰度图
    cvCvtColor(OutImage, image, CV_BGR2GRAY); //色彩空间转换//OpenCV1函数
    //cvtColor(OutImage,image,CV_BGR2GRAY);//opencv2
    //cvZero( image );
    //cvSaveImage(strcat(strCount,".pgm"),image);//pgm格式 //image=灰度图//OutImage=彩图
    if(isSave==0)
    {
     cvSaveImage(strcat(strCount,".jpg"),image);//jpg格式
     printf("Saved %d.jpg!\n",nFileNameCount);
    }
    else {
     strcat(Path2Save,strCount);////"c:\\face\\s2\\1"
     cvSaveImage(strcat(Path2Save,".jpg"),image);//
     printf("Save %s\n",Path2Save);
     strcpy(Path2Save,tPath);
    }
    //
    
    cvResetImageROI(img);
    cvReleaseImage(&Image1);
    cvReleaseImage(&OutImage);
      
   }//if(key=='s')//end
   else if(key=='a')//isSave=1
   {
    if(isSave==1){
    
     strcpy(Path2Save,oPath);
     isSave=1;     
     nFileNameCount=0;
     nFolder+=1;//1-> 2 3 4 5...     
     strcat(Path2Save,who[nFolder]);//"c:\\face\\s2\\"     
     strcpy(tPath,Path2Save);
     printf("存入人脸库路径%s\n",Path2Save);

    
    }
    else printf("先按Q\n");
   }
   /**/
   else if(key=='q'){
    if(isSave==1){isSave=0;printf("普通截图\n");}
    else {isSave=1;printf("从s2开始存储");nFolder=0;printf(",按A设置文件夹\n");}
   }
   //else if(key=='f')
   {
    //printf("识别中\n");
    //目标图片
    cvSetImageROI(img, Region);
    CvRect Temp_region= cvGetImageROI(img);
    IplImage* Image0=cvCreateImage(cvSize(Temp_region.width,Temp_region.height),img->depth,3);
    cvCopy(img,Image0,0);
    IplImage* OutImage=cvCreateImage(cvSize(96,96),8,3);//(cvSize(96,96),8,3);////保存的图片大小250*250 depth=8 channel=3
    cvResize(Image0,OutImage);
    
    IplImage* Image1= cvCreateImage( cvGetSize(OutImage), 8, 1 ); //创建灰度图
    cvCvtColor(OutImage, Image1, CV_BGR2GRAY); //色彩空间转换//OpenCV1函数

    CvHistogram *Histogram1=cvCreateHist(1,&HistogramBins,CV_HIST_ARRAY,HistogramRange);
    cvCalcHist(&Image1,Histogram1,0,0);
    cvNormalizeHist(Histogram1,1);

    //IplImage *Image1=cvLoadImage("C:\\ruita\\2013-8\\openCV_from_2013.8.5\\CVprj01\\CVprj01\\1.jpg",0);//   //("c:\\face\\s1\\10.jpg",0);   //如果没有对象,直接输出为完美匹配
    
    char path[20]="c:\\face\\s";    
    char way[20]="c:\\face\\s";
    double thre = 20.0;//阈值//下面的程序推荐5000以下,其实也不可能用到5000,官方给的更大1.7*10^308
    double res;//对比结果
    double max_ores=50000.0;
    double sum_res=max_ores,avr_res=max_ores;//对比结果总和,对比结果平均值,
    double min_res=max_ores;//对比结果的最小值
    double ores[3]={max_ores,max_ores,max_ores};//保存最小值
    //int resID[3]={999,999,999};
    
    char res_TM[99]={123,234,456};//结果排列数组                         //大小与人脸库有关
    char TM[99][3]={"0","1","2","3","4","5","6","7","8","9","10"};    //组别,用于读取组别,记录最优结果
         
    int limitpeople=5; //对比总人数
    int limitpic=10;  //对比时每人的头像数
    //813printf("阈值=%.2f,总人数=%d,其中每人提供的头像数=%d\n",thre,limitpeople,limitpic);

    for(int readTM=0;readTM<limitpeople;readTM++){//人数//

     //sum_res=0;     //avr_res=0;
     min_res=max_ores;

     for(int readID=0;readID<limitpic;readID++){//每人头像数
   
      strcat(path,who[readTM]);  //c:\\face\\s1\\     //
      strcat(path,s[readID]);   //c:\\face\\s1\\1       
      strcat(path,".jpg");   //c:\\face\\s1\\1.jpg
      IplImage *Image2=cvLoadImage(path,0);
      //printf("\n%s  ",path);   //打印路径
      strcpy(path,way);    //还原
 
      

      CvHistogram *Histogram2=cvCreateHist(1,&HistogramBins,CV_HIST_ARRAY,HistogramRange);
      cvCalcHist(&Image2,Histogram2,0,0);
      cvNormalizeHist(Histogram2,1);
 
      double res=cvCompareHist(Histogram1,Histogram2,CV_COMP_CHISQR);
      //printf("%d= %.3f\n",readTM,res);//卡方

      
      //最小值法
      if(res<min_res){min_res=res;}//如果比记录的最小值还小
      else if(res>thre){min_res=max_ores;break;}//超出阈值,本组不再比较
     }// for readID
     
     //最小值法
     //if(min_res<max_ores)printf("★%d min=%.2f\n",readTM,min_res);
     //else printf("☆%d no match\n",readTM);
     if(min_res<ores[0])//如果本次比记录的结果小,把他放进第一位
     {
      //改变均值队列
      ores[2]=ores[1];
      ores[1]=ores[0];
      ores[0]=min_res;//代替第一位
      //改变结果队列
      res_TM[2]=res_TM[1];
      res_TM[1]=res_TM[0];
      res_TM[0]=readTM;      //printf("0\n");

     }
     else if(min_res<ores[1])
     {
      //改变均值队列
      ores[2]=ores[1];
      ores[1]=min_res;
      //改变结果队列
      res_TM[2]=res_TM[1];
      res_TM[1]=readTM;      //printf("1\n");

     }
     else if(min_res<ores[2])
     {
      //改变均值队列
      ores[2]=min_res;
      //改变结果队列
      res_TM[2]=readTM;      //printf("2\n");

     }

    }//for readTM
    
    
    //玩玩
    


    if(ores[0]==max_ores){
     printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
     printf("在阈值范围内没有最合适的人\n");

    }
    else if(ores[1]==max_ores){
     printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
     //printf("阈值范围内,只有%d(%.2f)最像\n",res_TM[0],ores[0]);
     printf("阈值范围内,只像");printf("(%.2f)",ores[0]);
     tellwho(res_TM[0]);

    }
    else if(ores[2]==max_ores){
     printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
     //printf("最像%d(%.2f),次像%d(%.2f)\n",res_TM[0],ores[0],res_TM[1],ores[1]); 
     printf("阈值范围内只有两个像:最像");
     tellwho(res_TM[0]);printf("(%.2f)",ores[0]);
     printf(",比较像");
     tellwho(res_TM[1]);printf("(%.2f)",ores[1]);

    }
    else {
     printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
     printf("最像");
     tellwho(res_TM[0]);printf("(%.2f)",ores[0]);
     printf(",比较像");
     tellwho(res_TM[1]);printf("(%.2f)",ores[1]);
     printf(",有点像");
     tellwho(res_TM[2]);printf("(%.2f)",ores[2]);


     //printf("最像%d(%.2f),次像%d(%.2f),或像%d(%.2f)\n",++res_TM[0],ores[0],++res_TM[1],ores[1],++res_TM[2],ores[2]);
   }//else 3种情况
   //printf("Finish!\n");

   cvResetImageROI(img);
   cvReleaseImage(&Image0);
   cvReleaseImage(&OutImage);
   if(res_TM[0]==1)
   {//玩玩
    //printf("f\n");
    char text[20] = "zc_LU";
    CvPoint point = cvPoint(Rp.x-250, Rp.y+50);
    CvFont font;
    cvInitFont(&font,CV_FONT_HERSHEY_DUPLEX, 1.0f,1.0f, 1, 2);
    cvPutText(img, text, point, &font,CV_RGB(255, 0, 0) );
   }
   }//else if(key=='f'
   
   
   
        }
    }
 
    cvShowImage( "result", img );
 cvMoveWindow("result",600,0);
    cvReleaseImage( &gray );
    cvReleaseImage( &small_img );
}


 

猜你喜欢

转载自blog.csdn.net/lzcggg/article/details/9950419