人脸检测并打码的关键,首先需要定位人脸区域,再修改人脸区域像素灰度值。
定义生成马赛克函数 Generate_Mosaic,对图形 Mat& src 做操作,将需要操作的块(faces)存入数组 vector
src:代表马赛克效果的图片; faces:显示马赛克的区域; Rect:矩形区域(x,y,w,h)
马赛克函数思想过程:定义马赛克大小为10像素,int step = 10。for (int t = 0; t < faces.size(); t++) 对每一张脸进行马赛克操作。再确定 faces 所在区域(x, y, w, h),然后针对 faces 所在进行马赛克处理。10像素的矩形遍历人脸矩形框区域像素,再将矩形框细分成若干个小方块,依次修改每个方块的像素,相同方块赋予相同灰度值。
src.at
bool Generate_Mosaic(Mat& src, vector& faces)
{
if (faces.empty())return false;
int step = 10;//步长
for (int t = 0; t < faces.size(); t++)
{
int x = faces[t].tl().x; //人脸矩形框起点x坐标
int y = faces[t].tl().y;//人脸矩形框起点y坐标
int width = faces[t].width;//人脸矩形框宽
int height = faces[t].height;//人脸矩形框高
//仅对人脸区域进行像素修改。遍历人脸矩形框区域像素,并对其进行修改
for (int i = y; i < (y + height); i += step)
{
for (int j = x; j < (x + width); j += step)
{
//将人脸矩形框再细分为若干个小方块,依次对每个方块修改像素(相同方块赋予相同灰度值)
for (int k = i; k < (step + i); k++)
{
for (int m = j; m < (step + j); m++)
{
//对矩形区域像素值进行修改,rgb三通道
for (int c = 0; c < 3; c++)
{
src.at(k, m)[c] = src.at(i, j)[c];
}
}
}
}
}
}
return true;
}
定义单张图片打码函数 Picture_Demo,将图片 Mat src 传入函数。首先加载人脸检测配置文件。在 OpenCV 中,人脸检测用的是 harr 或 LBP 特征,分类算法用的是 adaboost 算法。这种算法需要提前训练大量的图片,非常耗时,因此 OpenCV 已经训练好了,把训练结果存放在一些 xml 文件里面。然后创建人脸检测器并存储人脸检测的结果,人脸检测主要用到的是 CascadeClassifier 这个类,以及该类下的 detectMultiScale 函数。
detector.detectMultiScale(src, faces, 1.1, 5),src 检测的图片,faces 存储的结果,1.1 缩放尺寸
bool Picture_Demo(Mat src)
{
//人脸检测配置文件
string harr_file = "haarcascade_frontalface_default.xml";
//创建人脸检测器
CascadeClassifier detector;
detector.load(harr_file);
//人脸检测,存储人脸检测的结果
vectorfaces;
detector.detectMultiScale(src, faces, 1.1, 5);
if (!Generate_Mosaic(src, faces))return false;
imshow("test", src);
waitKey(0);
return true;
}
视频主要涉及视频的读取以及视频的保存
//把视频转图像操作
void VideoToImg()
{
VideoCapture cap = VideoCapture("视频路径"); //创建一个对象cap,打开一个视频,若参数设为0则为打开默认摄像头
if(!cap.isOpened())
{
cout << "打开失败。。。" << endl;
return;
}
// 如果成功开打,视频的每一帧都在对象cap中
Mat img; //定义图片
int i = 1;
while (true) //用流的方式将图片导出来
{
cap >> img; //拿出一帧
if (img.empty())
break;
imshow("img", img); //显示图片
string URL = "data/img" + to_string(i) + ".jpg"; //定义图片存储路径 data/img0.jpg
imwrite(URL, img); //把图片写入文件
waitKey(30); //延迟30ms
i++;
}
return;
}
打开摄像头,获取每一帧图片并显示在窗口上。
//打开摄像头
void VideoToImg()
{
VideoCapture cap = VideoCapture(0); //创建一个对象cap,打开一个视频,若参数设为0则为打开默认摄像头
if (!cap.isOpened())
{
cout << "打开失败。。。" << endl;
return;
}
// 如果成功开打,视频的每一帧都在对象cap中
Mat img; //定义图片
while (true) //用流的方式将图片导出来
{
cap >> img; //拿出一帧
if (img.empty())
break;
imshow("img", img); //显示图片
char userKey = waitKey(10);
if (userKey == 27) //如果userkey为esc键,退出循环
break;
}
return;
}
将摄像头捕获的视频分成每一帧,将每帧保存为一张图片,再使用马赛克函数完成打码操作。
其中加载人脸检测配置文件、创建人脸检测器及保存人脸检测结果与单张图片做马赛克相同。
flip(frame, frame, 1) 用filp切割视频,一帧一帧的拿出来
bool Video_Demo()
{
//人脸检测配置文件
string harr_file = "haarcascade_frontalface_default.xml";
//创建人脸检测器
CascadeClassifier detector;
detector.load(harr_file);
VideoCapture cap;
cap.open(0);
if (!cap.isOpened())
{
cout << "can not open the camera!" << endl;
}
Mat frame;
while (cap.read(frame))
{
flip(frame, frame, 1); //函数的方式取出帧
//人脸检测
vectorfaces;
detector.detectMultiScale(frame, faces, 1.1, 5);
if (Generate_Mosaic(frame, faces))
{
imshow("Demo", frame);
}
char key = waitKey(10);
if (key == 27)break;
}
cap.release();
return true;
}
#include
#include
using namespace std;
using namespace cv;
bool Generate_Mosaic(Mat& src, vector& faces)
{
if (faces.empty())return false;
int step = 10;//步长
for (int t = 0; t < faces.size(); t++)
{
int x = faces[t].tl().x; //人脸矩形框起点x坐标
int y = faces[t].tl().y;//人脸矩形框起点y坐标
int width = faces[t].width;//人脸矩形框宽
int height = faces[t].height;//人脸矩形框高
//仅对人脸区域进行像素修改。遍历人脸矩形框区域像素,并对其进行修改
for (int i = y; i < (y + height); i += step)
{
for (int j = x; j < (x + width); j += step)
{
//将人脸矩形框再细分为若干个小方块,依次对每个方块修改像素(相同方块赋予相同灰度值)
for (int k = i; k < (step + i); k++)
{
for (int m = j; m < (step + j); m++)
{
//对矩形区域像素值进行修改,rgb三通道
for (int c = 0; c < 3; c++)
{
src.at(k, m)[c] = src.at(i, j)[c];
}
}
}
}
}
}
return true;
}
/*
void TestMosaic(Mat& src)
{
vector faces;
faces.push_back(Rect(100, 100, 200, 200));
faces.push_back(Rect(300, 300, 200, 200));
Generate_Mosaic(src, faces);
}
*/
//对单张图片打马赛克
bool Picture_Demo(Mat src)
{
//人脸检测配置文件
string harr_file = "haarcascade_frontalface_default.xml";
//创建人脸检测器
CascadeClassifier detector;
detector.load(harr_file);
//人脸检测,存储人脸检测的结果
vectorfaces;
detector.detectMultiScale(src, faces, 1.1, 5);
if (!Generate_Mosaic(src, faces))return false;
imshow("test", src);
waitKey(0);
return true;
}
//把视频转图像操作
void VideoToImg()
{
VideoCapture cap = VideoCapture("视频路径"); //创建一个对象cap,打开一个视频,若参数设为0则为打开默认摄像头
if(!cap.isOpened())
{
cout << "打开失败。。。" << endl;
return;
}
// 如果成功开打,视频的每一帧都在对象cap中
Mat img; //定义图片
int i = 1;
while (true) //用流的方式将图片导出来
{
cap >> img; //拿出一帧
if (img.empty())
break;
imshow("img", img); //显示图片
string URL = "data/img" + to_string(i) + ".jpg"; //定义图片存储路径 data/img0.jpg
imwrite(URL, img); //把图片写入文件
waitKey(30); //延迟30ms
i++;
}
return;
}
/*
//打开摄像头,并在窗口上显示每一帧图片
void VideoToImg()
{
VideoCapture cap = VideoCapture(0); //创建一个对象cap,打开一个视频,若参数设为0则为打开默认摄像头
if (!cap.isOpened())
{
cout << "打开失败。。。" << endl;
return;
}
// 如果成功开打,视频的每一帧都在对象cap中
Mat img; //定义图片
while (true) //用流的方式将图片导出来
{
cap >> img; //拿出一帧
if (img.empty())
break;
imshow("img", img); //显示图片
char userKey = waitKey(10);
if (userKey == 27) //如果userkey为esc键,退出循环
break;
}
return;
}
*/
//对视频打马赛克
bool Video_Demo()
{
//人脸检测配置文件
string harr_file = "haarcascade_frontalface_default.xml";
//创建人脸检测器
CascadeClassifier detector;
detector.load(harr_file);
VideoCapture cap;
cap.open(0);
if (!cap.isOpened())
{
cout << "can not open the camera!" << endl;
}
Mat frame;
while (cap.read(frame))
{
flip(frame, frame, 1);
//人脸检测
vectorfaces;
detector.detectMultiScale(frame, faces, 1.1, 5);
if (Generate_Mosaic(frame, faces))
{
imshow("Demo", frame);
}
char key = waitKey(10);
if (key == 27)break;
}
cap.release();
return true;
}
int main()
{
Mat src = imread("图片路径");
if (src.empty())
{
cout << "No Image!" << endl;
system("pause");
return -1;
}
//TestMosaic(src);
Picture_Demo(src);
//Video_Demo();
system("pause");
return 0;
}