【OpenCV入门指南】第十三篇 人脸检测
此为转载,原文链接:http://blog.csdn.net/morewindows/article/details/8426318
本篇介绍图像处理与模式识别中最热门的一个领域——人脸检测(人脸识别)。人脸检测可以说是学术界的宠儿,在不少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(
constCvArr* image,
CvHaarClassifierCascade*cascade,
CvMemStorage*storage,
doublescale_factor CV_DEFAULT(1.1),
intmin_neighbors CV_DEFAULT(3),
intflags CV_DEFAULT(0),
CvSizemin_size CV_DEFAULT(cvSize(0,0)),
CvSizemax_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>
<div class="dp-highlighter bg_cpp"><div class="bar"><div class="tools"><strong>[cpp]</strong> <a target=_blank title="view plain" class="ViewSource" href="http://blog.csdn.net/morewindows/article/details/8426318#">view plain</a><a target=_blank title="copy" class="CopyToClipboard" href="http://blog.csdn.net/morewindows/article/details/8426318#">copy</a><a target=_blank title="print" class="PrintSource" href="http://blog.csdn.net/morewindows/article/details/8426318#">print</a><a target=_blank title="?" class="About" href="http://blog.csdn.net/morewindows/article/details/8426318#">?</a></div></div><ol class="dp-cpp"><li class="alt"><span><span class="comment">// 编译前请配置好VS2008的编译环境</span><span> </span></span></li><li><span><span class="comment">// 详见《【OpenCV入门指南】第一篇 安装OpenCV》</span><span> </span></span></li><li class="alt"><span><span class="comment">// 地址: http://blog.csdn.net/morewindows/article/details/8225783</span><span> </span></span></li><li><span> </span></li><li class="alt"><span><span class="comment">// 本文配套博客文章地址:</span><span> </span></span></li><li><span><span class="comment">// http://blog.csdn.net/morewindows/article/details/8426318</span><span> </span></span></li><li class="alt"><span> </span></li><li><span><span class="comment">// Haar特征检测 - 人脸识别</span><span> </span></span></li><li class="alt"><span><span class="comment">//By MoreWindows (http://blog.csdn.net/MoreWindows)</span><span> </span></span></li><li><span><span class="preprocessor">#include <opencv2/opencv.hpp></span><span> </span></span></li><li class="alt"><span><span class="preprocessor">#include <cstdio></span><span> </span></span></li><li><span><span class="preprocessor">#include <cstdlib></span><span> </span></span></li><li class="alt"><span><span class="preprocessor">#include <Windows.h></span><span> </span></span></li><li><span><span class="keyword">using</span><span> </span><span class="keyword">namespace</span><span> std; </span></span></li><li class="alt"><span><span class="datatypes">int</span><span> main() </span></span></li><li><span>{ </span></li><li class="alt"><span> <span class="comment">// 加载Haar特征检测分类器</span><span> </span></span></li><li><span> <span class="comment">// haarcascade_frontalface_alt.xml系OpenCV自带的分类器 下面是我机器上的文件路径</span><span> </span></span></li><li class="alt"><span> <span class="keyword">const</span><span> </span><span class="datatypes">char</span><span> *pstrCascadeFileName = </span><span class="string">"G:\\OpenCV\\opencv\\data\\haarcascades\\haarcascade_frontalface_alt.xml"</span><span>; </span></span></li><li><span> CvHaarClassifierCascade *pHaarCascade = NULL; </span></li><li class="alt"><span> pHaarCascade = (CvHaarClassifierCascade*)cvLoad(pstrCascadeFileName); </span></li><li><span> </span></li><li class="alt"><span> <span class="comment">// 载入图像</span><span> </span></span></li><li><span> <span class="keyword">const</span><span> </span><span class="datatypes">char</span><span> *pstrImageName = </span><span class="string">"101.jpg"</span><span>; </span></span></li><li class="alt"><span> IplImage *pSrcImage = cvLoadImage(pstrImageName, CV_LOAD_IMAGE_UNCHANGED); </span></li><li><span> </span></li><li class="alt"><span> IplImage *pGrayImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1); </span></li><li><span> cvCvtColor(pSrcImage, pGrayImage, CV_BGR2GRAY); </span></li><li class="alt"><span> </span></li><li><span> <span class="comment">// 人脸识别与标记</span><span> </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (pHaarCascade != NULL) </span></span></li><li><span> { </span></li><li class="alt"><span> CvScalar FaceCirclecolors[] = </span></li><li><span> { </span></li><li class="alt"><span> {{0, 0, 255}}, </span></li><li><span> {{0, 128, 255}}, </span></li><li class="alt"><span> {{0, 255, 255}}, </span></li><li><span> {{0, 255, 0}}, </span></li><li class="alt"><span> {{255, 128, 0}}, </span></li><li><span> {{255, 255, 0}}, </span></li><li class="alt"><span> {{255, 0, 0}}, </span></li><li><span> {{255, 0, 255}} </span></li><li class="alt"><span> }; </span></li><li><span> </span></li><li class="alt"><span> CvMemStorage *pcvMStorage = cvCreateMemStorage(0); </span></li><li><span> cvClearMemStorage(pcvMStorage); </span></li><li class="alt"><span> <span class="comment">// 识别</span><span> </span></span></li><li><span> <span class="datatypes">DWORD</span><span> dwTimeBegin, dwTimeEnd; </span></span></li><li class="alt"><span> dwTimeBegin = GetTickCount(); </span></li><li><span> CvSeq *pcvSeqFaces = cvHaarDetectObjects(pGrayImage, pHaarCascade, pcvMStorage); </span></li><li class="alt"><span> dwTimeEnd = GetTickCount(); </span></li><li><span> </span></li><li class="alt"><span> printf(<span class="string">"人脸个数: %d 识别用时: %d ms\n"</span><span>, pcvSeqFaces->total, dwTimeEnd - dwTimeBegin); </span></span></li><li><span> </span></li><li class="alt"><span> <span class="comment">// 标记</span><span> </span></span></li><li><span> <span class="keyword">for</span><span>(</span><span class="datatypes">int</span><span> i = 0; i <pcvSeqFaces->total; i++) </span></span></li><li class="alt"><span> { </span></li><li><span> CvRect* r = (CvRect*)cvGetSeqElem(pcvSeqFaces, i); </span></li><li class="alt"><span> CvPoint center; </span></li><li><span> <span class="datatypes">int</span><span> radius; </span></span></li><li class="alt"><span> center.x = cvRound((r->x + r->width * 0.5)); </span></li><li><span> center.y = cvRound((r->y + r->height * 0.5)); </span></li><li class="alt"><span> radius = cvRound((r->width + r->height) * 0.25); </span></li><li><span> cvCircle(pSrcImage, center, radius, FaceCirclecolors[i % 8], 2); </span></li><li class="alt"><span> } </span></li><li><span> cvReleaseMemStorage(&pcvMStorage); </span></li><li class="alt"><span> } </span></li><li><span> </span></li><li class="alt"><span> <span class="keyword">const</span><span> </span><span class="datatypes">char</span><span> *pstrWindowsTitle = </span><span class="string">"人脸识别 (http://blog.csdn.net/MoreWindows)"</span><span>; </span></span></li><li><span> cvNamedWindow(pstrWindowsTitle, CV_WINDOW_AUTOSIZE); </span></li><li class="alt"><span> cvShowImage(pstrWindowsTitle, pSrcImage); </span></li><li><span> </span></li><li class="alt"><span> cvWaitKey(0); </span></li><li><span> </span></li><li class="alt"><span> cvDestroyWindow(pstrWindowsTitle); </span></li><li><span> cvReleaseImage(&pSrcImage); </span></li><li class="alt"><span> cvReleaseImage(&pGrayImage); </span></li><li><span> <span class="keyword">return</span><span> 0; </span></span></li><li class="alt"><span>} </span></li></ol></div><pre class="cpp" style="display: none;" 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;
}
五.人脸识别程序运行结果
运行结果一(单人正面):
这张图的干扰太少,换张干扰大点的图来试试。
运行结果二(单人侧面):
呵呵,左边那个人眼睛被挡住了,因此普通的人脸检测肯定难以识别的。
运行结果三(多人):
效果还不错。当然商业级产品的准确度,性能,效率肯定会比OpenCV自带的分类器高的多。
下一篇《【OpenCV入门指南】第十四篇 Haartraining》将介绍如何训练Haar特征分类器并简要介绍Haar特征检测的原理。欢迎继续浏览。
下面列出OpenCV入门指南系列目录,以方便大家查看:
11.《【OpenCV入门指南】第十一篇鼠标绘图》
12.《【OpenCV入门指南】第十二篇无法运行OpenCV程序?》
13.《【OpenCV入门指南】第十三篇人脸识别》
14.《【OpenCV入门指南】第十四篇 Haartraining》即将发布