主要按照以下三步完成,初学者找资料随便整的。
#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