歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

OpenCV 人臉識別

本文實現基於eigenface的人臉檢測與識別。給定一個圖像數據庫,進行以下步驟:

進行人臉檢測,將檢測出的人臉存入數據庫2
對數據庫2進行人臉建模
在測試集上進行recognition

本篇實現第一步:
進行人臉檢測,將檢測出的人臉存入數據庫2

環境:vs2010+opencv 2.4.6.0

特征:eigenface

Input:一個人臉數據庫,15個人,每人20個樣本(左右)。

Output:人臉檢測,並識別出每張檢測到的人臉。

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

文章所用代碼打包下載

Linux公社資源站下載:

------------------------------------------分割線------------------------------------------

免費下載地址在 http://linux.linuxidc.com/

用戶名與密碼都是www.linuxidc.com

具體下載目錄在 /2016年資料/6月/18日/OpenCV 人臉識別/

下載方法見 http://www.linuxidc.com/Linux/2013-07/87684.htm

------------------------------------------分割線------------------------------------------

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

本文完成第一步,數據預處理:自動檢測所有文件夾中每個sample中的人臉,作為訓練數據。

Input:一個color文件夾,每個文件夾中有1~N這N個子文件夾,每個子文件夾內有n張包括第n類人的照片,如圖。

最終結果:

核心:face detection(detectAndDraw)

輔助:截圖並保存部分圖片(CutImg),文件夾內圖片遍歷(read_img),圖片轉換成相同大小(normalizeone)

括號內分別是函數名,下面分別給出代碼及說明。

OpenCV官方教程中文版(For Python) PDF  http://www.linuxidc.com/Linux/2015-08/121400.htm

Ubuntu Linux下安裝OpenCV2.4.1所需包 http://www.linuxidc.com/Linux/2012-08/68184.htm

Ubuntu 12.04 安裝 OpenCV2.4.2 http://www.linuxidc.com/Linux/2012-09/70158.htm

CentOS下OpenCV無法讀取視頻文件 http://www.linuxidc.com/Linux/2011-07/39295.htm

Ubuntu 12.04下安裝OpenCV 2.4.5總結 http://www.linuxidc.com/Linux/2013-06/86704.htm

Ubuntu 10.04中安裝OpenCv2.1九步曲 http://www.linuxidc.com/Linux/2010-09/28678.htm

基於QT和OpenCV的人臉識別系統 http://www.linuxidc.com/Linux/2011-11/47806.htm

[翻譯]Ubuntu 14.04, 13.10 下安裝 OpenCV 2.4.9  http://www.linuxidc.com/Linux/2014-12/110045.htm

1. 遍歷文件夾:CBrowseDir類和CStatDir類(具體見這篇 http://www.linuxidc.com/Linux/2016-06/132427.htm),三個文件如下:

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://www.linuxidc.com/Linux/2016-06/132429p2.htm

Copyright © Linux教程網 All Rights Reserved