社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
本篇文章主要介绍了如何使用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)之后的每一帧就不需要像第一帧那样在全图中对小明进行检测,而是可以根据小明的运动轨迹建立运动模型,通过模型对下一帧小明的位置进行预测,从而提升跟踪的效率(目标跟踪)
程序实现
下载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)照片分类
我的程序如下:
#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;
}
亲测,按照上面的步骤实现的话,是可以得出结果哒,这里就不贴出自己的照片了
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!