• Introduction

网上存在很多人脸识别的文章,这篇文章是我的一个作业,重在通过摄像头实时采集人脸信息,进行人脸检测和人脸识别,并将识别结果显示在左上角。

利用 OpenCV 实现一个实时的人脸识别系统,人脸库采用 ORL FaceDatabase (网上下载) ,另外在数据库中增加了作业中自带的20张照片和自己利用摄像头采集到的10张照片,系统利用摄像头实时的采集到场景图像,从中检测出人脸用方框标出,并利用提供的数据库进行人脸识别,并在图像左上角显示相匹配的数据库图片。

  • Method

算法流程分两步,分别是人脸检测和人脸识别。人脸检测使用的是 ViolaJones 人脸检测方法,利用样本的 Haar-like 特征进行分类器训练,得到级联boosted 分类器,加载训练好的人脸分类器,利用分类器在视频帧中查找人脸区域;人脸识别利用了局部二进制模式直方图。

  • Haar-like 特征

Haar-like 特征如下图所示

图1 Haar-like 特征

  • LBPH

人脸识别常用的方法有三种,Eigenfaces、Fisherfaces 和 LBPH;对于高维的图像空间,我们首先应该进行降维操作。LBP 不把图像看做高维的矢量,而是通过物体的局部特征来描述。将每个像素和其相邻像素对比形成局部的结构,把该像素看做中心,并以该值对邻接像素做阈值处理,如果临界像素的亮度大于该像素则为 1 否则为 0,这样每个像素点都可以用一个二进制数来表示,比如一个使用 3*3 临界点的 LBP 操作如下图所示:

图2 LBP

  • Implementation
  • 识别训练

利用准备好的数据库进行识别训练:首先我们利用Opencv安装文件中的python脚本create_csv.py建立CSV文件,文件中每条记录如:orl/s13/2.pgm;12,分号之前是图片所存路径,而分号之后是图片的标签号,每一组图片对应着唯一的标签号;之后利用代码中的train_data和read_csv函数对数据集进行训练。使用到的 OpenCV 类和函数有:FaceRecognizer,createLBPHFaceRecognizer

  • 人脸检测

运用Opencv安装文件中的haarcascade_frontalface_alt.xml文件,使用分类器在视频帧中查找人脸区域,并用绿色方框标出。用到的 OpenCV 类和函数有:CascadeClassifier,detectMultiScale。

  • 人脸识别

读取训练好的 yaml文件,对每个监测到的区域的图像分类,并在视频帧人脸区域上方显示分类结果(分类结果显示为标签和可信度),在左上角显示缩略图。用到的 OpenCV 函数主要有:predict.

  • Code

看到评论,大家需要config.h,抱歉事情多添加有些晚,我放在下面了,有什么问题欢迎交流~

  1. #include "opencv2/core/core.hpp"
  2. #include "opencv2/contrib/contrib.hpp"
  3. #include "opencv2/highgui/highgui.hpp"
  4. #include "opencv2/imgproc/imgproc.hpp"
  5. #include "opencv2/objdetect/objdetect.hpp"
  6.  
  7. #include <iostream>
  8. #include <fstream>
  9. #include <sstream>
  10. #include <string.h>
  11.  
  12. char *FACES_TXT_PATH = "face.txt";
  13. char *HARR_XML_PATH = "haarcascade_frontalface_alt.xml";
  14. char *FACES_MODEL = "face.yaml";
  15. char *POTRAITS ="potraits.jpg";
  16. int DEVICE_ID = ;

