#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/face.hpp>
//用摄像头获取图像,定位人脸和关键点
//用人脸关键点进行人脸交换
//在人脸区域打上马赛克
void Fun_LandMark()
{
//载入正脸检测模型
//载入人脸关键点检测模型
//打开摄像头
//进入取图循环
//检测图像出现的人脸
//对人脸区域进行关键点提取
//绘制关键点
//显示
//人脸
cv::CascadeClassifier faceCascade;
faceCascade.load("..\\FaceSwap\\haarcascade_frontalface_alt2.xml");
//关键点
cv::Ptr<cv::face::Facemark> facemark = cv::face::FacemarkLBF::create();
facemark->loadModel("..\\FaceSwap\\lbfmodel.yaml");
//摄像头
cv::VideoCapture cap(0);
if (!cap.isOpened())
{
printf("无法打开摄像头!\r\n");
return;
}
//取图
while (1)
{
cv::Mat frame;
cap >> frame;
//检测图像是否存在人脸
cv::Mat detImg;
cv::cvtColor(frame, detImg, cv::COLOR_BGR2GRAY);
std::vector<cv::Rect> faces;
faceCascade.detectMultiScale(detImg, faces, 1.1f, 3, 0, cv::Size(80, 80));
if (!faces.empty())
{
std::vector<std::vector<cv::Point2f>> landmark;
//拟合关键点区域
if (facemark->fit(frame, faces, landmark))
{
for (int i = 0; i < landmark.size(); i++)
{
cv::face::drawFacemarks(frame, landmark[i], cv::Scalar(0, 255, 0));
}
}
//绘制人脸
for (int i = 0; i < faces.size(); i++)
{
cv::rectangle(frame, faces[i], cv::Scalar(0, 0, 255));
printf("人脸%d,位置(%d, %d, %d, %d)\r\n", i, faces[i].x, faces[i].y, faces[i].width, faces[i].height);
}
cv::imshow("face", frame);
}
else
{
printf("不存在人脸!\r\n");
}
//监听ESC按键事件
if (27 == cv::waitKey(10))
break;
}
}
void Fun_FaceSwap()
{
//载入人脸检测模型
//载入关键点检测模型
//载入测试图像
//检测图像中的人脸(两个以上的人脸
//提取人脸关键点
//对这两个人脸进行最小外接矩形拟合
//图像融合,交换两个区域
//显示
//人脸
cv::CascadeClassifier faceCascade;
faceCascade.load("..\\FaceSwap\\haarcascade_frontalface_alt2.xml");
//关键点
cv::Ptr<cv::face::Facemark> facemark = cv::face::FacemarkLBF::create();
facemark->loadModel("..\\FaceSwap\\lbfmodel.yaml");
//图像
cv::Mat img = cv::imread("..\\FaceSwap\\TestPic\\face.jpg", cv::IMREAD_COLOR);
cv::Mat swapImg = img.clone();
//检测图像是否存在人脸
cv::Mat detImg;
cv::cvtColor(img, detImg, cv::COLOR_BGR2GRAY);
std::vector<cv::Rect> faces;
faceCascade.detectMultiScale(detImg, faces, 1.1f, 3, 0, cv::Size(80, 80));
if (!faces.empty())
{
std::vector<std::vector<cv::Point2f>> landmark;
if (facemark->fit(img, faces, landmark))
{
if (landmark.size() >= 2)
{
std::vector<cv::Point> landmark1, landmark2;
for (int i = 0; i < landmark[0].size(); ++i)
{
landmark1.push_back(cv::Point(landmark[0][i].x, landmark[0][i].y));
landmark2.push_back(cv::Point(landmark[1][i].x, landmark[1][i].y));
}
//对点集拟合最小外界矩形
cv::Rect roi1 = cv::boundingRect(landmark1);
cv::Rect roi2 = cv::boundingRect(landmark2);
//交换人脸
cv::Mat mask1 = cv::Mat(img.size(), CV_8UC1, cv::Scalar(0));
cv::Mat mask2 = cv::Mat(img.size(), CV_8UC1, cv::Scalar(0));
cv::rectangle(mask1, roi1, cv::Scalar(255), -1);//线宽-1表示填充
cv::rectangle(mask2, roi2, cv::Scalar(255), -1);//线宽-1表示填充
cv::Mat out1, out2;
cv::Point pt1 = cv::Point(roi1.x + roi1.width / 2, roi1.y + roi1.height / 2);
cv::Point pt2 = cv::Point(roi2.x + roi2.width / 2, roi2.y + roi2.height / 2);
cv::seamlessClone(swapImg, swapImg, mask2, pt1, out1, cv::MIXED_CLONE);
cv::seamlessClone(swapImg, swapImg, mask1, pt2, out2, cv::MIXED_CLONE);
cv::imshow("out1", out1);
cv::imshow("out2", out2);
//cv::seamlessClone
}
/*for (int i = 0; i < landmark.size(); i++)
{
cv::face::drawFacemarks(frame, landmark[i], cv::Scalar(0, 255, 0));
}*/
}
}
cv::imshow("srcImg", img);
cv::waitKey(0);
}
void Fun_FaceMSK()
{
//载入正脸模型
//打开相机
//进入取图流程
//检测人脸
//对人脸进行马赛克处理
//显示
//人脸
cv::CascadeClassifier faceCascade;
faceCascade.load("..\\FaceSwap\\haarcascade_frontalface_alt2.xml");
//相机
cv::VideoCapture cap(0);
if (!cap.isOpened())
{
printf("无法打开摄像头!\r\n");
return;
}
//取图
while (1)
{
cv::Mat frame;
cap >> frame;
//检测图像是否存在人脸
cv::Mat detImg;
cv::cvtColor(frame, detImg, cv::COLOR_BGR2GRAY);
std::vector<cv::Rect> faces;
faceCascade.detectMultiScale(detImg, faces, 1.1f, 3, 0, cv::Size(80, 80));
printf("已对图像检测人脸是否存在...\r\n");
if (!faces.empty())
{
printf("当前存在人脸...\r\n");
//马赛克
int step = 10;
for (int i = 0; i < faces.size(); ++i)
{
cv::rectangle(frame, faces[i], cv::Scalar(0, 0, 255));
//人脸信息提取
int x = faces[i].x;
int y = faces[i].y;
int width = faces[i].width;
int height = faces[i].height;
printf("第%d个人脸,ROI信息(%d,%d,%d,%d)...\r\n", x, y, width, height);
//只对人脸区域进行处理
//每次只对10*10区域进行处理
for (int r = y; r < (y + height); r += step)//高
{
for (int c = x; c < (x + width); c += step)//宽
{
//进入区域位置
for (int k = r; k < (step + r); k++)
{
for (int m = c; m < (step + c); m++)
for (int d = 0; d < 3; d++)
{
//该10*10区域的每个像素的每个通道值,都等于左上角像素的值
frame.at<cv::Vec3b>(k, m)[d] = frame.at<cv::Vec3b>(r, c)[d];//d表示对应通道的索引
}
}
}
}
}
printf("已对人脸添加马赛克...\r\n");
}
cv::imshow("MSK", frame);
if (27 == cv::waitKey(10))
break;
}
}
int mainFaceMark()
{
//Fun_LandMark();
//Fun_FaceSwap();
Fun_FaceMSK();
return 0;
}