使用OpenCV检测人脸并进行倾斜人脸的矫正

使用OpenCV检测人脸并进行倾斜人脸的矫正

主要按照以下三步完成,初学者找资料随便整的。

1:人脸检测

2:人眼检测

2:基于人眼位置矫正图片

#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include 
#include 

using namespace std;
using namespace cv;

#define PI acos(-1)
#define ANGLE_ROT  180/acos(-1)
//宏定义不能用等号
/** Function Headers */
void detectAndDisplay(Mat frame);

/** Global variables */
CascadeClassifier face_cascade;
CascadeClassifier eyes_cascade;

/** @function main */
int main()
{
	if (!face_cascade.load("E:/opencv/opencv/build/etc/haarcascades/haarcascade_frontalface_alt.xml")) //opencv自带的人脸识别
	{
		cout << "--(!)Error loading face cascade\n";
		return -1;
	};
	if (!eyes_cascade.load("E:/opencv/opencv/build/etc/haarcascades/haarcascade_eye_tree_eyeglasses.xml"))
	{
		cout << "--(!)Error loading eyes cascade\n";
		return -1;
	};
	Mat frame = imread("E:/User/Schoolshop/模式识别/大作业/Boys.jpg");//输入图片
	if (frame.empty())
	{
		cout << " wrong" << endl;
	}
	namedWindow("Face", 0);
	imshow("Face", frame);
	waitKey(0);

	detectAndDisplay(frame);
	return 0;
}
/** @function detectAndDisplay */
void detectAndDisplay(Mat frame)
{
	Mat frame_gray;
	Mat faceROC;
	//Point diff;
	cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
	equalizeHist(frame_gray, frame_gray);
	//-- Detect faces
	std::vector<Rect> faces;
	face_cascade.detectMultiScale(frame_gray, faces);
	for (size_t i = 0; i < faces.size(); i++)
	{
		//使用椭圆标记人脸
		//Point center(faces[i].x + faces[i].width / 2, faces[i].y + faces[i].height / 2);
		//ellipse(frame, center, Size(faces[i].width / 2, faces[i].height / 2), 0, 0, 360, Scalar(255, 0, 255), 4);
		//使用方框标记人脸
		Rect rect = Rect(faces[i].x, faces[i].y, faces[i].width, faces[i].height);
		cv::rectangle(frame, rect, Scalar(255, 0, 0), 1, LINE_8, 0);
		Mat faceROI = frame_gray(faces[i]);
		//-- In each face, detect eyes
		std::vector<Rect> eyes;
		eyes_cascade.detectMultiScale(faceROI, eyes);
		std::vector<cv::Point> eye_center(2);
		for (size_t j = 0; j < eyes.size(); j++)
		{
			
			eye_center[j]= Point(faces[i].x + eyes[j].x + eyes[j].width / 2,
				faces[i].y + eyes[j].y + eyes[j].height / 2);

			int radius = cvRound((eyes[j].width + eyes[j].height)*0.25);
			circle(frame, eye_center[j], radius, Scalar(255, 0, 0), 4);
		}

		//确定两眼中心的位置
		//两眼中心在原始图像中的位置
		Point eye_centers = (eye_center[0] + eye_center[1]) / 2;
		//因为后面要对检测出来的人脸基于眼睛中心进行旋转,此处得到其位置
		Point center_actual = Point(eye_centers.x - faces[i].x, eye_centers.x - faces[i].y);
		//为了将两眼对齐需要计算的角度,写的比较幼稚,能用,哈哈
		Point diff = eye_centers - eye_center[0];
		double degree = atan2(diff.y, diff.x)*ANGLE_ROT;//diff.y / diff.x;
		if (eye_center[0].x < eye_center[1].x)
			degree = degree;
		else
			degree = degree-180;
		//旋转这儿比较经验,由于图像本身y是从上到下递增的,所以和直观的感觉相反。就是直观上的tan为正,但算出来是负数,而且在旋转时,正为逆时针
		//正好合适,但注意的一点是,atan2是有pi以上的值得,此处需要减去180

		Mat roate = cv::getRotationMatrix2D(center_actual, degree, 1);
		cv::Size dst_sz(faces[i].width, faces[i].height);

		//Mat face_correct;
		cv::warpAffine(faceROI, faceROC,roate, dst_sz, cv::INTER_LINEAR, cv::BORDER_REPLICATE);
		//输出直接在参数列表里面,该函数不能采用=赋值的操作
		//在文献[1]中,作者进行了切割,下面是大概的实现
		/*
		double dis_eyes = 2 * sqrt(pow(diff.x, 2) + pow(diff.y, 2));
		Point Cut_begin(center_actual.x - 0.9*dis_eyes, center_actual.y- 0.9*dis_eyes);
		Rect rect_cut = cv::Rect(center_actual.x-0.9*dis_eyes, center_actual.y - 0.5*dis_eyes, 0.8*dis_eyes, 0.8*dis_eyes);
		faceROC = faceROC(rect_cut);
		*/

	}
	imwrite("E:/User/Schoolshop/模式识别/大作业/datasetBoys.bmp", faceROC);
	//人脸检测的结果
	namedWindow("Face detection", 0);
	imshow("Face detection", frame);
	waitKey(0);
	//展示切割后的图片
	namedWindow("Face Cut", 0);
	imshow("Face Cut", faceROC);
	waitKey(0);

}

实验中遇到的问题:
主要是自己基础的问题吧。
1:宏定义里面加了等号,出现了BUG
2:旋转中心的问题,第一次直接使用了人眼中心在face中的位置,看起来有效果,图片是被弄正了,我想这挺神奇的,后面仔细想想不对劲,将中心改了回来(代码里面第二个)
3:vector的初始化为大小,还有一些opencv函数的使用,自己都是在csdn上现查的,感谢各位大佬。

不规范的参考文献,大家能找到就行
[1]基于OpenCV人眼定位的人脸检测方法,汪明明1,2林小竹2
[2]https://blog.csdn.net/timbrist/article/details/100985957

你可能感兴趣的:(Mini,PROJECT,opencv,计算机视觉,人工智能)