主文件内容:

  1. /*头文件:*/
  2. #include "opencv2/core/core.hpp"
  3. #include "opencv2/contrib/contrib.hpp"
  4. #include "opencv2/highgui/highgui.hpp"
  5. #include "opencv2/imgproc/imgproc.hpp"
  6. #include "opencv2/objdetect/objdetect.hpp"
  7.  
  8. #include <iostream>
  9. #include <fstream>
  10. #include <sstream>
  11. #include <string.h>
  12.  
  13. char *FACES_TXT_PATH = "face.txt";
  14. char *HARR_XML_PATH = "haarcascade_frontalface_alt.xml";
  15. char *FACES_MODEL = "face.yaml";
  16. char *POTRAITS ="potraits.jpg";
  17. int DEVICE_ID = ;
  18.  
  19. /*主文件*/
  20. #include "config.h"
  21.  
  22. using namespace cv;
  23. using namespace std;
  24. int FACE_WIDHT=;
  25. int FACE_HEIGHT=;
  26. int POTRITE_WIDTH = ;
  27. int POTRITE_HEIGHT = ;
  28.  
  29. static void read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, char separator = ';') {
  30. std::ifstream file(filename.c_str(), ifstream::in);
  31. if (!file) {
  32. string error_message = "找不到文件,请核对路径";
  33. CV_Error(CV_StsBadArg, error_message);
  34. }
  35. string line, path, classlabel;
  36. while (getline(file, line)) {
  37. stringstream liness(line);
  38. getline(liness, path, separator);
  39. getline(liness, classlabel);
  40. if(!path.empty() && !classlabel.empty()) {
  41. images.push_back(imread(path, ));
  42. labels.push_back(atoi(classlabel.c_str()));
  43. }
  44. }
  45.  
  46. }
  47.  
  48. /*利用csv文件读取数据集并训练对应模型*/
  49. void train_data(String fn_csv)
  50. {
  51. vector<Mat> images;
  52. vector<int> labels;
  53. //获取数据集,如果出错抛出异常
  54. try {
  55. read_csv(fn_csv, images, labels);
  56. }
  57. catch (cv::Exception& e) {
  58. cerr << "打开文件失败 \"" << fn_csv << "\". 原因: " << e.msg << endl;
  59. exit();
  60. }
  61.  
  62. // 如果训练集数量不够退出
  63. if(images.size() <= ) {
  64. string error_message = "训练集图片少于2";
  65. CV_Error(CV_StsError, error_message);
  66. }
  67.  
  68. //训练模型
  69. Ptr<FaceRecognizer> model = createLBPHFaceRecognizer();
  70. model->train(images, labels);
  71. model->save(FACES_MODEL);
  72. }
  73.  
  74. void show_portrait(Mat &potrait, Mat &frame) {
  75. int channels = potrait.channels();
  76. int nRows = potrait.rows;
  77. int nCols = potrait.cols*channels;
  78.  
  79. uchar *p_p, *p_f;
  80. for(auto i=; i<nRows; i++) {
  81. p_p = potrait.ptr<uchar>(i);
  82. p_f = frame.ptr<uchar>(i);
  83. for(auto j=; j<nCols; j++) {
  84. p_f[j*] = p_p[j];
  85. p_f[j*+] = p_p[j+];
  86. p_f[j*+] = p_p[j+];
  87. }
  88. }
  89.  
  90. }
  91.  
  92. void makePotraitImages(vector<Mat> potraits) {
  93. int rows = potraits.size()/;
  94. if(potraits.size()-rows *>)rows++;
  95. rows *= POTRITE_HEIGHT;
  96. int cols = *POTRITE_HEIGHT;
  97. Mat potrait_s = Mat(rows,cols,CV_8UC3);
  98. rows = POTRITE_HEIGHT;
  99. cols = POTRITE_WIDTH;
  100. uchar *p_ps, *p_p;
  101. for(auto i=; i<potraits.size(); i++) {
  102. for(auto j=; j<rows; j++) {
  103. p_ps = potrait_s.ptr<uchar>(i/*POTRITE_HEIGHT+j)+*(i%)*POTRITE_WIDTH;
  104. p_p = potraits[i].ptr<uchar>(j);
  105. for(auto k=; k<cols; k++) {
  106. p_ps[k*] = p_p[k];
  107. p_ps[k*+] = p_p[k+];
  108. p_ps[k*+] = p_p[k+];
  109. }
  110. }
  111. }
  112. imwrite(POTRAITS, potrait_s);
  113. }
  114.  
  115. void loadPortraits(const string& filename, vector<Mat>& images, char separator = ';') {
  116. string fn_csv = string(FACES_TXT_PATH);
  117. std::ifstream file(fn_csv.c_str(), ifstream::in);
  118. if (!file) {
  119. string error_message = "找不到文件,请核对路径.";
  120. CV_Error(CV_StsBadArg, error_message);
  121. }
  122. string line, path, classlabel;
  123. int label();
  124. while (getline(file, line)) {
  125. stringstream liness(line);
  126. getline(liness, path, separator);
  127. getline(liness, classlabel);
  128. if(!path.empty() && !classlabel.empty()) {
  129. if(atoi(classlabel.c_str()) != label) {
  130. Mat potrait = imread(path, );
  131. resize(potrait, potrait,Size(POTRITE_WIDTH, POTRITE_HEIGHT));
  132. images.push_back(potrait);
  133. label = atoi(classlabel.c_str());
  134. }
  135. }
  136. }
  137. }
  138.  
  139. int main(int argc, const char *argv[]) {
  140. // 保存图像和对应标签的向量,要求同一个人的图像必须对应相同的标签
  141. string fn_csv = string(FACES_TXT_PATH);
  142. string fn_haar = string(HARR_XML_PATH);
  143.  
  144. Ptr<FaceRecognizer> model = createLBPHFaceRecognizer();
  145. FileStorage model_file(FACES_MODEL, FileStorage::READ);
  146. if(!model_file.isOpened()){
  147. cout<<"无法找到模型,训练中..."<<endl;
  148. train_data(fn_csv);//训练数据集,1表示EigenFace 2表示FisherFace 3表示LBPHFace
  149. }
  150. model->load(model_file);
  151. model_file.release();
  152. vector<Mat> potraits;
  153. loadPortraits(FACES_MODEL,potraits);
  154. makePotraitImages(potraits);
  155. CascadeClassifier haar_cascade;
  156. haar_cascade.load(fn_haar);
  157.  
  158. VideoCapture cap(DEVICE_ID);
  159. if(!cap.isOpened()) {
  160. cerr << "设备 " << DEVICE_ID << "无法打开" << endl;
  161. return -;
  162. }
  163.  
  164. Mat frame;
  165. for(;;) {
  166. cap >> frame;
  167. if(!frame.data)continue;
  168. // 拷贝现有frame
  169. Mat original = frame.clone();
  170. // 灰度化
  171. Mat gray;
  172. cvtColor(original, gray, CV_BGR2GRAY);
  173. // 识别frame中的人脸
  174. vector< Rect_<int> > faces;
  175. haar_cascade.detectMultiScale(gray, faces);
  176.  
  177. if(faces.size() != )
  178. {
  179. int max_area_rect=;
  180. for(int i = ; i < ; i++) {
  181. if(faces[i].area() > faces[max_area_rect].area()){
  182. max_area_rect = i;
  183. }
  184.  
  185. }
  186.  
  187. // 顺序处理
  188. Rect face_i = faces[max_area_rect];
  189.  
  190. Mat face = gray(face_i);
  191. rectangle(original, face_i, CV_RGB(, ,), );
  192. int pridicted_label = -;
  193. double predicted_confidence = 0.0;
  194. model->predict(face, pridicted_label, predicted_confidence);
  195. string result_text = format("Prediction = %d confidence=%f", pridicted_label, predicted_confidence);
  196. int text_x = std::max(face_i.tl().x - , );
  197. int text_y = std::max(face_i.tl().y - , );
  198. putText(original,result_text, Point(text_x, text_y),FONT_HERSHEY_PLAIN, 1.0, CV_RGB(,,), 2.0);
  199. if(pridicted_label >)
  200. show_portrait(potraits[pridicted_label], original);
  201. }
  202. // 显示结果:
  203. imshow("face_recognizer", original);
  204.  
  205. char key = (char) waitKey();
  206. if(key == )
  207. exit();;
  208. }
  209. return ;
  210. }
  • Experiment

图3 结果展示

图4 人脸库拼图

Opencv摄像头实时人脸识别的更多相关文章

  1. 使用dlib中的深度残差网络(ResNet)实现实时人脸识别

    opencv中提供的基于haar特征级联进行人脸检测的方法效果非常不好,本文使用dlib中提供的人脸检测方法(使用HOG特征或卷积神经网方法),并使用提供的深度残差网络(ResNet)实现实时人脸识别 ...

  2. Asp.net+WebSocket+Emgucv实时人脸识别

    上个月在网上看到一个用web实现简单AR效果的文章,然后自己一路折腾,最后折腾出来一个 Asp.net+WebSocket+Emgucv实时人脸识别的东西,网上也有不少相关资料,有用winform的也 ...

  3. Python 3 利用 Dlib 实现摄像头实时人脸检测和平铺显示

    1. 引言 在某些场景下,我们不仅需要进行实时人脸检测追踪,还要进行再加工:这里进行摄像头实时人脸检测,并对于实时检测的人脸进行初步提取: 单个/多个人脸检测,并依次在摄像头窗口,实时平铺显示检测到的 ...

  4. 【从零学习openCV】IOS7人脸识别实战

    前言 接着上篇<IOS7下的人脸检測>,我们顺藤摸瓜的学习怎样在IOS7下用openCV的进行人脸识别,实际上非常easy,因为人脸检測部分已经完毕,剩下的无非调用openCV的方法对採集 ...

  5. 基于Opencv快速实现人脸识别(完整版)

    无耻收藏网页链接: 基于OpenCV快速实现人脸识别:https://blog.csdn.net/beyond9305/article/details/92844258 基于Opencv快速实现人脸识 ...

  6. Python程序调用摄像头实现人脸识别

    使用简单代码实现摄像头进行在线人脸识别 import cv2 import sys import logging as log import datetime as dt from time impo ...

  7. MFC中利用Opencv与C++抓取摄像头进行人脸识别(Mat)

    原文:http://blog.csdn.net/mr_curry/article/details/51098311 第一次写博客哈哈,有些小激动,还请各位大神多多包涵~ 最近的项目需要用到人脸识别,作 ...

  8. 利用face_recognition,dlib与OpenCV调用摄像头进行人脸识别

    用已经搭建好 face_recognition,dlib 环境来进行人脸识别 未搭建好环境请参考:https://www.cnblogs.com/guihua-pingting/p/12201077. ...

  9. OpenCV 和 Dlib 人脸识别基础

    00 环境配置 Anaconda 安装 1 下载 https://repo.anaconda.com/archive/ 考虑到兼容性问题,推荐下载Anaconda3-5.2.0版本. 2 安装 3 测 ...

随机推荐

  1. [LintCode] Container With Most Water 装最多水的容器

    Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai).  ...

  2. initWithCoder与initWithFrame的区别

    1. initWithFrame方法是什么?   initWithFrame方法用来初始化并返回一个新的视图对象,根据指定的CGRect(尺寸). 当然,其他UI对象,也有initWithFrame方 ...

  3. SQL语句经典大全

    一.基础 1.说明:创建数据库 CREATE DATABASE database-name  2.说明:删除数据库 drop database dbname 3.说明:备份sql server --- ...

  4. backbone新手填坑教程资源

    backbone 入门第二版 http://www.kancloud.cn/kancloud/backbonejs-learning-note/49379 backbone 入门讲解 http://w ...

  5. 打造AngularJs2.0开发环境

    angularjs2.0刚发布, typescript2.0也刚发布, 于2016.9.29记录. 参考文档:https://angular.cn/docs/ts/latest/quickstart. ...

  6. angularjs provider 供应商服务

    今天学习了angularjs的provider的供应商服务,写了个例子(自定义供应商服务,也可使用angularjs内部提供的服务) var starterApp = angular.module(' ...

  7. xcode gdb/lldb调试命令

    命令                        解释 break NUM               在指定的行上设置断点. bt                      显示所有的调用栈帧.该 ...

  8. mono 3.10.0 正式发布:性能进一步改进

    Mono是Xamarin资助的一个项目,是微软的.NET框架的开源实现.它使得使用C#.F#和其他.NET语言进行跨平台开发成为可能.Xamarin在Mono之上构建了跨平台开发工具以及像Xamari ...

  9. UI控件(UIWebView)

    本文主要记录UIWebView三方面内容: 1.基本的加载网页链接或文件: 2.网页js调用原生,也就是Cordova混合架构的原理: 3.原生调用js程序: 原生部分主要代码: @implement ...

  10. Python黑帽编程 3.1 ARP欺骗

    Python灰帽编程 3.1 ARP欺骗 ARP欺骗是一种在局域网中常用的攻击手段,目的是让局域网中指定的(或全部)的目标机器的数据包都通过攻击者主机进行转发,是实现中间人攻击的常用手段,从而实现数据 ...