计算机视觉
图像处理

opencv 人脸识别总结

本文实现基于eigenface的人脸检测与识别。给定一个图像数据库,进行以下步骤:
进行人脸检测,将检测出的人脸存入数据库2
对数据库2进行人脸建模
在测试集上进行recognition
 Opencv 人脸识别 (一)训练样本的处理
本篇实现第一步:
进行人脸检测,将检测出的人脸存入数据库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
#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 BeginBrowseFilenames(const char *filespec);

protected:
    bool BrowseDir(const char *dir,const char *filespec);
    vector 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;
}

vectorCBrowseDir:: 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 CBrowseDir::GetDirFilenames(const char *dir,const char *filespec)
{
    _chdir(dir);
    vectorfilename_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++]!='');
                strcat(filename,fileinfo.name); //filename[st]='';
                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
#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>  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;
    }
    vectorfile_vec = statdir.BeginBrowseFilenames("*.*");
    int i;
    for (i=0;idepth,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 "<file_vec = statdir.BeginBrowseFilenames("*.*");
    int i,s = file_vec.size();
    for (i=0;i>  read_img(const string& dir)
{
    CStatDir statdir;
    pair pfi;
    vector> Vp;
    if (!statdir.SetInitDir(dir.c_str()))
    {
        cout<<"Direct "<file_vec = statdir.BeginBrowseFilenames("*.*");
    int i,s = file_vec.size();
    for (i=0;i 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 msn", 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;idepth,transimg->nChannels);
        CutImg(transimg,Rvec[id],res);

        return res;
    }
    return NULL;
}

3. 主函数   //Detect.cpp

#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 picturet 2: from cameran"); //     scanf("%d",&mode);     char** pics = (char**) malloc(sizeof*pics);     /************************************************************************/     /*                                  detect face and save                                    */     /************************************************************************/     int i,j;     cout<<"detect and save..."<> imgs=read_img(cur_dir);
        for(j=0;j

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


opencv
人脸识别 (二)训练和识别
上 一篇中我们对训练数据做了一些预处理,检测出人脸并保存在piccolorx文件夹下(x=1,2,3,...类别号),本文做训练和识别。为了识 别,首先将人脸训练数据 转为灰度、对齐、归一化,再放入分类器(EigenFaceRecognizer),最后用训练出的model进行predict。
-----------------------------------------
环境:vs2010+opencv 2.4.6.0
特征:eigenface
Input:一个人脸数据库,15个人,每人20个样本(左右)。
Output:人脸检测,并识别出每张检测到的人脸。
-----------------------------------------
1. 为训练数据预处理( 转为灰度、对齐、归一化 )
转为灰度和对齐是后面做训练时EigenFaceRecognizer的要求;
归一化是防止光照带来的影响
在上一篇的 2.2 Prehelper.cpp文件中加入函数
void resizeandtogray(char* dir,int k, vector<Mat> &images, vector<int> &labels,
vector<Mat> &testimages, vector<int> &testlabels);
 void resizeandtogray(char* dir,int K, vector &images, vector &labels,
    vector &testimages, vector &testlabels)
{
    IplImage* standard = cvLoadImage("D:\privacy\picture\photo\2.jpg",CV_LOAD_IMAGE_GRAYSCALE);
    string cur_dir;
    char id[5];
    int i,j;
    for(int i=1; i<=K; i++)     {         cur_dir = dir;         cur_dir.append("gray\");             _itoa(i,id,10);         cur_dir.append(id);         const char* dd = cur_dir.c_str();         CStatDir statdir;         if (!statdir.SetInitDir(dd))         {             puts("Dir not exist");             return;         }         cout<<"Processing samples in Class "<file_vec = statdir.BeginBrowseFilenames("*.*");
        for (j=0;j
并在main中调用:   int main( )
{
    CvCapture* capture = 0;
    Mat frame, frameCopy, image;
    string inputName;    
    int mode;

    char dir[256] = "D:\Courses\CV\Face_recognition\pic\";
    //preprocess_trainingdata(dir,K); //face_detection and extract to file
    vector images,testimages;
    vector labels,testlabels;
    resizeandtogray(dir,K,images,labels,testimages,testlabels); //togray, normalize and resize
    
    system("pause");
    return 0;
}

2. 训练
有了vector<Mat> images,testimages; vector<int> labels,testlabels; 可以开始训练了,我们采用EigenFaceRecognizer建模。
在Prehelper.cpp中加入函数
Ptr<FaceRecognizer> Recognition(vector<Mat> images, vector<int> labels,vector<Mat> testimages, vector<int> testlabels);
  Ptr Recognition(vector images, vector labels,
    vector testimages, vector testlabels)
{
    Ptr model = createEigenFaceRecognizer(10);//10 Principal components
    cout<<"train"<train(images,labels);
    int i,acc=0,predict_l;
    for (i=0;ipredict(testimages[i]);
        if(predict_l != testlabels[i])
        {
            cout<<"An error in recognition: sample "<
Recognization()输出分错的样本和正确率,最后返回建模结果Ptr<FaceRecognizer> model
主函数改为:

最终结果:一个错分样本,正确率93.3%

转载注明来源:CV视觉网 » opencv 人脸识别总结

分享到:更多 ()
扫描二维码,给作者 打赏
pay_weixinpay_weixin

请选择你看完该文章的感受:

3不错 0超赞 0无聊 0扯淡 0不解 0路过

评论 抢沙发

评论前必须登录!