本篇介紹圖像處理與模式識別中最熱門的一個領域——人臉檢測(人臉識別)。人臉檢測可以說是學術界的寵兒,在不少EI,SCI高級別論文都能看到它的身影。甚至很多高校學生的畢業設計都會涉及到人臉檢測。當然人臉檢測的巨大實用價值也讓很多公司紛紛關注,很多公司都擁有這方面的專利或是開發商業產品出售。
????在OpenCV中,人臉檢測也是其熱門應用之一。在OpenCV的特征檢測專題就詳細介紹了人臉檢測的原理——通過Haar特征來識別是否為人臉。Haar特征檢測原理與Haar特征分類器的訓練放到下一篇《【OpenCV入門指南】第十四篇? Haartraining》來講,本篇主要介紹如何在OpenCV中使用Haar特征分類器來對圖像中的人臉進行檢測和識別。下面將分成五步來詳細示范如何在OpenCV中進行人臉識別:
??? 一.人臉的Haar特征分類器是什么
??? 二.在哪找人臉的Haar特征分類器
??? 三.怎么用人臉的Haar特征分類器
??? 四.人臉識別示例代碼
??? 五.人臉識別程序運行結果
一.人臉的Haar特征分類器是什么
人臉的Haar特征分類器就是一個XML文件,該文件中會描述人臉的Haar特征值。當然Haar特征的用途可不止可以用來描述人臉這一種,用來描述眼睛,嘴唇或是其它物體也是可以的。
二.在哪找人臉的Haar特征分類器
OpenCV有已經自帶了人臉的Haar特征分類器。OpenCV安裝目錄中的\data\ haarcascades目錄下的haarcascade_frontalface_alt.xml與haarcascade_frontalface_alt2.xml都是用來檢測人臉的Haar分類器。這個haarcascades目錄下還有人的全身,眼睛,嘴唇的Haar分類器。讀者可以仿照本方的例子來試驗下效果看看。
三.怎么用人臉的Haar特征分類器
使用人臉的Haar特征分類器非常之簡單,直接使用cvHaarDetectObjects。下面來看看這個函數的介紹:
函數功能:檢測圖像中的目錄
函數原型:
CVAPI(CvSeq*)?cvHaarDetectObjects(
? const?CvArr*?image,
? CvHaarClassifierCascade*?cascade,
? CvMemStorage*?storage,
? double?scale_factor?CV_DEFAULT(1.1),
? int?min_neighbors?CV_DEFAULT(3),
? int?flags?CV_DEFAULT(0),
? CvSize?min_size?CV_DEFAULT(cvSize(0,0)),
? CvSize?max_size?CV_DEFAULT(cvSize(0,0))
);
函數說明:
第一個參數表示輸入圖像,盡量使用灰度圖以加快檢測速度。
第二個參數表示Haar特征分類器,可以用cvLoad()函數來從磁盤中加載xml文件作為Haar特征分類器。
第三個參數為CvMemStorage類型,大家應該很熟悉這個CvMemStorage類型了,《OpenCV入門指南》中很多文章都介紹過了。
第四個參數表示在前后兩次相繼的掃描中,搜索窗口的比例系數。默認為1.1即每次搜索窗口依次擴大10%
第五個參數表示構成檢測目標的相鄰矩形的最小個數(默認為3個)。如果組成檢測目標的小矩形的個數和小于?min_neighbors - 1?都會被排除。如果min_neighbors?為?0,?則函數不做任何操作就返回所有的被檢候選矩形框,這種設定值一般用在用戶自定義對檢測結果的組合程序上。
第六個參數要么使用默認值,要么使用CV_HAAR_DO_CANNY_PRUNING,如果設置為CV_HAAR_DO_CANNY_PRUNING,那么函數將會使用Canny邊緣檢測來排除邊緣過多或過少的區域,因此這些區域通常不會是人臉所在區域。
第七個,第八個參數表示檢測窗口的最小值和最大值,一般設置為默認即可。
函數返回值:
函數將返回CvSeq對象,該對象包含一系列CvRect表示檢測到的人臉矩形。
四.人臉識別示例代碼
下面給出一個完整的示例代碼,代碼中的GetTickCount可以參閱《Windows?各種計時函數總結》,cvEqualizeHist可以參閱《【OpenCV入門指南】第八篇灰度直方圖》。


