opencv 人脸识别 (一)训练样本的处理


本文实现基于eigenface的人脸检测与识别。给定一个图像数据库,进行以下步骤:

  • 进行人脸检测,将检测出的人脸存入数据库2
  • 对数据库2进行人脸建模
  • 在测试集上进行recognition
本篇实现第一步:
  • 进行人脸检测,将检测出的人脸存入数据库2

环境:vs2010+opencv 2.4.6.0

特征:LBP

Input:一个人脸数据库,15个人,每人20个样本(左右)。

Output:人脸检测,并识别出每张检测到的人脸。

===============================

本文完成第一步,数据预处理:自动检测所有文件夹中每个sample中的人脸,作为训练数据。

Input:一个color文件夹,每个文件夹中有1~N这N个子文件夹,每个子文件夹内有n张包括第n类人的照片,如图。

最终结果:

核心:face detection(detectAndDraw)

辅助:截图并保存部分图片(CutImg),文件夹内图片遍历(read_img),图片转换成相同大小(normalizeone)

括号内分别是函数名,下面分别给出代码及说明。

1. 遍历文件夹:CBrowseDir类和CStatDir类(具体见这篇),三个文件如下:

1.1 BrowseDir.h

#pragma once
#include "direct.h" #include "string.h" #include "io.h" #include "stdio.h" #include #include using namespace std; class CBrowseDir { protected:  char m_szInitDir[_MAX_PATH]; public:  CBrowseDir();  bool SetInitDir(const char *dir);  bool BeginBrowse(const char *filespec);  vector<char*> BeginBrowseFilenames(const char *filespec); protected:  bool BrowseDir(const char *dir,const char *filespec);  vector<char*> GetDirFilenames(const char *dir,const char *filespec);  virtual bool ProcessFile(const char *filename);  virtual void ProcessDir(const char *currentdir,const char *parentdir); };

1.2 BrowseDir.cpp

#include "BrowseDir.h"
#include "direct.h" #include "string.h" #include "io.h" #include "stdio.h" #include #include using namespace std; CBrowseDir::CBrowseDir() {  getcwd(m_szInitDir,_MAX_PATH);  int len=strlen(m_szInitDir);  if (m_szInitDir[len-1] != '\\')   strcat(m_szInitDir,"\\"); } bool CBrowseDir::SetInitDir(const char *dir) {  if (_fullpath(m_szInitDir,dir,_MAX_PATH) == NULL)   return false;  if (_chdir(m_szInitDir) != 0)   return false;  int len=strlen(m_szInitDir);  if (m_szInitDir[len-1] != '\\')   strcat(m_szInitDir,"\\");  return true; } vector<char*>CBrowseDir:: BeginBrowseFilenames(const char *filespec) {  ProcessDir(m_szInitDir,NULL);  return GetDirFilenames(m_szInitDir,filespec); } bool CBrowseDir::BeginBrowse(const char *filespec) {  ProcessDir(m_szInitDir,NULL);  return BrowseDir(m_szInitDir,filespec); } bool CBrowseDir::BrowseDir(const char *dir,const char *filespec) {  _chdir(dir);  long hFile;  _finddata_t fileinfo;  if ((hFile=_findfirst(filespec,&fileinfo)) != -1)  {   do   {    if (!(fileinfo.attrib & _A_SUBDIR))    {     char filename[_MAX_PATH];     strcpy(filename,dir);     strcat(filename,fileinfo.name);     cout << filename << endl;     if (!ProcessFile(filename))      return false;    }   } while (_findnext(hFile,&fileinfo) == 0);   _findclose(hFile);  }  _chdir(dir);  if ((hFile=_findfirst("*.*",&fileinfo)) != -1)  {   do   {    if ((fileinfo.attrib & _A_SUBDIR))    {     if (strcmp(fileinfo.name,".") != 0 && strcmp      (fileinfo.name,"..") != 0)     {      char subdir[_MAX_PATH];      strcpy(subdir,dir);      strcat(subdir,fileinfo.name);      strcat(subdir,"\\");      ProcessDir(subdir,dir);      if (!BrowseDir(subdir,filespec))       return false;     }    }   } while (_findnext(hFile,&fileinfo) == 0);   _findclose(hFile);  }  return true; } vector<char*> CBrowseDir::GetDirFilenames(const char *dir,const char *filespec) {  _chdir(dir);  vector<char*>filename_vec;  filename_vec.clear();  long hFile;  _finddata_t fileinfo;  if ((hFile=_findfirst(filespec,&fileinfo)) != -1)  {   do   {    if (!(fileinfo.attrib & _A_SUBDIR))    {     char *filename = new char[_MAX_PATH];     strcpy(filename,dir);     //int st = 0; while (dir[st++]!='\0');     strcat(filename,fileinfo.name); //filename[st]='\0';     filename_vec.push_back(filename);    }   } while (_findnext(hFile,&fileinfo) == 0);   _findclose(hFile);  }  _chdir(dir);  if ((hFile=_findfirst("*.*",&fileinfo)) != -1)  {   do   {    if ((fileinfo.attrib & _A_SUBDIR))    {     if (strcmp(fileinfo.name,".") != 0 && strcmp      (fileinfo.name,"..") != 0)     {      char subdir[_MAX_PATH];      strcpy(subdir,dir);      strcat(subdir,fileinfo.name);      strcat(subdir,"\\");      ProcessDir(subdir,dir);      return GetDirFilenames(subdir,filespec);     }    }   } while (_findnext(hFile,&fileinfo) == 0);   _findclose(hFile);  }  return filename_vec; } bool CBrowseDir::ProcessFile(const char *filename) {  return true; } void CBrowseDir::ProcessDir(const char  *currentdir,const char *parentdir) { }

