本篇介紹圖像處理與模式識別中最熱門的一個領域——人臉檢測(人臉識別)。人臉檢測可以說是學術界的寵兒,在不少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入門指南】第八篇灰度直方圖》。
<pre class="cpp" name="code">// 編譯前請配置好VS2008的編譯環境
// 詳見《【OpenCV入門指南】第一篇 安裝OpenCV》
// 地址: http://blog.csdn.net/morewindows/article/details/8225783
// 本文配套博客文章地址:
// http://blog.csdn.net/morewindows/article/details/8426318
// Haar特徵檢測 - 人臉識別
//By MoreWindows (http://blog.csdn.net/MoreWindows)
#include <opencv2/opencv.hpp>
#include <cstdio>
#include <cstdlib>
#include <Windows.h>
using namespace std;
int main()
{
// 加載Haar特徵檢測分類器
// haarcascade_frontalface_alt.xml系OpenCV自帶的分類器 下面是我機器上的文件路徑
const char *pstrCascadeFileName = "G:\\OpenCV\\opencv\\data\\haarcascades\\haarcascade_frontalface_alt.xml";
CvHaarClassifierCascade *pHaarCascade = NULL;
pHaarCascade = (CvHaarClassifierCascade*)cvLoad(pstrCascadeFileName);
// 載入圖像
const char *pstrImageName = "101.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 *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);
}
cvReleaseMemStorage(&pcvMStorage);
}
const char *pstrWindowsTitle = "人臉識別 (http://blog.csdn.net/MoreWindows)";
cvNamedWindow(pstrWindowsTitle, CV_WINDOW_AUTOSIZE);
cvShowImage(pstrWindowsTitle, pSrcImage);
cvWaitKey(0);
cvDestroyWindow(pstrWindowsTitle);
cvReleaseImage(&pSrcImage);
cvReleaseImage(&pGrayImage);
return 0;
}</pre><br>
五.人臉識別程序運行結果
運行結果一(單人正面):
這張圖的干擾太少,換張干擾大點的圖來試試。
運行結果二(單人側面):
呵呵,左邊那個人眼睛被擋住了,因此普通的人臉檢測肯定難以識別的。
運行結果三(多人):
效果還不錯。當然商業級產品的準確度,性能,效率肯定會比OpenCV自帶的分類器高的多。