// FaceDetect.cpp : 定義控制臺應用程序的入口點。 // 本文配套博客文章地址: http://blog.csdn.net/morewindows/article/details/8426318 #include "stdafx.h"#include <iostream> #include <opencv2/core/core.hpp> //cvGetSize cvCreateImage #include <opencv2/highgui/highgui.hpp> #include <opencv2/opencv.hpp> //cvResize cvInitMatHeader cvGetMinMaxHistValue cvCvtColor #include <opencv2/imgproc/imgproc.hpp>#include <Windows.h> //DWORD GetTickCount() #ifdef _DEBUG #pragma comment(lib, "opencv_core244d") #pragma comment(lib, "opencv_highgui244d") #pragma comment(lib, "opencv_imgproc244d") //cvResize #pragma comment(lib, "opencv_objdetect244d") //cvHaarDetectObjects #else #pragma comment(lib, "opencv_core244") #pragma comment(lib, "opencv_highgui244") #pragma comment(lib, "opencv_imgproc244") //cvResize #pragma comment(lib, "opencv_objdetect244") //cvHaarDetectObjects #endifusing namespace std; int main() { // 加載Haar特征檢測分類器 // haarcascade_frontalface_alt.xml系OpenCV自帶的分類器 下面是我機器上的文件路徑 const char *pstrCascadeFileName = "G:\\Software\\openCV\\opencv\\data\\haarcascades\\haarcascade_frontalface_alt.xml"; CvHaarClassifierCascade *pHaarCascade = NULL; pHaarCascade = (CvHaarClassifierCascade*)cvLoad(pstrCascadeFileName); // 載入圖像 const char *pstrImageName = "./images/linzhiling.jpg"; //const char *pstrImageName = "./images/liuyifei.jpg"; //const char *pstrImageName = "./images/unknown.jpg"; IplImage *pSrcImage = cvLoadImage(pstrImageName, CV_LOAD_IMAGE_UNCHANGED); IplImage *pGrayImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1); cvCvtColor(pSrcImage, pGrayImage, CV_BGR2GRAY); // 人臉識別與標記 if (pHaarCascade != NULL) { CvScalar FaceCirclecolors[] = { {{0, 0, 255}}, {{0, 128, 255}}, {{0, 255, 255}}, {{0, 255, 0}}, {{255, 128, 0}}, {{255, 255, 0}}, {{255, 0, 0}}, {{255, 0, 255}} }; CvMemStorage *pcvMStorage = cvCreateMemStorage(0); cvClearMemStorage(pcvMStorage); // 識別 DWORD dwTimeBegin, dwTimeEnd; dwTimeBegin = GetTickCount(); //函數將返回CvSeq對象,該對象包含一系列CvRect表示檢測到的人臉矩形//第一個參數表示輸入圖像,盡量使用灰度圖以加快檢測速度//第二個參數表示Haar特征分類器,可以用cvLoad()函數來從磁盤中加載xml文件作為Haar特征分類器//第三個參數為CvMemStorage類型//第四個參數表示在前后兩次相繼的掃描中,搜索窗口的比例系數。默認為1.1即每次搜索窗口依次擴大10%//第五個參數表示構成檢測目標的相鄰矩形的最小個數(默認為3個)。如果組成檢測目標的小矩形的個數和小于 min_neighbors - 1 都會被排除。//如果min_neighbors 為 0, 則函數不做任何操作就返回所有的被檢候選矩形框,這種設定值一般用在用戶自定義對檢測結果的組合程序上//第六個參數要么使用默認值,要么使用CV_HAAR_DO_CANNY_PRUNING,如果設置為CV_HAAR_DO_CANNY_PRUNING,那么函數將會使用Canny邊緣檢測//來排除邊緣過多或過少的區域,因此這些區域通常不會是人臉所在區域//第七個,第八個參數表示檢測窗口的最小值和最大值,一般設置為默認即可CvSeq *pcvSeqFaces = cvHaarDetectObjects(pGrayImage, pHaarCascade, pcvMStorage); dwTimeEnd = GetTickCount(); printf("人臉個數: %d 識別用時: %d ms\n", pcvSeqFaces->total, dwTimeEnd - dwTimeBegin); // 標記 for(int i = 0; i <pcvSeqFaces->total; i++) { CvRect* r = (CvRect*)cvGetSeqElem(pcvSeqFaces, i); //用圓形畫出臉部部分 CvPoint center; int radius; center.x = cvRound((r->x + r->width * 0.5)); center.y = cvRound((r->y + r->height * 0.5)); radius = cvRound((r->width + r->height) * 0.25); cvCircle(pSrcImage, center, radius, FaceCirclecolors[i % 8], 2); //用矩形畫出臉部部分/*CvPoint startPoint,endPoint;startPoint.x = cvRound(r->x);startPoint.y = cvRound(r->y);endPoint.x = cvRound(r->x + r->width);endPoint.y = cvRound(r->x + r->height);cvRectangle(pSrcImage,startPoint,endPoint,FaceCirclecolors[i % 8]);*/} cvReleaseMemStorage(&pcvMStorage); } const char *pstrWindowsTitle = "人臉識別"; cvNamedWindow(pstrWindowsTitle, CV_WINDOW_AUTOSIZE); cvShowImage(pstrWindowsTitle, pSrcImage); cvWaitKey(0); cvDestroyWindow(pstrWindowsTitle); cvReleaseImage(&pSrcImage); cvReleaseImage(&pGrayImage); return 0; }
五.人臉識別程序運行結果
運行結果一(單人正面):
這張圖的干擾太少,換張干擾大點的圖來試試。
?
運行結果二:
?
運行結果三(多人):
?
本文轉自:http://blog.csdn.net/morewindows/article/details/8426318