OpenCV实现人脸检测

人脸识别和人脸检测简介

人脸识别是对已知人脸进行分类的过程。人脸识别通常包括四个主要步骤:

  1. 人脸检测:它是在图像中定位人脸区域的过程。(不关心人是谁,只关心是不是人脸)。
  2. 人脸预处理:这步是调整人脸图像,使其看起来更加清楚,且相似于其他人脸的过程。
  3. 收集和学习人脸:这步会收集许多被预处理过的人脸,然后学习如何识别它们。
  4. 人脸识别:在所收集的人脸中查找哪个人脸与摄像机中的人脸最相似。

用OpenCV实现人脸检测

1.加载Haar或LBP对象或人脸检测

为了执行对象或人脸检测,首先必须用OpenCV的CascadeClassifier类来加载训练好的XML文件。通过指定不同的文件名,就可以加载Haar或LBP检测器。用这种方式加载时,有一个常见的错误,即提供了错误的文件夹或文件名。代码实现如下:

	CascadeClassifier faceDetector;
	try{
			faceDetector.load(faceCascadeFilename);
		}
	catch (cv::Exception e){}
	if (faceDetector.empty())
	{
		std::cerr << "脸部检测器不能加载 (";
		std::cerr << faceCascadeFilename << ")!" << std::endl;
		exit(1);
	}

2.访问摄像机

为了从一台电脑的摄像头或从视频文件中获取帧,可简单地按摄像机编号或视频文件名来调用VideoCapture::open()函数,然后使用C++的流运算符来获取帧。

	VideoCapture camera(0);
	Mat camerFrame;
	camera >> camerFrame;

3.用Haar或LBP检测器来检测对象

现在已加载检测器(在初始化期间只加载一次),可用它来检测摄像机每帧中的人脸。但首先需专门针对人脸检测来预处理摄像机图像。

  1. 灰度色彩转换:人脸检测只适用于灰度图像。因此,应转换彩色摄像机每帧中的人脸。
    使用cvtColor()函数,可很容易地将RGB的彩色图像转换为灰度图像。但如果知道一个彩色图像,且必须指定输入图像格式(通常台式机是3通道BGR,而移动设备是4通道的BGRA格式),就只能这样做(即不需要对灰度图像进行转换)。因此,应该允许三种不同的输入色彩模式,如下面代码所示:
	Mat gray;
	if (camerFrame.channels() == 3)
	{
		cvtColor(camerFrame, gray, CV_BGR2GRAY);
	}
	else if (camerFrame.channels() == 4)
	{
		cvtColor(camerFrame, gray, CV_BGRA2GRAY);
	}
	else
		gray = camerFrame;
  1. 收缩摄像机图像:人脸检测的速度取决于输入图像的大小(对大的图像很慢,而对小图像很快),即使在低分辨率的情况下,其检测也相当可靠。所以应该缩小摄像机图像,使其有一个比较合理的尺寸。
    可使用resize()函数来将图像按一定尺寸或缩放因子进行缩放。只要图像尺寸大于240x240像素,人脸检测器通常都能得到很好的结果(除非要检测的人脸远离摄像机),因为它会寻找比minFeatureSize(通常为20x20像素)更大的所有人脸。
    另一个重要操作是要放大检测结果。因为一个缩小的图像中检测到人脸,则输出的图像也是缩小的。另外,如果不缩小输入图像,其代替方式是,在检测器中设置大的minFeatureSize值。除此之外,还必须确保图像不会变的太宽或太窄。所以,须保持输出和输入有相同的纵横比。具体操作如下:
		const int DETECTION_WIDTH = 320;
		Mat smallImg;
		float scale = camerFrame.cols / (float)DETECTION_WIDTH;
		if (camerFrame.cols > DETECTION_WIDTH){
			int scaleHeight = cvRound(camerFrame.rows / scale);
			resize(camerFrame, smallImg, Size(DETECTION_WIDTH,scaleHeight));
		}
		else{
			smallImg = camerFrame;
		}
  1. 直方图均衡化:在光线不足的情况下,人脸检测并不可靠。因此,应该进行直方图均衡化,以改善对比度和亮度。使用equalizeHist()函数来执行直方图均衡化。
	Mat equalizedImg;
	equalizeHist(gray, equalizedImg);

4.检测人脸

