基于opencv的人脸视频采集及实时检测

目标:
(1)在windows下使用opencv编程,用摄像头采集一段人脸表情视频和挥手手势短视频,并保存下来;
(2)在树莓派上基于opencv(c/c++)完成对视频中人脸的检测,
a)对检测出的人脸画一个矩形框或圆圈,
b)对此人脸区域进行模糊处理。

(一)调用摄像头采集视频

环境:VS2017+opencv3.4.1

源码
//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)图片人脸检测&矩形框标记:

参考教程:https://blog.csdn.net/qq_30155503/article/details/79475461

  • 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;
}
  • 实时视频检测效果(单人&多人)
    在这里插入图片描述
    在这里插入图片描述
  • 优化视频流程序

参考教程:
https://blog.csdn.net/qq_30155503/article/details/79637231

实时人脸检测源码(优化版)
#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)对此人脸区域进行模糊处理

高斯模糊参考教程:https://www.cnblogs.com/Blackops/p/5766317.html

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
在这里插入图片描述

大功告成!

猜你喜欢

转载自blog.csdn.net/cungudafa/article/details/84486889