Opencv摄像头实时人脸识别
- 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,抱歉事情多添加有些晚,我放在下面了,有什么问题欢迎交流~
#include "opencv2/core/core.hpp"
#include "opencv2/contrib/contrib.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/objdetect/objdetect.hpp" #include <iostream>
#include <fstream>
#include <sstream>
#include <string.h> char *FACES_TXT_PATH = "face.txt";
char *HARR_XML_PATH = "haarcascade_frontalface_alt.xml";
char *FACES_MODEL = "face.yaml";
char *POTRAITS ="potraits.jpg";
int DEVICE_ID = ;
主文件内容:
/*头文件:*/
#include "opencv2/core/core.hpp"
#include "opencv2/contrib/contrib.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/objdetect/objdetect.hpp" #include <iostream>
#include <fstream>
#include <sstream>
#include <string.h> char *FACES_TXT_PATH = "face.txt";
char *HARR_XML_PATH = "haarcascade_frontalface_alt.xml";
char *FACES_MODEL = "face.yaml";
char *POTRAITS ="potraits.jpg";
int DEVICE_ID = ; /*主文件*/
#include "config.h" using namespace cv;
using namespace std;
int FACE_WIDHT=;
int FACE_HEIGHT=;
int POTRITE_WIDTH = ;
int POTRITE_HEIGHT = ; static void read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, char separator = ';') {
std::ifstream file(filename.c_str(), ifstream::in);
if (!file) {
string error_message = "找不到文件,请核对路径";
CV_Error(CV_StsBadArg, error_message);
}
string line, path, classlabel;
while (getline(file, line)) {
stringstream liness(line);
getline(liness, path, separator);
getline(liness, classlabel);
if(!path.empty() && !classlabel.empty()) {
images.push_back(imread(path, ));
labels.push_back(atoi(classlabel.c_str()));
}
} } /*利用csv文件读取数据集并训练对应模型*/
void train_data(String fn_csv)
{
vector<Mat> images;
vector<int> labels;
//获取数据集,如果出错抛出异常
try {
read_csv(fn_csv, images, labels);
}
catch (cv::Exception& e) {
cerr << "打开文件失败 \"" << fn_csv << "\". 原因: " << e.msg << endl;
exit();
} // 如果训练集数量不够退出
if(images.size() <= ) {
string error_message = "训练集图片少于2";
CV_Error(CV_StsError, error_message);
} //训练模型
Ptr<FaceRecognizer> model = createLBPHFaceRecognizer();
model->train(images, labels);
model->save(FACES_MODEL);
} void show_portrait(Mat &potrait, Mat &frame) {
int channels = potrait.channels();
int nRows = potrait.rows;
int nCols = potrait.cols*channels; uchar *p_p, *p_f;
for(auto i=; i<nRows; i++) {
p_p = potrait.ptr<uchar>(i);
p_f = frame.ptr<uchar>(i);
for(auto j=; j<nCols; j++) {
p_f[j*] = p_p[j];
p_f[j*+] = p_p[j+];
p_f[j*+] = p_p[j+];
}
} } void makePotraitImages(vector<Mat> potraits) {
int rows = potraits.size()/;
if(potraits.size()-rows *>)rows++;
rows *= POTRITE_HEIGHT;
int cols = *POTRITE_HEIGHT;
Mat potrait_s = Mat(rows,cols,CV_8UC3);
rows = POTRITE_HEIGHT;
cols = POTRITE_WIDTH;
uchar *p_ps, *p_p;
for(auto i=; i<potraits.size(); i++) {
for(auto j=; j<rows; j++) {
p_ps = potrait_s.ptr<uchar>(i/*POTRITE_HEIGHT+j)+*(i%)*POTRITE_WIDTH;
p_p = potraits[i].ptr<uchar>(j);
for(auto k=; k<cols; k++) {
p_ps[k*] = p_p[k];
p_ps[k*+] = p_p[k+];
p_ps[k*+] = p_p[k+];
}
}
}
imwrite(POTRAITS, potrait_s);
} void loadPortraits(const string& filename, vector<Mat>& images, char separator = ';') {
string fn_csv = string(FACES_TXT_PATH);
std::ifstream file(fn_csv.c_str(), ifstream::in);
if (!file) {
string error_message = "找不到文件,请核对路径.";
CV_Error(CV_StsBadArg, error_message);
}
string line, path, classlabel;
int label();
while (getline(file, line)) {
stringstream liness(line);
getline(liness, path, separator);
getline(liness, classlabel);
if(!path.empty() && !classlabel.empty()) {
if(atoi(classlabel.c_str()) != label) {
Mat potrait = imread(path, );
resize(potrait, potrait,Size(POTRITE_WIDTH, POTRITE_HEIGHT));
images.push_back(potrait);
label = atoi(classlabel.c_str());
}
}
}
} int main(int argc, const char *argv[]) {
// 保存图像和对应标签的向量,要求同一个人的图像必须对应相同的标签
string fn_csv = string(FACES_TXT_PATH);
string fn_haar = string(HARR_XML_PATH); Ptr<FaceRecognizer> model = createLBPHFaceRecognizer();
FileStorage model_file(FACES_MODEL, FileStorage::READ);
if(!model_file.isOpened()){
cout<<"无法找到模型,训练中..."<<endl;
train_data(fn_csv);//训练数据集,1表示EigenFace 2表示FisherFace 3表示LBPHFace
}
model->load(model_file);
model_file.release();
vector<Mat> potraits;
loadPortraits(FACES_MODEL,potraits);
makePotraitImages(potraits);
CascadeClassifier haar_cascade;
haar_cascade.load(fn_haar); VideoCapture cap(DEVICE_ID);
if(!cap.isOpened()) {
cerr << "设备 " << DEVICE_ID << "无法打开" << endl;
return -;
} Mat frame;
for(;;) {
cap >> frame;
if(!frame.data)continue;
// 拷贝现有frame
Mat original = frame.clone();
// 灰度化
Mat gray;
cvtColor(original, gray, CV_BGR2GRAY);
// 识别frame中的人脸
vector< Rect_<int> > faces;
haar_cascade.detectMultiScale(gray, faces); if(faces.size() != )
{
int max_area_rect=;
for(int i = ; i < ; i++) {
if(faces[i].area() > faces[max_area_rect].area()){
max_area_rect = i;
} } // 顺序处理
Rect face_i = faces[max_area_rect]; Mat face = gray(face_i);
rectangle(original, face_i, CV_RGB(, ,), );
int pridicted_label = -;
double predicted_confidence = 0.0;
model->predict(face, pridicted_label, predicted_confidence);
string result_text = format("Prediction = %d confidence=%f", pridicted_label, predicted_confidence);
int text_x = std::max(face_i.tl().x - , );
int text_y = std::max(face_i.tl().y - , );
putText(original,result_text, Point(text_x, text_y),FONT_HERSHEY_PLAIN, 1.0, CV_RGB(,,), 2.0);
if(pridicted_label >)
show_portrait(potraits[pridicted_label], original);
}
// 显示结果:
imshow("face_recognizer", original); char key = (char) waitKey();
if(key == )
exit();;
}
return ;
}
- Experiment
图3 结果展示
图4 人脸库拼图
Opencv摄像头实时人脸识别的更多相关文章
- 使用dlib中的深度残差网络(ResNet)实现实时人脸识别
opencv中提供的基于haar特征级联进行人脸检测的方法效果非常不好,本文使用dlib中提供的人脸检测方法(使用HOG特征或卷积神经网方法),并使用提供的深度残差网络(ResNet)实现实时人脸识别 ...
- Asp.net+WebSocket+Emgucv实时人脸识别
上个月在网上看到一个用web实现简单AR效果的文章,然后自己一路折腾,最后折腾出来一个 Asp.net+WebSocket+Emgucv实时人脸识别的东西,网上也有不少相关资料,有用winform的也 ...
- Python 3 利用 Dlib 实现摄像头实时人脸检测和平铺显示
1. 引言 在某些场景下,我们不仅需要进行实时人脸检测追踪,还要进行再加工:这里进行摄像头实时人脸检测,并对于实时检测的人脸进行初步提取: 单个/多个人脸检测,并依次在摄像头窗口,实时平铺显示检测到的 ...
- 【从零学习openCV】IOS7人脸识别实战
前言 接着上篇<IOS7下的人脸检測>,我们顺藤摸瓜的学习怎样在IOS7下用openCV的进行人脸识别,实际上非常easy,因为人脸检測部分已经完毕,剩下的无非调用openCV的方法对採集 ...
- 基于Opencv快速实现人脸识别(完整版)
无耻收藏网页链接: 基于OpenCV快速实现人脸识别:https://blog.csdn.net/beyond9305/article/details/92844258 基于Opencv快速实现人脸识 ...
- Python程序调用摄像头实现人脸识别
使用简单代码实现摄像头进行在线人脸识别 import cv2 import sys import logging as log import datetime as dt from time impo ...
- MFC中利用Opencv与C++抓取摄像头进行人脸识别(Mat)
原文:http://blog.csdn.net/mr_curry/article/details/51098311 第一次写博客哈哈,有些小激动,还请各位大神多多包涵~ 最近的项目需要用到人脸识别,作 ...
- 利用face_recognition,dlib与OpenCV调用摄像头进行人脸识别
用已经搭建好 face_recognition,dlib 环境来进行人脸识别 未搭建好环境请参考:https://www.cnblogs.com/guihua-pingting/p/12201077. ...
- OpenCV 和 Dlib 人脸识别基础
00 环境配置 Anaconda 安装 1 下载 https://repo.anaconda.com/archive/ 考虑到兼容性问题,推荐下载Anaconda3-5.2.0版本. 2 安装 3 测 ...
随机推荐
- [LeetCode] All solution
比较全的leetcode答案集合: kamyu104/LeetCode grandyang
- ESENT分布式数据存储
关于ESENT,我能想到最恰当的比喻是,它是Microsoft世界的BerkeleyDB,鲜为人知,很少有.NET开发人员使用它,rhino-queues项目使用就是它,但它的性能和可靠性已经经受住了 ...
- 基于Deep Learning 的视频识别方法概览
深度学习在最近十来年特别火,几乎是带动AI浪潮的最大贡献者.互联网视频在最近几年也特别火,短视频.视频直播等各种新型UGC模式牢牢抓住了用户的消费心里,成为互联网吸金的又一利器.当这两个火碰在一起,会 ...
- Javascript判断两个日期是否相等
大家一定遇到过这样的情况,有两个日期对象,然后需要判断他们是否相等. 例如: var date1 = new Date("2013-11-29"); var date2 = new ...
- ASP.Net WebForm温故知新学习笔记:二、ViewState与UpdatePanel探秘
开篇:经历了上一篇<aspx与服务器控件探秘>后,我们了解了aspx和服务器控件背后的故事.这篇我们开始走进WebForm状态保持的一大法宝—ViewState,对其刨根究底一下.然后,再 ...
- .Net开发笔记(二十)创建一个需要授权的第三方组件
在使用需要授权的软件时,注册付费的目标是软件的使用者,我们开发人员平时用到的一些第三方组件也是需要授权付费的,也就是说,付费者是开发人员,并不是系统(使用了该第三方组件)的最终使用者. 以上两者的区别 ...
- 从Undo,Redo谈命令模式
一般的应用软件中,通常会提供Redo和Undo的操作,比如Paint.NET中的动作面板,Word中的撤销重做,一般我们按Ctrl-Z即可回退到上次操作. 要实现上面的这一功能,最直观的想法就是,我们 ...
- Web3DGame之路,Babylonjs 和TypeScript学习笔记(二)
先来认识一下Babylonjs,由于基于webgl来开发,所以先介绍一下基础知识. Webgl是一个html标准,他要在canvas元素上初始化. Html页面上的准备 所以我们先从html页面开始看 ...
- 如何设计一门语言(十)——正则表达式与领域特定语言(DSL)
几个月前就一直有博友关心DSL的问题,于是我想一想,我在gac.codeplex.com里面也创建了一些DSL,于是今天就来说一说这个事情. 创建DSL恐怕是很多人第一次设计一门语言的经历,很少有人一 ...
- Oralce 重建EM服务,OracleDBConsoleOracle
今天打开Oracle ,想进em看看,结果发现OracleDBConsoleOracle服务老是报错: OracleDBConsoleOracle 服务因 2 (0x2) 服务性错误而停止. 搞不懂, ...