人脸检测与人脸识别 - Go语言中文社区

人脸检测与人脸识别


       本篇文章主要介绍了如何使用OpenCV实现人脸检测,训练自己的分类器并进行视频和照片的人脸识别。本文不具体讲解人脸检测和识别的原理,直接使用OpenCV实现。



软件版本

       OpenCV版本:2.4.13.4;VS开发版本:VS2015。



目标分割、检测、识别和跟踪的概念


参考链接 http://blog.csdn.net/mdjxy63/article/details/76009046


目标分割, Target Segmentation,任务是把目标对应的部分分割出来。
目标检测, Target Detection。检测到图片当中的目标的具体位置。
目标识别, Target Recognition。即是在所有的给定数据中,分类出哪一些sample是目标,哪一些不是。这个仅仅做一下分类任务。
目标追踪, Target Tracking。这个任务很重要的第一点是目标定位(Target Locating)。而且这个任务设计到的数据一般具有时间序列(Temporal Data)。常见的情况是首先Target被Identify以后,算法或者系统需要在接下来时序的数据中,快速并高效地对给定目标进行再定位。任务需要区别类似目标,需要避免不要的重复计算,充分利用好时序相关性(Temporal Correlation),并且需要对一些简单的变化Robust,必须旋转、遮盖、缩小放大,Motion Blur之类的线性或者非线性变化。
典型的技术路线是:目标分割 ——>目标检测 ——>目标识别 ——>目标跟踪
如:需要对视频中的小明进行跟踪,处理过程将经历如下过程:
(1)首先,采集第一帧视频图像,因为人脸部的肤色偏黄,因此可以通过颜色特征将人脸与背景分割出来(目标分割);
(2)分割出来后的图像有可能不仅仅包含人脸,可能还有部分环境中颜色也偏黄的物体,此时可以通过一定的形状特征将图像中所有的人脸准确找出来,确定其位置及范围(目标检测);
(3)接下来需将图像中的所有人脸与小明的人脸特征进行对比,找到匹配度最好的,从而确定哪个是小明(目标识别);
(4)之后的每一帧就不需要像第一帧那样在全图中对小明进行检测,而是可以根据小明的运动轨迹建立运动模型,通过模型对下一帧小明的位置进行预测,从而提升跟踪的效率(目标跟踪)


程序实现


(1)数据收集和预处理

       下载att_faces,是ORL人脸数据库,共40个人,每人10张照片分别存于att_facess1-s40文件夹。

       建立face_collection工程,功能是打开摄像头,给自己拍10张照片,存在myfaces文件夹中。
该工程还将10张照片进行人像检测并转化为灰度图保存在att_facess41文件夹,作为第41组训练数据。

       运行create_csv.py文件,读取att_faces文件夹,生成包含图片地址和标签的csv文件,命名为try.txt,并存放在face_training工程下。注意这里分类时并不完全按照文件夹升序的,比如s1是类别0,s10是类别1而不是s2是类别1。因此,自己的照片存于s41文件夹,分到的类别号是35。这个至关重要,决定了人脸识别时的判断条件。


       参考链接 http://blog.csdn.net/xingchenbingbuyu/article/details/51386949


(2)分类器训练
       建立face_training工程,读取此try.txt文件,将自己在内的410张照片进行训练,得到三种分类器MyFaceFisherModel.xml、MyFaceLBPHModel.xml和MyFacePCAModel.xml。


       参考链接 http://blog.csdn.net/xingchenbingbuyu/article/details/51407336


(3)视频识别自己
       建立face_detect_show_name工程,测试face_training工程下的分类器MyFaceFisherModel.xml、MyFaceLBPHModel.xml和MyFacePCAModel.xml。


       参考链接 http://blog.csdn.net/xingchenbingbuyu/article/details/51472330


(4)照片分类

            MyFaceRecognition工程中,将一些人的照片放在一个文件夹里,合照、自拍、摄像头拍、别人的照片,程序里依次读取这些照片,利用haar-like特征进行人脸检测,在框出的人脸上依次利用训练出的PCA、LBP和Fisher分类器进行识别,将框出的人脸、人眼以及标记显示在窗口上识别出自己的照片时保存在测试结果文件夹testResults_PCA、testResults_LBP、testResults_Fisher中。

       我的结果显示:PCA只能识别出电脑摄像头拍的照片,手机自拍识别不出;LBP像是较为宽松,电脑和手机都能识别出;Fisher介于两者之间。三种分类器都能准确识别出电脑摄像头拍的照片。


       我的程序如下:

#include<opencv2/opencv.hpp> 
#include<opencv2/objdetect/objdetect.hpp>  
#include<opencv2/highgui/highgui.hpp>  
#include<opencv2/imgproc/imgproc.hpp>
#include <sstream>