1.3 StatDir.h

#pragma once #include "browsedir.h" class CStatDir:public CBrowseDir { protected:  int m_nFileCount; //保存文件个数  int m_nSubdirCount; //保存子目录个数 public:  CStatDir()  {   m_nFileCount=m_nSubdirCount=0;  }  int GetFileCount()  {   return m_nFileCount;  }  int GetSubdirCount()  {   return m_nSubdirCount-1;  } protected:  virtual bool ProcessFile(const char *filename)  {   m_nFileCount++;   return CBrowseDir::ProcessFile(filename);  }  virtual void ProcessDir   (const char *currentdir,const char *parentdir)  {   m_nSubdirCount++;   CBrowseDir::ProcessDir(currentdir,parentdir);  } };

2. 辅助函数Prehelper.h, Prehelper.cpp:负责返回文件夹内所有图片(read_img),检测人脸(detectAndDraw并可以在原图中画出),截图(CutImg),提取(DetectandExtract)

2.1 Prehelper.h

//preprocessing helper
//@ Author : Rachel-Zhang #include "opencv2/core/core.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/contrib/contrib.hpp" #include #include #include using namespace cv; using namespace std; void normalizeone(const char* dir,IplImage* standard); void CutImg(IplImage* src, CvRect rect,IplImage* res); vector detectAndDraw( Mat& img, CascadeClassifier& cascade,  CascadeClassifier& nestedCascade,  double scale, bool tryflip,bool draw ); IplImage* DetectandExtract(Mat& img, CascadeClassifier& cascade,  CascadeClassifier& nestedCascade,  double scale, bool tryflip); int read_img(const string& dir, vector &images); vector<pair<char*,mat>> read_img(const string& dir);

2.2 Prehelper.cpp

