本文实现基于eigenface的人脸检测与识别。给定一个图像数据库,进行以下步骤:
- 进行人脸检测,将检测出的人脸存入数据库2
- 对数据库2进行人脸建模
- 在测试集上进行recognition
环境:vs2010+opencv 2.4.6.0
特征:eigenface
Input:一个人脸数据库,15个人,每人20个样本(左右)。
Output:人脸检测,并识别出每张检测到的人脸。
===============================
本文完成第一步,数据预处理:自动检测所有文件夹中每个sample中的人脸,作为训练数据。
Input:一个color文件夹,每个文件夹中有1~N这N个子文件夹,每个子文件夹内有n张包括第n类人的照片,如图。
![opencv 人脸识别 (一)训练样本的处理_第1张图片](http://img.e-com-net.com/image/info5/37d1f2edbfce46f19aebbe6ec6c09524.jpg)
最终结果:
![opencv 人脸识别 (一)训练样本的处理_第2张图片](http://img.e-com-net.com/image/info5/22da568b8527495b8340feb72b557429.jpg)
核心: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);
-
- strcat(filename,fileinfo.name);
- 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
-
-
-
- #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);
-
- cvResize(cur_img,standard,CV_INTER_AREA);
-
-
-
-
-
-
- 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);
-
- 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
-
-
- ,
- Size(30, 30) );
- if( tryflip )
- {
- flip(smallImg, smallImg, 1);
- cascade.detectMultiScale( smallImg, faces2,
- 1.1, 2, 0
- |CV_HAAR_FIND_BIGGEST_OBJECT
-
-
- ,
- 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
-
-
-
- ,
- Size(30, 30) );
-
-
-
-
-
-
-
-
- }
- 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. 主函数
-
-
-
-
- #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;
- return -1;
- }
-
-
-
- char** pics = (char**) malloc(sizeof*pics);
-
-
-
-
- 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;
- }
正确的输出就是一系列人脸检测时间,且原文件夹内的图片变成了检测出的人脸(如上面结果图所示)。
![opencv 人脸识别 (一)训练样本的处理_第3张图片](http://img.e-com-net.com/image/info5/0770f8b2d1f34df18698e5e043d78005.jpg)
文章所用代码打包链接:http://download.csdn.net/detail/abcjennifer/7047853