using namespace cv;
using namespace std;

// 人脸检测的类,实例化对象  
CascadeClassifier face_cascade;
CascadeClassifier eyes_cascade;

int main()
{
    // 加载分类器,用于将人脸从背景中检测出来。注意文件路径。这里使用openCV2环境
	face_cascade.load("...\sources\data\haarcascades\haarcascade_frontalface_alt2.xml");
	eyes_cascade.load("...\sources\data\haarcascades\haarcascade_eye_tree_eyeglasses.xml");

	/*------以下分类器,用于人脸识别,三选一进行测试,注意修改分类结果的保存路径--------*/
	// 训练出的PCA分类器
	Ptr<FaceRecognizer> model = createEigenFaceRecognizer();
	model->load("...\MyFacePCAModel.xml");

	// 训练出的LBP分类器
	//Ptr<FaceRecognizer> model = createLBPHFaceRecognizer();
	//model->load("...\MyFaceLBPHModel.xml");

	// 训练出的Fisher分类器
	//Ptr<FaceRecognizer> model = createFisherFaceRecognizer();
	//model->load("...\MyFaceFisherModel.xml");
	/*-----------------------------------------------------------------------------------*/

	vector<Rect> faces;
	vector<Rect> eyes;
	Mat img, img_gray;

	// 图片编号
	int cnt = 1;
	// 循环停止标志
	bool stop_flag = false;

	while (!stop_flag)
	{
		// 待处理图片的地址及文件名
		string imagename = format("...\testphotos\%d.jpg", cnt);
		// 读取待处理图片,存放在img中
		img = imread(imagename);
		// 如果读入图像失败
		if (img.empty())
		{
			fprintf(stderr, "Can not load image %sn", imagename);
			return 1;
		}

		// 将图片转化为灰度图,存放在img_gray中
		cvtColor(img, img_gray, COLOR_BGR2GRAY);
		// 使灰度图像直方图均衡化
		equalizeHist(img_gray, img_gray);

		// 检测人脸,faces保存被检测出的人脸位置坐标序列 
		face_cascade.detectMultiScale(img_gray, faces, 1.1, 3, CV_HAAR_DO_ROUGH_SEARCH, Size(50, 50));

		Mat face;
		Point text_lb;

		// 将检测出的人脸框出,并进行识别标示自己的名字
		for (size_t i = 0; i < faces.size(); i++)
		{
			if (faces[i].height > 0 && faces[i].width > 0)
			{
				face = img_gray(faces[i]);
				text_lb = Point(faces[i].x, faces[i].y);

				rectangle(img, faces[i], Scalar(255, 0, 0), 2, 8, 0);

				// 检测人眼
				Mat faceROI = img_gray(faces[i]);
				eyes_cascade.detectMultiScale(faceROI, eyes, 1.1, 1, CV_HAAR_DO_ROUGH_SEARCH, Size(3, 3));

				for (size_t j = 0; j < eyes.size(); j++)
				{
					Rect rect(faces[i].x + eyes[j].x, faces[i].y + eyes[j].y, eyes[j].width, eyes[j].height);
					rectangle(img, rect, Scalar(0, 255, 0), 2, 8, 0);
				}
			}
		}

		Mat face_test;
		int predict = 0;
		if (face.rows >= 120)
		{
			resize(face, face_test, Size(92, 112));
		}

		if (!face_test.empty())
		{
			// 测试图像应该是灰度图  
			predict = model->predict(face_test);
		}

		cout << predict << endl;
		if (predict == 35)  // 35对应try.txt的s41文件夹下的照片,也就是我的照片
		{
			string name = "My Name";
			putText(img, name, text_lb, FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255));
			// 为识别出的图片定义存放路径
			string  str = format("...\testResults_PCA\%d.jpg", cnt);
			//string  str = format("...\testResults_LBP\%d.jpg", cnt);
			//string  str = format("...\testResults_Fisher\%d.jpg", cnt);
			imwrite(str, img);
		}

		//-- Show what you got  
		String window_name = format("%d Face Recognition",cnt);
		namedWindow(window_name, CV_WINDOW_NORMAL);
		resizeWindow(window_name,500,500);
		imshow(window_name, img);

		// 待处理图片的编号
		cnt++;
		// 共处理13张图片
		if (cnt > 13)
		{
			stop_flag = true;
		}
	}

	waitKey(0);
	return 0;

}





亲测,按照上面的步骤实现的话,是可以得出结果哒,这里就不贴出自己的照片了再见


版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/xiaoqkunle/article/details/78807748
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2019-09-13 15:59:53
  • 阅读 ( 1806 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

推荐文章

猜你喜欢