#include "Prehelper.h"
#include "BrowseDir.h" #include "StatDir.h" #include #include #include using namespace cv; void normalizeone(const char* dir,IplImage* standard) {  CStatDir statdir;  if (!statdir.SetInitDir(dir))  {   puts("Dir not exist");   return;  }  vector<char*>file_vec = statdir.BeginBrowseFilenames("*.*");  int i;  for (i=0;i<file_vec.size();i++) {="" iplimage*="" cur_img="cvLoadImage(file_vec[i],CV_LOAD_IMAGE_GRAYSCALE);" iplimage*cur_gray="cvCreateImage(cvGetSize(cur_img),cur_img-">depth,1);   cvResize(cur_img,standard,CV_INTER_AREA);   //cvCvtColor(standard,cur_gray,CV_RGB2GRAY);   // cvNamedWindow("cur_img",CV_WINDOW_AUTOSIZE);   // cvNamedWindow("standard",CV_WINDOW_AUTOSIZE);   // cvShowImage("cur_img",cur_img);   // cvShowImage("standard",standard);   // cvWaitKey();   cvSaveImage(file_vec[i],cur_img);  } } void CutImg(IplImage* src, CvRect rect,IplImage* res) {  CvSize imgsize;  imgsize.height = rect.height;  imgsize.width = rect.width;  cvSetImageROI(src,rect);  cvCopy(src,res);  cvResetImageROI(res); } int read_img(const string& dir, vector &images) {  CStatDir statdir;  if (!statdir.SetInitDir(dir.c_str()))  {   cout<<"Direct "<<dir<<" not="" exist!"<<endl;="" return="" 0;="" }="" int="" cls_id="dir[dir.length()-1]-'0';" vector<char*="">file_vec = statdir.BeginBrowseFilenames("*.*");  int i,s = file_vec.size();  for (i=0;i<s;i++) {="" mat="" graymat="imread(file_vec[i],0);" graymat.reshape(1,1);="" flatten="" to="" row="" images.push_back(graymat);="" }="" return="" s;="" vector<pair<char*,mat="">> read_img(const string& dir) {  CStatDir statdir;  pair<char*,mat> pfi;  vector<pair<char*,mat>> Vp;  if (!statdir.SetInitDir(dir.c_str()))  {   cout<<"Direct "<<dir<<" not="" exist!"<<endl;="" return="" vp;="" }="" int="" cls_id="dir[dir.length()-1]-'0';" vector<char*="">file_vec = statdir.BeginBrowseFilenames("*.*");  int i,s = file_vec.size();  for (i=0;i<s;i++) {="" pfi.first="file_vec[i];" pfi.second="imread(file_vec[i]);" vp.push_back(pfi);="" }="" return="" vp;="" vector<rect=""> detectAndDraw( Mat& img, CascadeClassifier& cascade,  CascadeClassifier& nestedCascade,  double scale, bool tryflip, bool draw ) {  int i = 0;  double t = 0;  vector faces, faces2;  const static Scalar colors[] = { CV_RGB(0,0,255),   CV_RGB(0,128,255),   CV_RGB(0,255,255),   CV_RGB(0,255,0),   CV_RGB(255,128,0),   CV_RGB(255,255,0),   CV_RGB(255,0,0),   CV_RGB(255,0,255)} ;  Mat gray, smallImg( cvRound (img.rows/scale), cvRound(img.cols/scale), CV_8UC1 );  cvtColor( img, gray, CV_BGR2GRAY );  resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR );  equalizeHist( smallImg, smallImg );  t = (double)cvGetTickCount();  cascade.detectMultiScale( smallImg, faces,   1.1, 2, 0   |CV_HAAR_FIND_BIGGEST_OBJECT   //|CV_HAAR_DO_ROUGH_SEARCH   //|CV_HAAR_SCALE_IMAGE   ,   Size(30, 30) );  if( tryflip )  {   flip(smallImg, smallImg, 1);   cascade.detectMultiScale( smallImg, faces2,    1.1, 2, 0    |CV_HAAR_FIND_BIGGEST_OBJECT    //|CV_HAAR_DO_ROUGH_SEARCH    //|CV_HAAR_SCALE_IMAGE    ,    Size(30, 30) );   for( vector::const_iterator r = faces2.begin(); r != faces2.end(); r++ )   {    faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height));   }  }  t = (double)cvGetTickCount() - t;  printf( "detection time = %g ms\n", t/((double)cvGetTickFrequency()*1000.) );  if(draw)  {   for( vector::const_iterator r = faces.begin(); r != faces.end(); r++, i++ )   {    Mat smallImgROI;    vector nestedObjects;    Point center;    Scalar color = colors[i%8];    int radius;    double aspect_ratio = (double)r->width/r->height;    rectangle( img, cvPoint(cvRound(r->x*scale), cvRound(r->y*scale)),     cvPoint(cvRound((r->x + r->width-1)*scale), cvRound((r->y + r->height-1)*scale)),     color, 3, 8, 0);    if( nestedCascade.empty() )     continue;    smallImgROI = smallImg(*r);    nestedCascade.detectMultiScale( smallImgROI, nestedObjects,     1.1, 2, 0     |CV_HAAR_FIND_BIGGEST_OBJECT     //|CV_HAAR_DO_ROUGH_SEARCH     //|CV_HAAR_DO_CANNY_PRUNING     //|CV_HAAR_SCALE_IMAGE     ,     Size(30, 30) );    //draw eyes    // for( vector::const_iterator nr = nestedObjects.begin(); nr != nestedObjects.end(); nr++ )    // {    // center.x = cvRound((r->x + nr->x + nr->width*0.5)*scale);    // center.y = cvRound((r->y + nr->y + nr->height*0.5)*scale);    // radius = cvRound((nr->width + nr->height)*0.25*scale);    // circle( img, center, radius, color, 3, 8, 0 );    // }   }   cv::imshow( "result", img );  }  return faces; } IplImage* DetectandExtract(Mat& img, CascadeClassifier& cascade,  CascadeClassifier& nestedCascade,  double scale, bool tryflip) {  vector Rvec = detectAndDraw(img,cascade,nestedCascade,scale,tryflip,0);  int i,maxxsize=0,id=-1,area;  for (i=0;i<rvec.size();i++) {="" area="Rvec[i].width*Rvec[i].height;" if(maxxsize<area)="" maxxsize="area;" id="i;" }="" iplimage*="" transimg="cvCloneImage(&(IplImage)img);" if(id!="-1)" cvsize="" imgsize;="" imgsize.height="Rvec[id].height;" imgsize.width="Rvec[id].width;" res="cvCreateImage(imgsize,transimg-">depth,transimg->nChannels);   CutImg(transimg,Rvec[id],res);   return res;  }  return NULL; }