使用Cascade Classifier::detectMultiScale()函数来进行人脸检测。参数含义:

  • minFeatureSize:该参数决定了最小的人脸大小
  • searchScaleFactor:该参数决定有多少不同大小的人脸要搜索,通常设置为1.1能得到很好的检测结果,若设置为1.2,会检测更快,但经常找不到人脸。
  • minNeighbors:该参数决定人脸检测器如何确定人脸已经被检测到,通常它的值为3,如果需要所检测人脸的正确率更高,可将其设置的更大,但这样做可能会使一些人脸无法被检测到。
  • flags:该参数允许用户指定是否要查找所有人脸(默认)或只查找最大的人脸。
    代码如下所示:
		int flags = CASCADE_FIND_BIGGEST_OBJECT | CASCADE_DO_ROUGH_SEARCH;
		//只检测脸最大的人
		//int flags = CASCADE_SCALE_IMAGE;	//检测多个人
		Size minFeatureSize(30, 30);
		float searchScaleFactor = 1.1f;
		int minNeighbors = 4;
		std::vector<Rect> faces;
		faceDetector.detectMultiScale(equalizedImg, faces, searchScaleFactor, minNeighbors, flags, minFeatureSize);

下面贴出完整代码

#include <opencv.hpp>
#include <opencv2/core/core.hpp>
#include <iostream>
#include <opencv2\opencv.hpp>
#include <vector>
#include<stdio.h>
#include <opencv.hpp>
#include <opencv2/core/core.hpp>

using namespace cv;

void Pic2Gray(Mat camerFrame, Mat &gray)
{
	//普通台式机3通道BGR,移动设备为4通道
	if (camerFrame.channels() == 3)
	{
		cvtColor(camerFrame, gray, CV_BGR2GRAY);
	}
	else if (camerFrame.channels() == 4)
	{
		cvtColor(camerFrame, gray, CV_BGRA2GRAY);
	}
	else
		gray = camerFrame;
}


int main()
{
	//加载Haar或LBP对象或人脸检测器
	CascadeClassifier faceDetector;
	std::string faceCascadeFilename = "G:\\CY\\opencv-3.4.3\\build\\install\\etc\\haarcascades\\haarcascade_frontalface_alt2.xml";

	//友好错误信息提示
	try{
		faceDetector.load(faceCascadeFilename);
	}
	catch (cv::Exception e){}
	if (faceDetector.empty())
	{
		std::cerr << "脸部检测器不能加载 (";
		std::cerr << faceCascadeFilename << ")!" << std::endl;
		exit(1);
	}

	//访问摄像机
	VideoCapture camera(0);
	while (true)
	{
		Mat camerFrame;
		camera >> camerFrame;
		if (camerFrame.empty())
		{
			std::cerr << "无法获取摄像头图像" << std::endl;
			getchar();
			exit(1);
		}
		Mat displayedFrame(camerFrame.size(), CV_8UC3);

		//用Harr或LBP检测器检测对象
		//灰度图像转换:人脸检测只适用于灰度图像
		Mat gray;
		Pic2Gray(camerFrame, gray);

		//收缩摄像机图像
		const int DETECTION_WIDTH = 320;
		Mat smallImg;
		float scale = camerFrame.cols / (float)DETECTION_WIDTH;
		if (camerFrame.cols > DETECTION_WIDTH){
			int scaleHeight = cvRound(camerFrame.rows / scale);
			resize(camerFrame, smallImg, Size(DETECTION_WIDTH,scaleHeight));
		}
		else{
			smallImg = camerFrame;
		}

		//直方图均匀化(改善图像的对比度和亮度)
		Mat equalizedImg;
		equalizeHist(gray, equalizedImg);

		//人脸检测用Cascade Classifier::detectMultiScale来进行人脸检测

		int flags = CASCADE_FIND_BIGGEST_OBJECT | CASCADE_DO_ROUGH_SEARCH;	//只检测脸最大的人
		//int flags = CASCADE_SCALE_IMAGE;	//检测多个人
		Size minFeatureSize(30, 30);
		float searchScaleFactor = 1.1f;
		int minNeighbors = 4;
		std::vector<Rect> faces;
		faceDetector.detectMultiScale(equalizedImg, faces, searchScaleFactor, minNeighbors, flags, minFeatureSize);

		//画矩形框
		cv::Mat face;
		cv::Point text_lb;
		for (size_t i = 0; i < faces.size(); i++)
		{
			if (faces[i].height > 0 && faces[i].width > 0)
			{
				face = gray(faces[i]);
				text_lb = cv::Point(faces[i].x, faces[i].y);
				cv::rectangle(equalizedImg, faces[i], cv::Scalar(255, 0, 0), 1, 8, 0);
				cv::rectangle(gray, faces[i], cv::Scalar(255, 0, 0), 1, 8, 0);
				cv::rectangle(camerFrame, faces[i], cv::Scalar(255, 0, 0), 1, 8, 0);
			}
		}


		imshow("直方图均匀化", equalizedImg);
		imshow("灰度化", gray);
		imshow("原图", camerFrame);

		waitKey(20);
	}

	getchar();
	return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值