openCV学习笔记(十) —— 人脸检测之面部特征(眼睛 鼻子 嘴巴)

首先给大家推荐一下我老师大神的人工智能教学网站。教学不仅零基础,通俗易懂,而且非常风趣幽默,还时不时有内涵黄段子!点这里可以跳转到网站

环境:VS2017

版本:3.4.1

人脸面部特征检测的准确性依赖于学习到的分类器。

分类器可以从以下地址下载:https://github.com/opencv/opencv_contrib/tree/master/modules/face/data/cascades

也可以从下载contrib模块,从以下路径获得:opencv_contrib_3.4.1\modules\face\data\cascades

程序

/*
	人脸面部检测:人脸、眼睛、鼻子、嘴
	检测的准确度依赖于分类器
*/

#include <opencv2/objdetect.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

#include <iostream>
#include <vector>

using namespace std;
using namespace cv;

void detectFaces(Mat &img, vector<Rect> &faces, string cascade_path);
void detectFacialFeatures(Mat &img, vector<Rect> faces, string eye_cascade, string nose_cascade, string mouth_cascade);
void detectEyes(Mat &img, vector<Rect> &eyes, string cascade_path);
void detectNose(Mat &img, vector<Rect> &nose, string cascade_path);
void detectMouth(Mat &img, vector<Rect> &mouth, string cascade_path);

int main()
{
	string input_image_path = "test1.jpg";
	string face_cascade_path = ".\\cascade\\haarcascades\\haarcascade_frontalface_default.xml";
	string eye_cascade_path = ".\\cascade\\haarcascades\\haarcascade_eye.xml";
	string nose_cascade_path = ".\\cascade\\haarcascades\\haarcascade_mcs_nose.xml";
	string mouth_cascade_path = ".\\cascade\\haarcascades\\haarcascade_mcs_mouth.xml";

	Mat img, imgGray;
	img = imread(input_image_path);
	if (img.empty())
	{
		printf("can't open image\n");
		return -1;
	}

	cvtColor(img, imgGray, CV_BGR2GRAY);	//转换成灰度图来加快人脸识别的速度
	equalizeHist(imgGray, imgGray);		//直方图均衡化

	//检测人脸和面部特征
	vector<Rect> faces;
	detectFaces(img, faces, face_cascade_path);
	detectFacialFeatures(img, faces, eye_cascade_path, nose_cascade_path, mouth_cascade_path);

	imshow("Result", img);

	waitKey(0);
	destroyAllWindows();

	return 0;
}

void detectFaces(Mat &img, vector<Rect> &faces, string cascade_path)
{
	CascadeClassifier face_cascade;

	face_cascade.load(cascade_path);
	if (face_cascade.empty())
	{
		printf("can't load face cascade file\n");
		return;
	}

	face_cascade.detectMultiScale(img, faces, 1.1, 3, 0, Size(30, 30));
	return;
}

void detectFacialFeatures(Mat &img, vector<Rect> faces, string eye_cascade, string nose_cascade, string mouth_cascade)
{
	printf("face_size = %zd\n", faces.size());

	for (int i = 0; i < faces.size(); i++)
	{
		Rect face = faces[i];
		rectangle(img, Point(face.x, face.y), Point(face.x + face.width, face.y + face.height), Scalar(255, 0, 0), 2, 4);

		//眼睛、鼻子和嘴巴将在脸部(感兴趣的区域)被检测到。
		Mat ROI = img(Rect(face.x, face.y, face.width, face.height));

		//检测眼睛、鼻子和嘴巴是否全部被检测到
		bool is_full_detection = false;
		if ((!eye_cascade.empty()) && (!nose_cascade.empty()) && (!mouth_cascade.empty()))
		{
			is_full_detection = true;
		}

		//用户提供的分类器可以检测眼睛
		if (!eye_cascade.empty())
		{
			vector<Rect> eyes;
			detectEyes(ROI, eyes, eye_cascade);

			//标记点与眼睛的中心相对应
			printf("eyes_size = %zd\n", eyes.size());
			for (int i = 0; i < eyes.size(); i++)
			{
				Rect e = eyes[i];
				circle(ROI, Point(e.x + e.width / 2, e.y + e.height / 2), 3, Scalar(0, 255, 0), -1, 8);
				//rectangle(ROI, Point(e.x, e.y), Point(e.x + e.width, e.y + e.height), Scalar(0, 255, 0), -1, 8);
			}
		}

		//用户提供的分类器可以检测鼻子
		double nose_center_height = 0;
		if (!nose_cascade.empty())
		{
			vector <Rect> nose;
			detectNose(ROI, nose, nose_cascade);

			//标记点与鼻子的中心相对应
			printf("nose_size = %zd\n", nose.size());
			for (int i = 0; i < nose.size(); i++)
			{
				Rect n = nose[i];
				circle(ROI, Point(n.x + n.width / 2, n.y + n.height / 2), 3, Scalar(0, 255, 0), -1, 8);
				nose_center_height = (n.y + n.height / 2);

			}
		}

		//用户提供的分类器可以检测嘴巴
		double mouth_center_height = 0;
		if (!mouth_cascade.empty())
		{
			vector<Rect> mouth;
			detectMouth(ROI, mouth, mouth_cascade);

			printf("mouth.size = %zd\n", mouth.size());
			for (int i = 0; i < mouth.size(); i++)
			{
				Rect m = mouth[i];
				mouth_center_height = (m.y + m.height / 2);

				if (is_full_detection && (mouth_center_height > nose_center_height))
				{
					rectangle(ROI, Point(m.x, m.y), Point(m.x + m.width, m.y + m.height), Scalar(0, 255, 0), 1, 4);
				}
				else if (is_full_detection && (mouth_center_height <= nose_center_height))
				{
					continue;
				}
				else
				{
					rectangle(ROI, Point(m.x, m.y), Point(m.x + m.width, m.y + m.height), Scalar(0, 255, 0), 1, 4);
				}
			}
		}
	}

	return;
}

void detectEyes(Mat &img, vector<Rect> &eyes, string cascade_path)
{
	CascadeClassifier eyes_cascade;

	eyes_cascade.load(cascade_path);
	
	eyes_cascade.detectMultiScale(img, eyes, 1.20, 5, 0, Size(30, 30));

	return;
}

void detectNose(Mat &img, vector<Rect> &nose, string cascade_path)
{
	CascadeClassifier nose_cascade;

	nose_cascade.load(cascade_path);

	nose_cascade.detectMultiScale(img, nose, 1.20, 5, 0, Size(30, 30));

	return;
}

void detectMouth(Mat &img, vector<Rect> &mouth, string cascade_path)
{
	CascadeClassifier mouth_cascade;

	mouth_cascade.load(cascade_path);

	mouth_cascade.detectMultiScale(img, mouth, 1.20, 5, 0, Size(30, 30));

	return;
}

运行结果

从运行结果来看,嘴巴的检测不够准确。

点这里可以跳转到人工智能网站

发表评论