基于opencv的人脸视频采集及实时检测
- (一)调用摄像头采集视频
- (二)基于opencv的人脸检测
- (a) 对检测出的人脸画一个矩形框或圆圈
- (1)图片人脸检测&矩形框标记
- (2)实时视频人脸检测&矩形框标记
- (3)对mp4视频进行人脸检测
- (b) 对此人脸区域进行模糊处理
目标:
(1)在windows下使用opencv编程,用摄像头采集一段人脸表情视频和挥手手势短视频,并保存下来;
(2)在树莓派上基于opencv(c/c++)完成对视频中人脸的检测,
a)对检测出的人脸画一个矩形框或圆圈,
b)对此人脸区域进行模糊处理。
(一)调用摄像头采集视频
环境:VS2017+opencv3.4.1
- 在vs2017下创建项目并引入空项目Project1为其添加一个test1.cpp,并为其配置环境(Windows10+opencv3.4.1+VS2017配置教程)。
源码
//VideoCapture.cpp
#include<opencv2\opencv.hpp>
using namespace cv;
int main() {
VideoCapture capture(0);
// 设置摄像头的拍摄属性为 分辨率640x480,帧率30fps
capture.set(CAP_PROP_FRAME_HEIGHT, 480);
capture.set(CAP_PROP_FRAME_WIDTH, 640);
capture.set(CAP_PROP_FPS, 30.0);
// 设置保存视频的格式为AVI,编码为MJPG
VideoWriter writer("test.avi", VideoWriter::fourcc('M', 'J', 'P', 'G'), 30.0, Size(640, 480), true);
Mat videoPlay;
// 通过总帧数来控制拍摄时间,如果是10s的段视频的话,循环300次
int count(300);
namedWindow("VideoPlay", WINDOW_NORMAL);
while (count--) {
capture >> videoPlay;
writer << videoPlay;
imshow("VideoPlay", videoPlay);
waitKey(1000 / 30);
}
// 释放相关对象
writer.release();
capture.release();
destroyWindow("VideoPlay");
return 0;
}
- 录制:(10s)
- 录制完成按Esc退出,自动保存avi到Project1项目中
- 查看录制test.avi:
- 将test.avi转换为mp4格式
为了防止后面"capture.open(test.avi)"读取总为null
(迅捷官网下载视频转换器:)
(二)基于opencv的人脸检测
(a) 对检测出的人脸画一个矩形框或圆圈
1. 图片人脸识别
2. 摄像头实时人脸识别
3. 识别视频中的人脸
(1)图片人脸检测&矩形框标记
参考教程:
- VS2017中新建一个face_find工程,新建face_find.cpp,并配置环境
图片人脸检测源码
#include<opencv2/objdetect/objdetect.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include <iostream>
//=============================================================================================
// 对图片进行人脸检测
//=============================================================================================
using namespace cv;
using namespace std;
CascadeClassifier faceCascade;
int main()
{
faceCascade.load("D:/mydownload/opencv341/opencv/build/etc/haarcascades/haarcascade_frontalface_alt2.xml");//引入人脸识别库文件
Mat img = imread("test.jpg"); // 载入图片,图片.jpg与.cpp处于同一路径
Mat imgGray;
vector<Rect> faces;
if (img.empty())
{
return 1;
}
if (img.channels() == 3)
{
cvtColor(img, imgGray, CV_RGB2GRAY); // RGB转化为灰度
}
else
{
imgGray = img; // 不转化
}
faceCascade.detectMultiScale(imgGray, faces, 1.2, 6, 0, Size(0, 0));// 检测人脸
if (faces.size() > 0)
{
for (int i = 0; i < faces.size(); i++)
{
rectangle(img, Point(faces[i].x, faces[i].y), Point(faces[i].x + faces[i].width, faces[i].y + faces[i].height), Scalar(0, 255, 0), 1, 8); // 框出人脸
}
}
imshow("FacesOfPrettyGirl", img); // 显示图片
waitKey(0);
return 0;
}
关于图片人脸识别xml存放位置:(可以把*.xml直接拷到project工程里)
- 图片识别检测效果:
(2)实时视频人脸检测&矩形框标记
- 如上在VS2017中创建空项目与.cpp文件并配置环境
实时人脸检测源码
#include<opencv2/objdetect/objdetect.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<iostream>
//=============================================================================================
// 对视频进行人脸检测
//=============================================================================================
using namespace cv;
using namespace std;
CascadeClassifier faceCascade;
int main()
{
faceCascade.load("D:/mydownload/opencv341/opencv/build/etc/haarcascades/haarcascade_frontalface_alt2.xml");
VideoCapture capture;
capture.open(0); // 打开摄像头
// capture.open("test.avi"); // 打开视频
if (!capture.isOpened())
{
cout << "open camera failed. " << endl;
return -1;
}
Mat img, imgGray;
vector<Rect> faces;
while (1)
{
capture >> img; // 读取图像至img
if (img.empty())
{
continue;
}
if (img.channels() == 3)
{
cvtColor(img, imgGray, CV_RGB2GRAY);
}
else
{
imgGray = img;
}
faceCascade.detectMultiScale(imgGray, faces, 1.2, 6, 0, Size(0, 0)); // 检测人脸
if (faces.size() > 0)
{
for (int i = 0; i < faces.size(); i++)
{
rectangle(img, Point(faces[i].x, faces[i].y), Point(faces[i].x + faces[i].width, faces[i].y + faces[i].height), Scalar(0, 255, 0), 1, 8);
}
}
imshow("CamerFace", img);// 显示
if (waitKey(1) > 0) // delay ms 等待按键退出
{
break;
}
}
return 0;
}
- 实时视频检测效果(单人&多人)
- 优化视频流程序
参考教程:
实时人脸检测源码(优化版)
#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
// 控制编译版本宏
//#define VERSION_2_4
/* 参数 : 输入图像、级联分类器、缩放倍数 */
void DetectAndDraw(Mat& img, CascadeClassifier& cascade, double scale);
int main()
{
CascadeClassifier faceCascade;
double scale = 4;
int nRet = 0;
VideoCapture capture;
capture.open(0);
// capture.open("test.avi");
if (!capture.isOpened())
{
cout << "open camera failed. " << endl;
return -1;
}
cout << "open camera succeed. " << endl;
/* 加载分类器 */
#ifdef VERSION_2_4
nRet = faceCascade.load("D:/mydownload/opencv341/opencv/build/etc/haarcascades/haarcascade_frontalface_alt2.xml");
#else
nRet = faceCascade.load("D:/mydownload/opencv341/opencv/build/etc/haarcascades/haarcascade_frontalface_alt2.xml");
#endif
if (!nRet)
{
printf("load xml failed.\n");
return -1;
}
Mat frame;
vector<Rect> faces;
while (1)
{
capture >> frame;
if (frame.empty())
{
continue;
}
Mat frame1 = frame.clone();
DetectAndDraw(frame1, faceCascade, scale);
if (waitKey(1) > 0) // delay ms 等待按键退出
{
break;
}
}
return 0;
}
void DetectAndDraw(Mat& img, CascadeClassifier& cascade, double scale)
{
double t = 0;
vector<Rect> faces;
Mat gray, smallImg;
double fx = 1 / scale;
cvtColor(img, gray, COLOR_BGR2GRAY); // 将源图像转为灰度图
/* 缩放图像 */
#ifdef VERSION_2_4
resize(gray, smallImg, Size(), fx, fx, INTER_LINEAR);
#else
resize(gray, smallImg, Size(), fx, fx, INTER_LINEAR_EXACT);
#endif
equalizeHist(smallImg, smallImg); // 直方图均衡化,提高图像质量
/* 检测目标 */
t = (double)getTickCount();
cascade.detectMultiScale(smallImg, faces,
1.1, 2, 0
//|CASCADE_FIND_BIGGEST_OBJECT
//|CASCADE_DO_ROUGH_SEARCH
| CASCADE_SCALE_IMAGE,
Size(30, 30));
t = (double)getTickCount() - t;
printf("detection time = %g ms\n", t * 1000 / getTickFrequency());
/* 画矩形框出目标 */
for (size_t i = 0; i < faces.size(); i++) // faces.size():检测到的目标数量
{
Rect rectFace = faces[i];
rectangle(img, Point(rectFace.x, rectFace.y) * scale,
Point(rectFace.x + rectFace.width, rectFace.y + rectFace.height) * scale,
Scalar(0, 255, 0), 2, 8);
}
imshow("FaceDetect", img); // 显示
}
- 视频优化后检测效果:
(3)对mp4视频进行人脸检测
- 对(b)部分代码更改:
- 对mp4视频进行人脸检测运行结果:
- 优化后的mp4视频检测代码:
(b) 对此人脸区域进行模糊处理
高斯模糊参考教程:
1. VS2017+C语言
- 如上在VS2017中创建空项目与.cpp文件并配置环境
高斯人脸模糊源码
#include<opencv2/objdetect.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>
#include<iostream>
#include<stdio.h>
using namespace cv;
using namespace std;
// 控制编译版本宏
//#define VERSION_2_4
//参数 : 输入图像、级联分类器、缩放倍数
void DetectAndDraw(Mat& img, CascadeClassifier& cascade, double scale);
int main()
{
CascadeClassifier faceCascade;
double scale = 4;
int nRet = 0;
VideoCapture capture;
//capture.open(0);
capture.open("test.mp4");
if (!capture.isOpened())
{
cout << "open camera failed. " << endl;
return -1;
}
cout << "open camera succeed. " << endl;
// 加载分类器
#ifdef VERSION_2_4
nRet = faceCascade.load("D:/mydownload/opencv341/opencv/build/etc/haarcascades/haarcascade_frontalface_alt2.xml");
#else
nRet = faceCascade.load("D:/mydownload/opencv341/opencv/build/etc/haarcascades/haarcascade_frontalface_alt2.xml");
#endif
if (!nRet)
{
printf("load xml failed.\n");
return -1;
}
Mat frame;
vector<Rect> faces;
while (1)
{
capture >> frame;
if (frame.empty())
{
continue;
}
Mat frame1 = frame.clone();
//高斯模糊处理
//GaussianBlur(frame, frame1, Size(7, 7 ), 0, 0);
imshow("Face", frame1); // 显示原画
DetectAndDraw(frame1, faceCascade, scale);
if (waitKey(1) > 0) // delay ms 等待按键退出
{
break;
}
}
return 0;
}
void DetectAndDraw(Mat& img, CascadeClassifier& cascade, double scale)
{
double t = 0;
vector<Rect> faces;
Mat gray, smallImg;
Mat temp;
double fx = 1 / scale;
cvtColor(img, gray, COLOR_BGR2GRAY); // 将源图像转为灰度图
// 缩放图像
#ifdef VERSION_2_4
resize(gray, smallImg, Size(), fx, fx, INTER_LINEAR);
#else
resize(gray, smallImg, Size(), fx, fx, INTER_LINEAR_EXACT);
#endif
equalizeHist(smallImg, smallImg); // 直方图均衡化,提高图像质量
// 检测目标
t = (double)getTickCount();
cascade.detectMultiScale(smallImg, faces,
1.1, 2, 0
//|CASCADE_FIND_BIGGEST_OBJECT
//|CASCADE_DO_ROUGH_SEARCH
| CASCADE_SCALE_IMAGE,
Size(30, 30));
t = (double)getTickCount() - t;
printf("detection time = %g ms\n", t * 1000 / getTickFrequency());
// 画矩形框出目标
for (size_t i = 0; i < faces.size(); i++) // faces.size():检测到的目标数量
{
Rect rectFace = faces[i];
rectangle(img, Point(rectFace.x, rectFace.y) * scale,
Point(rectFace.x + rectFace.width, rectFace.y + rectFace.height) * scale,
Scalar(0, 255, 0), 2, 8);
//高斯模糊处理(全图模糊)
//GaussianBlur(img, img, Size(7,7), 0, 0);
//高斯模糊处理(引入矩形框)
Mat imgct;
Rect rec(Point(rectFace.x, rectFace.y) * scale, Point(rectFace.x + rectFace.width, rectFace.y + rectFace.height) * scale);
imgct = img(rec);
GaussianBlur(imgct, imgct, Size(15, 15), 0, 0);
}
imshow("FaceDetect", img); // 显示
}
- 模糊前后运行结果:(对比)
2. 树莓派3b+C语言
- 将test.mp4传到树莓派上进行编译
用teamviewer传输文件
- 命令行模式:
cd opencv_test//进入opencv_test文件夹
mkdir test2_video//新建一个opencv_test2文件夹
touch test2_video.cpp//新建一个空的cpp文件
Vim test2_video.cpp //将高斯人脸模糊源码中的复制到cpp中 注意将xml的位置更改一下: #ifdef VERSION_2_4 nRet = faceCascade.load(“home/pi/opencv-3.4.1/data/haarcascades/haarcascade_frontalface_alt2.xml”); #else nRet = faceCascade.load(“home/pi/opencv-3.4.1/data/haarcascades/haarcascade_frontalface_alt2.xml”); #endif
- g++编译
g++ test2_video.cpp -o test
pkg-config --cflags --libs opencv
- 运行程序
./test
大功告成!