本文实现基于eigenface的人脸检测与识别。给定一个图像数据库,进行以下步骤:
- 进行人脸检测,将检测出的人脸存入数据库2
- 对数据库2进行人脸建模
- 在测试集上进行recognition
- 进行人脸检测,将检测出的人脸存入数据库2
环境:vs2010+opencv 2.4.6.0
特征:eigenface
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 <vector>
- #include <iostream>
- 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 <vector>
- #include <iostream>
- 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 <cv.h>
- #include <vector>
- #include <utility>
- using namespace cv;
- using namespace std;
- void normalizeone(const char* dir,IplImage* standard);
- void CutImg(IplImage* src, CvRect rect,IplImage* res);
- vector<Rect> 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<Mat> &images);
- vector<pair<char*,Mat>> read_img(const string& dir);
2.2 Prehelper.cpp
- #include "Prehelper.h"
- #include "BrowseDir.h"
- #include "StatDir.h"
- #include <opencv2/core/core.hpp>
- #include <opencv2/highgui/highgui.hpp>
- #include <cv.h>
- 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<Mat> &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 one 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<Rect> 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<Rect>::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<Rect>::const_iterator r = faces.begin(); r != faces.end(); r++, i++ )
- {
- Mat smallImgROI;
- vector<Rect> 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<Rect>::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<Rect> 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;
- IplImage* 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 <cctype>
- #include <iostream>
- #include <iterator>
- #include <stdio.h>
- #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;
- char 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;
- }
正确的输出就是一系列人脸检测时间,且原文件夹内的图片变成了检测出的人脸(如上面结果图所示)。
文章所用代码打包链接:http://download.csdn.net/detail/abcjennifer/7047853
from: http://blog.csdn.net/abcjennifer/article/details/20396869