实时多人面部检测与识别






4.90/5 (350投票s)
使用 C# 和 EmguCV 进行多人面部检测与识别,支持同一场景中的多张人脸以及其他有趣的功能。
引言
面部识别一直是全球许多人致力于解决的问题,这个问题在多个领域和科学领域中出现,尤其是在计算机科学领域。对这项技术非常感兴趣的其他领域包括:机电一体化、机器人学、犯罪学等。在本文中,我将使用 EmguCV 这一跨平台的 .NET OpenCV 图像处理库的封装以及 C# .NET 来研究这个有趣的主题。这些库允许我实时捕获和处理来自捕获设备的图像。本文的主要目标是展示和解释最简单的方法,使用主成分分析(PCA)和特征脸(eigenface)来实现实时多人面部检测和识别,并将其应用于多个领域。
背景
面部识别是一个由复杂算法组成的计算机应用程序,这些算法采用数学和矩阵技术,将图像以光栅模式(数字格式)获取,然后逐像素地进行处理和比较,采用不同的方法以获得更快、更可靠的结果。显然,这些结果取决于用于处理的机器,因为这些算法、函数和例程需要巨大的计算能力。这些是解决现代问题最流行的技术。
技术
传统
一些面部识别算法通过从被摄者面部的图像中提取地标或特征来识别面部。例如,一个算法可能会分析眼睛、鼻子、颧骨和下巴的相对位置、大小和/或形状。然后使用这些特征来搜索具有匹配特征的其他图像。其他算法则对人脸图像库进行归一化,然后压缩面部数据,只保存图像中有助于面部检测的数据。然后将探针图像与面部数据进行比较。最早成功的系统之一是基于模板匹配技术,该技术应用于一组显著的面部特征,提供一种压缩的面部表示。识别算法可以分为两种主要方法:几何方法,它关注区分性特征;或光度方法,这是一种统计方法,将图像提炼成数值,并将数值与模板进行比较以消除差异。流行的识别算法包括基于特征脸的主成分分析、线性判别分析、弹性图匹配(fisherface)、隐马尔可夫模型以及受神经科学启发的动态链接匹配。
摘自 [1]
特征脸(EigenFaces)的示例
摘自 [4]
3-D
一种新出现的趋势,据称可以实现前所未有的准确度,是三维面部识别。该技术使用 3D 传感器来捕获面部形状的信息。然后利用这些信息来识别面部表面的独特特征,如眼窝、鼻子和下巴的轮廓。3D 面部识别的一个优点是它不像其他技术那样受光照变化的影响。它还可以从一系列视角识别面部,包括侧面视图。即使是完美的 3D 匹配技术也可能对表情敏感。为了达到这个目标,特拉维夫大学的一个小组应用了度量几何的工具来将表情视为等距变换。
摘自 [2]
皮肤纹理分析
另一种新兴趋势是利用标准数字或扫描图像中捕获的皮肤视觉细节。这种称为皮肤纹理分析的技术,将一个人皮肤上独特的线条、图案和斑点转化为数学空间。测试表明,通过添加皮肤纹理分析,识别面部的性能可以提高 20% 到 25%。它通常用于安全系统,并且可以与其他生物识别技术(如指纹或虹膜识别系统)进行比较。
摘自 [1]
EmguCV
Emgu CV 是 Intel OpenCV 图像处理库的一个跨平台 .NET 封装。它允许从 .NET 兼容语言(如 C#、VB、VC++、IronPython 等)调用 OpenCV 函数。该封装可以在 Mono 中编译并在 Linux / Mac OS X 上运行。
摘自 [3]
用我自己的话来说,EmguCV 是一个很棒的封装库,它允许我们完成非常有趣且具有挑战性的计算机视觉任务。这个库集让我们能够在这个领域开展无限的精彩项目,EmguCV 拥有许多功能,可以让我们利用 CPU 和 GPU 进行工作,后者可以显著提高性能。
这个很棒的软件项目可以进行
- 光学字符识别(OCR)
- 人脸检测
- 行人检测
- Kinect 项目
- 3D 重建
- SURF 特征检测器……以及许多其他有趣的任务
EmguCV 基础:我如何开始工作?
如果您以前从未接触过这个封装库,想了解如何为项目添加引用或解决问题,可以看看 C_Johnson 写的这篇优秀文章/教程。
另一个关于 emguCV、图像处理和面部识别的精彩博客/网站,其中包含多个入门教程,由 mehwish87 撰写,地址是:
Using the Code
首先,声明所有要使用的变量和重要对象
//Declaration of all variables, vectors and haarcascades
Image<bgr,> currentFrame;
Capture grabber;
HaarCascade face;
HaarCascade eye;
MCvFont font = new MCvFont(FONT.CV_FONT_HERSHEY_TRIPLEX, 0.5d, 0.5d);
Image<gray,> result, TrainedFace = null;
Image<gray,> gray = null;
List<image<gray,>> trainingImages = new List<image<gray,>>();
List<string> labels= new List<string>();
List<string> NamePersons = new List<string>();
int ContTrain, NumLabels, t;
string name, names = null;
然后加载用于面部检测的 `haarcascade`,然后我进行一个小“程序”来加载之前训练的面部和每个图像的标签,这些图像已预先存储。
//Load haarcascades for face detection
face = new HaarCascade("haarcascade_frontalface_alt_tree.xml");
eye = new HaarCascade("haarcascade_eye.xml");
try
{
//Load of previous trained faces and labels for each image
string Labelsinfo =
File.ReadAllText(Application.StartupPath + "/TrainedFaces/TrainedLabels.txt");
string[] Labels = Labelsinfo.Split('%');
NumLabels = Convert.ToInt16(Labels[0]);
ContTrain = NumLabels;
string LoadFaces;
for (int tf = 1; tf < NumLabels+1; tf++)
{
LoadFaces = "face" + tf + ".bmp";
trainingImages.Add(new Image<gray,>
(Application.StartupPath + "/TrainedFaces/" + LoadFaces));
labels.Add(Labels[tf]);
}
}
catch(Exception e)
{
//MessageBox.Show(e.ToString());
MessageBox.Show("Nothing in binary database,
please add at least a face", "Trained faces load",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
初始化捕获设备,以及执行检测和处理每个捕获帧图像的 `FrameGrabber` 事件
grabber = new Capture();
grabber.QueryFrame();
//Initialize the FrameGraber event
Application.Idle += new EventHandler(FrameGrabber);
button1.Enabled = false;
进入 `FrameGrabber` 事件(原型的主要部分),我们使用最重要的函数和对象:`DetectHaarCascade` 和 `EigenObjectRecognizer`,并对每一帧中检测到的面部执行操作。
MCvAvgComp[][] facesDetected = gray.DetectHaarCascade(
face,
1.2,
10,
Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.DO_CANNY_PRUNING,
new Size(20, 20));
//Action for each element detected
foreach (MCvAvgComp f in facesDetected[0])
{
t = t + 1;
result = currentFrame.Copy(f.rect).Convert<gray,>().
Resize(100, 100, Emgu.CV.CvEnum.INTER.CV_INTER_CUBIC);
//draw the face detected in the 0th (gray) channel with blue color
currentFrame.Draw(f.rect, new Bgr(Color.Red), 2);
if (trainingImages.ToArray().Length != 0)
{
//TermCriteria for face recognition with
//numbers of trained images like maxIteration
MCvTermCriteria termCrit = new MCvTermCriteria(ContTrain, 0.001);
//Eigen face recognizer
EigenObjectRecognizer recognizer = new EigenObjectRecognizer(
trainingImages.ToArray(),
labels.ToArray(),
5000,
ref termCrit);
name = recognizer.Recognize(result);
//Draw the label for each face detected and recognized
currentFrame.Draw(name, ref font,
new Point(f.rect.X - 2, f.rect.Y - 2), new Bgr(Color.LightGreen));
}
}
参数
haarObj
:Haar 分类器级联的内部表示。scaleFactor
:在连续扫描之间搜索窗口缩放的因子,例如,1.1 表示窗口增加 10%。minNeighbors
:构成对象的最小邻居矩形数量(减 1)。所有小于 `min_neighbors-1` 个矩形组成的组都被拒绝。如果 `min_neighbors` 为 `0`,则函数根本不进行分组,并返回所有检测到的候选矩形,这在用户想要应用自定义分组程序时可能很有用。flag
:操作模式。目前,唯一可以指定的标志是 `CV_HAAR_DO_CANNY_PRUNING`。如果设置了该标志,则函数使用 Canny 边缘检测器来拒绝一些包含过少或过多边缘的图像区域,从而无法包含要搜索的对象。特定的阈值经过面部检测的调整,在这种情况下,修剪可以加快处理速度。minSize
:最小窗口大小。默认情况下,它设置为分类器训练的样本大小(面部检测约 20x20)。
如何训练原型?
我以最简单的方式完成这部分,原型不断检测面部(每帧),您可以将检测到的面部以相应的标签添加到图像数据库中。训练人脸的图像将显示在 `imageBoxFrameGrabber` 中,然后过程就完成了!
请记住:基于 PCA(主成分分析)的面部识别算法会在检测到的面部与二进制数据库中存储的训练图像之间进行多次比较和匹配。因此,为了提高识别的准确性,您应该添加同一个人在不同角度、位置和光照条件下的几张图像。这种训练使该原型坚固且非常准确。
示例
训练按钮的代码(这执行添加训练面孔和各自的标签)
try
{
//Trained face counter
ContTrain = ContTrain + 1;
//Get a gray frame from capture device
gray = grabber.QueryGrayFrame().Resize
(320, 240, Emgu.CV.CvEnum.INTER.CV_INTER_CUBIC);
//Face Detector
MCvAvgComp[][] facesDetected = gray.DetectHaarCascade(
face,
1.2,
10,
Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.DO_CANNY_PRUNING,
new Size(20, 20));
//Action for each element detected
foreach (MCvAvgComp f in facesDetected[0])
{
TrainedFace = currentFrame.Copy(f.rect).Convert<gray,>();
break;
}
//resize face detected image for force to compare the same size with the
//test image with cubic interpolation type method
TrainedFace = result.Resize(100, 100, Emgu.CV.CvEnum.INTER.CV_INTER_CUBIC);
trainingImages.Add(TrainedFace);
labels.Add(textBox1.Text);
//Show face added in gray scale
imageBox1.Image = TrainedFace;
//Write the number of trained faces in a file text for further load
File.WriteAllText(Application.StartupPath +
"/TrainedFaces/TrainedLabels.txt",
trainingImages.ToArray().Length.ToString() + "%");
//Write the labels of trained faces in a file text for further load
for (int i = 1; i < trainingImages.ToArray().Length + 1; i++)
{
trainingImages.ToArray()[i - 1].Save
(Application.StartupPath + "/TrainedFaces/face" + i + ".bmp");
File.AppendAllText(Application.StartupPath +
"/TrainedFaces/TrainedLabels.txt", labels.ToArray()[i - 1] + "%");
}
MessageBox.Show(textBox1.Text + "´s face detected and added :)",
"Training OK", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch
{
MessageBox.Show("Enable the face detection first",
"Training Fail", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
“先启用面部检测”警告?
要将面部添加到模型,您需要先初始化摄像头和面部识别引擎。您只需按“检测与识别”按钮。
当摄像头在实时图像中显示您的脸时,您可以添加和训练模型。
如何提高识别度?
默认参数(scale_factor=1.1, min_neighbors=3, flags=0
)经过调整,可以在实现准确的同时实现缓慢的对象检测。
另外,您可以修改大小以获得一个较大的值,在代码中修改此设置。
MCvAvgComp[][] facesDetected = gray.DetectHaarCascade(
face,
1.1,
3,
0,
new Size(20, 20));
此外,将第三个参数修改为 **2500** 或 **3000** 而不是 5000,这个修改将使 `EigenObjectRecognizer` 更加严格/准确。
//Eigen face recognizer
EigenObjectRecognizer recognizer = new EigenObjectRecognizer(
trainingImages.ToArray(),
labels.ToArray(),
5000,
ref termCrit);
如何提高较慢 CPU 的性能?
所有图像处理算法都需要大量的计算能力。在这种情况下,CPU 对该软件原型进行的内部处理对于较慢或单核 CPU 来说非常困难。要提高此演示性能的简单方法是修改 `DetectHaarCascade` 方法使用的参数,这些参数允许减少实时摄像头捕获图像的迭代次数、关键部分和比较次数,从而显著提高应用程序性能。
请记住:减小这些参数的值会影响识别算法的效率。
选项一
为了在实时视频图像上实现更快的操作,设置如下:scale_factor=1.2, min_neighbors=2, flags=CV_HAAR_DO_CANNY_PRUNING, min_size=<minimum>
(例如,对于视频会议,图像面积的 1/4 到 1/16)。
此外,您还可以将 `Minsize` 参数修改为一个较大的值。
// DetectHaarCascade Config for optimal performance
MCvAvgComp[][] facesDetected = gray.DetectHaarCascade(
face,
1.2,
2,
Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.DO_CANNY_PRUNING,
new Size(20, 20));
选项二
获取原始捕获图像的“缩略图”或调整大小,以减少 `FrameGrabber` 方法中的处理时间,请修改为较小的尺寸值(原始尺寸为 320x240)。
示例
//Get the current frame form capture device
currentFrame = grabber.QueryFrame().Resize
(260, 200, Emgu.CV.CvEnum.INTER.CV_INTER_CUBIC);
记住在训练按钮中也要做同样的事情。
gray = grabber.QueryGrayFrame().Resize(260, 200, Emgu.CV.CvEnum.INTER.CV_INTER_CUBIC);
原型不会将陌生人显示为未知,为什么?
这是特征脸方法的一个局限性,这不是错误,而是建议使用 LBPH 算法(有优点和缺点),该算法在 EmguCV 2.4.2 及更高版本中可用。
运行/使用此项目而不会出错需要什么?
为避免此类错误
- 首先,下载并解压 `FaceRecPro_Demo.zip`。它包含一些 `OpenCV` 函数使用的“外部”操作系统库(DLL)。在将这些 DLL 复制到 `C:/Windows/System32` 或此项目的 `bin` 文件夹后。
- 然后下载 `EmguCV(C# 的 OpenCV 封装)`,地址为 http://sourceforge.net/projects/emgucv/files/。安装它,然后转到 `C:\Emgu\emgucv-windows-x86 2.2.1.1150\bin` 文件夹并复制:`opencv_calib3d220`、`opencv_contrib220`、`opencv_core220`、`opencv_features2d220`、`opencv_ffmpeg220`、`opencv_flann220`、`opencv_gpu220`、`opencv_highgui220`、`opencv_imgproc220`、`opencv_legacy220`、`opencv_ml220`、`opencv_objdetect220` 和 `opencv_video220` 到 `C:/Windows/System32` 或此项目的 `bin` 文件夹。
请记住,这些 DLL 是 `OpenCV` 库,对于运行任何使用 EgmuCV 的项目都是必需的。
这是运行演示或项目最简单的方法,找到并将这些文件复制到演示文件夹或 bin 文件夹(如果您想“运行”源代码)。
opencv_calib3d220.dll、opencv_contrib220.dll、opencv_core220.dll、opencv_features2d220.dll、opencv_ffmpeg220.dll、opencv_flann220.dll、opencv_gpu220.dll、opencv_highgui220.dll、opencv_imgproc220.dll、opencv_legacy220.dll、opencv_ml220.dll、opencv_objdetect220.dll 和 opencv_video220.dll(来自 EmguCV 下载中的 OpenCV 内容的 DLL),以及 Emgu.CV.dll、Emgu.CV.UI.dll、Emgu.Util.dll、cv110.dll、cvaux110.dll、cvextern.dll、cxcore110.dll、highgui110.dll(来自演示下载 zip 的内容)。
请记住:您可以将这些文件复制到 `Windows/System32/` 文件夹,从而解决您在此类项目以及其他使用 Emgu 或 openCV 的项目中的依赖问题(Emgu.CV.dll、Emgu.CV.UI.dll、Emgu.Util.dll 应始终放在 `bin` 或 `.exe` 文件夹中)或者在此处下载所有准备好的项目(优化版本)和文件。
关注点
我在使用 EmguCV 时遇到了许多关于向量使用的问题,因此我学习了如何使用组件列表作为向量,并且它确实对我的项目非常有效。
我学到了很多关于图像处理、PCA 和特征脸的知识,以及如何优化代码,因为人工智能视觉算法需要大量的资源。
这个项目想法的出现是在看到钢铁侠的场景之后……XD
用本文和 OpenCV 你可以做什么?
类似这样的东西……
关于此主题的书籍
OpenCV 的官方参考书是:《Learning OpenCV: Computer Vision with the OpenCV Library》,O'Reilly 出版(2008)。
还有数百本其他优秀的计算机视觉书籍,并非专门针对 OpenCV。
- 《Computer Vision: A Modern Approach》作者:Forsyth 和 Ponce (2002)
- 《Computer Vision: Algorithms and Applications》作者:Szeliski (2011)
- 《Digital Image Processing》作者:Gonzalez 和 Woods (2001)
- 《The Essential Guide to Image Processing》作者:Bovik (2009)
- 《Computer Vision and Applications: A Guide for Students and Practitioners》作者:Jähne 和 Haußecker (2000)
- HIPR2 图像处理工作表(对许多计算机视觉主题的简单解释)
参考文献
- [1] http://en.wikipedia.org/wiki/Facial_recognition_system
- [2] "Firms point to biometric future" 作者:Dominic Bailey, BBC News, Biometrics 2006 展会
- [3] http://www.emgu.com/wiki/index.php/Main_Page
- [4] http://www.shervinemami.info/faceRecognition.html
许可证
本文和原型仅用于学术目的,未经作者许可,不得用于商业或公开发布。
历史
- 2011-07-11:初始发布
- 2012-01-28:最终发布(优化版本)