最近几年AI比较火,而AI中人脸检测算是比较基础的部分。但是人脸检测很多模型以及训练的数据集其实是人脸检测准确率比较低的,所以将一个普通视频转换为带人脸检测效果的视频可以校验模型以及数据集的人脸识别准确率和漏检率等等。
好吧背景说的差不多,现在进入正题。
该怎么做呢?实际上不复杂,就是首先用opencv解析一个视频,拆分成每一帧,然后对每一帧进行人脸检测,检测完画上框,然后再把每一帧合并回去视频,搞定。
那么开始。
第一步,下载opencv,编译出库文件然后使用。很多人觉得编译麻烦,有现成的下载:
https://download.youkuaiyun.com/download/luohualiushui1/10930424
第二步,这次我使用windows环境的vs2015来弄,opencv版本4.0.0
第三步,首先opencv读取一个视频文件
VideoCapture capture("E:\\video\\229728.mp4");
if (!capture.isOpened())
return -1;
好吧,opencv集成很完善,读取就是一行代码
第四步,拆分每一帧
while (!stop)
{
if (!capture.read(frame)){
break;
}
... ...
... ...
}
第五步,人脸检测我使用的是opencv的模型和默认训练好的数据集
cascadeName = "D:\\Virtual Machines\\share\\opencv-4.0.0\\data\\haarcascades\\haarcascade_frontalface_alt.xml";
nestedCascadeName = "D:\\Virtual Machines\\share\\opencv-4.0.0\\data\\haarcascades\\haarcascade_eye_tree_eyeglasses.xml";
scale = 5;
tryflip = false;
if (!nestedCascade.load(samples::findFileOrKeep(nestedCascadeName)))
cerr << "WARNING: Could not load classifier cascade for nested objects" << endl;
if (!cascade.load(samples::findFile(cascadeName)))
{
cerr << "ERROR: Could not load classifier cascade" << endl;
return -1;
}
第六步,检测和画框方法如下:
void detectAndDraw( Mat& img, CascadeClassifier& cascade,
CascadeClassifier& nestedCascade,
double scale, bool tryflip )
{
double t = 0;
vector<Rect> faces, faces2;
const static Scalar colors[] =
{
Scalar(255,0,0),
Scalar(255,128,0),
Scalar(255,255,0),
Scalar(0,255,0),
Scalar(0,128,255),
Scalar(0,255,255),
Scalar(0,0,255),
Scalar(255,0,255)
};
Mat gray, smallImg;
cvtColor( img, gray, COLOR_BGR2GRAY );
double fx = 1 / scale;
resize( gray, smallImg, Size(), fx, fx, INTER_LINEAR_EXACT );
equalizeHist( smallImg, smallImg );
t = (double)getTickCount();
cascade.detectMultiScale( smallImg, faces,
1.1, 2, 0
//|CASCADE_FIND_BIGGEST_OBJECT
//|CASCADE_DO_ROUGH_SEARCH
|CASCADE_SCALE_IMAGE,
Size(30, 30) );
if( tryflip )
{
flip(smallImg, smallImg, 1);
cascade.detectMultiScale( smallImg, faces2,
1.1, 2, 0
//|CASCADE_FIND_BIGGEST_OBJECT
//|CASCADE_DO_ROUGH_SEARCH
|CASCADE_SCALE_IMAGE,
Size(30, 30) );
for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); ++r )
{
faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height));
}
}
t = (double)getTickCount() - t;
printf( "detection time = %g ms\n", t*1000/getTickFrequency());
for ( size_t i = 0; i < faces.size(); i++ )
{
Rect r = faces[i];
Mat smallImgROI;
vector<Rect> nestedObjects;
Point center;
Scalar color = colors[i%8];
int radius;
double aspect_ratio = (double)r.width/r.height;
if( 0.75 < aspect_ratio && aspect_ratio < 1.3 )
{
center.x = cvRound((r.x + r.width*0.5)*scale);
center.y = cvRound((r.y + r.height*0.5)*scale);
radius = cvRound((r.width + r.height)*0.25*scale);
circle( img, center, radius, color, 3, 8, 0 );
}
else
rectangle( img, Point(cvRound(r.x*scale), cvRound(r.y*scale)),
Point(cvRound((r.x + r.width-1)*scale), cvRound((r.y + r.height-1)*scale)),
color, 3, 8, 0);
if( nestedCascade.empty() )
continue;
smallImgROI = smallImg( r );
nestedCascade.detectMultiScale( smallImgROI, nestedObjects,
1.1, 2, 0
//|CASCADE_FIND_BIGGEST_OBJECT
//|CASCADE_DO_ROUGH_SEARCH
//|CASCADE_DO_CANNY_PRUNING
|CASCADE_SCALE_IMAGE,
Size(30, 30) );
for ( size_t j = 0; j < nestedObjects.size(); j++ )
{
Rect nr = nestedObjects[j];
center.x = cvRound((r.x + nr.x + nr.width*0.5)*scale);
center.y = cvRound((r.y + nr.y + nr.height*0.5)*scale);
radius = cvRound((nr.width + nr.height)*0.25*scale);
circle( img, center, radius, color, 3, 8, 0 );
}
}
//imshow( "result", img );
}
第七部,创建新的视频,输出视频的参数我设置为和输入参数一样
const char* fileName = "E:\\video\\229728_1.avi";
cv::VideoWriter out(fileName,
CV_FOURCC('D', 'I', 'V', 'X'),
rate,
cv::Size(capture.get(CAP_PROP_FRAME_WIDTH), capture.get(CAP_PROP_FRAME_HEIGHT)),
true
);
while (!stop)
{
if (!capture.read(frame))
{
break;
}
detectAndDraw(frame, cascade, nestedCascade, scale, tryflip);
out << frame;
//string imgPath = "E:\\img\\";
//imgPath += to_string(currentFrame);
//imgPath += ".jpg";
//imwrite(imgPath, frame);
}
ok,搞定看看效果
视频过程中人脸被检测出来,不过也可以发现有一些误检和漏检的地方。