3. 主函数

//Detect.cpp
//Preprocessing - Detect, Cut and Save //@Author : Rachel-Zhang #include "opencv2/objdetect/objdetect.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include #include #include #include #include "BrowseDir.h" #include "StatDir.h" #include "Prehelper.h" using namespace std; using namespace cv; #define CAM 2 #define PHO 1 #define K 5 string cascadeName = "E:/software/opencv2.4.6.0/data/haarcascades/haarcascade_frontalface_alt.xml"; string nestedCascadeName = "E:/software/opencv2.4.6.0/data/haarcascades/haarcascade_eye_tree_eyeglasses.xml"; int main( ) {  CvCapture* capture = 0;  Mat frame, frameCopy, image;  string inputName;  bool tryflip = false;  int mode;  CascadeClassifier cascade, nestedCascade;  double scale = 1.0;  if( !cascade.load( cascadeName ) ||!nestedCascade.load( nestedCascadeName))  {   cerr << "ERROR: Could not load classifier cascade or nestedCascade" << endl;//若出现该问题请去检查cascadeName,可能是opencv版本路径问题   return -1;  } // printf("select the mode of detection: \n1: from picture\t 2: from camera\n"); // scanf("%d",&mode);  char** pics = (char**) malloc(sizeof*pics);  /************************************************************************/  /* detect face and save */  /************************************************************************/  int i,j;  cout<<"detect and save..."<<endl; const="" char="" dir[256]="D:\\Face_recognition\\pic\\" ;="" string="" cur_dir;="" id[5];="" for(i="1;" i<="K;" i++)="" {="" cur_dir="dir;" _itoa(i,id,10);="" cur_dir.append("color\\");="" cur_dir.append(id);="" vector<pair<char*,mat="">> imgs=read_img(cur_dir);   for(j=0;j<imgs.size();j++) {="" iplimage*="" res="DetectandExtract(imgs[j].second,cascade,nestedCascade,scale,tryflip);" if(res)="" cvsaveimage(imgs[j].first,res);="" }="" return="" 0;="" }<="" pre="">

正确的输出就是一系列人脸检测时间,且原文件夹内的图片变成了检测出的人脸(如上面结果图所示)。

关于Computer Vision更多的学习资料将继续更新,敬请关注本博客和新浪微博Rachel Zhang


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM