温馨提示:本博文支持opencv-2.4及opencv-3.4版本,可通过宏 VERSION_2_4 控制。
上一篇文章只是简单地实现了图片与视频流的人脸检测,但这只是采用一种简单粗暴的方式,从效果上来看,视频检测卡顿问题较严重。这次主要针对该问题进行优化。
一、未作优化版本的程序
首先,摆上简单粗暴的opencv打开摄像头检测人脸的代码:
#include "opencv2/objdetect.hpp" #include "opencv2/highgui.hpp" #include "opencv2/imgproc.hpp" #include <iostream> #include <stdio.h> using namespace cv; using namespace std; // 控制编译版本宏 //#define VERSION_2_4 int main() { CascadeClassifier faceCascade; double t = 0; int nRet = 0; VideoCapture capture; capture.open(0); // capture.open("video.avi"); if(!capture.isOpened()) { cout << "open camera failed. " << endl; return -1; } /* 加载分类器 */ #ifdef VERSION_2_4 nRet = faceCascade.load("/root/library/opencv/opencv-2.4.13.6/data/haarcascades/haarcascade_frontalface_alt.xml"); #else nRet = faceCascade.load("/root/library/opencv/opencv-3.4.0/data/haarcascades/haarcascade_frontalface_alt.xml"); #endif if(!nRet) { printf("load xml failed.\n"); return -1; } Mat img, imgGray; vector<Rect> faces; while(1) { capture >> img; if(img.empty()) { continue; } cvtColor(img, imgGray, CV_RGB2GRAY); /* 检测人脸 */ t = (double)getTickCount(); faceCascade.detectMultiScale( imgGray, faces, 1.1, 2, 0 //|CASCADE_FIND_BIGGEST_OBJECT //|CASCADE_DO_ROUGH_SEARCH |CASCADE_SCALE_IMAGE, Size(30, 30) ); t = (double)getTickCount() - t; printf( "detection time = %g ms\n", t*1000/getTickFrequency()); /* 画矩形框出人脸 */ for(size_t i =0; i<faces.size(); i++) { rectangle(img, Point(faces[i].x, faces[i].y), Point(faces[i].x + faces[i].width, faces[i].y + faces[i].height), Scalar(0, 255, 0), 1, 8); } imshow("CameraFace", img); if(waitKey(1) > 0) // delay ms 等待按键退出 { break; } } return 0; }
运行效果(人脸图像就不贴出来了):
detection time = 278.65 ms detection time = 280.025 ms detection time = 280.809 ms detection time = 289.129 ms detection time = 279.903 ms detection time = 281.969 ms
二、优化处理
第三方库的使用,最权威的教程当属官方文档,opencv也一样。
所以,先参考/看懂官方的人脸检测例程:
官网: https://docs.opencv.org/3.4.0/db/d3a/facedetect_8cpp-example.html
库源码: opencv-3.4.0/samples/cpp/facedetect.cpp
官方示例主要对图像作以下处理:
1、缩放图像,可提高检测速率,减少检测时间
void cv::resize( InputArray _src, OutputArray _dst, Size dsize, double inv_scale_x, double inv_scale_y, int interpolation )
2、直方图均衡化,可提高图像质量
void equalizeHist(const oclMat &mat_src, oclMat &mat_dst)
本程序也主要作以上优化处理(能力有限,希望后续能有更多优化)
优化后的程序:
#include "opencv2/objdetect.hpp" #include "opencv2/highgui.hpp" #include "opencv2/imgproc.hpp" #include <iostream> #include <stdio.h> using namespace cv; using namespace std; // 控制编译版本宏 //#define VERSION_2_4 /* 参数 : 输入图像、级联分类器、缩放倍数 */ void DetectAndDraw( Mat& img, CascadeClassifier& cascade, double scale); int main() { CascadeClassifier faceCascade; double scale = 4; int nRet = 0; VideoCapture capture; capture.open(0); // capture.open("video.avi"); if(!capture.isOpened()) { cout << "open camera failed. " << endl; return -1; } cout << "open camera succeed. " << endl; /* 加载分类器 */ #ifdef VERSION_2_4 nRet = faceCascade.load("/root/library/opencv/opencv-2.4.13.6/data/haarcascades/haarcascade_frontalface_alt.xml"); #else nRet = faceCascade.load("/root/library/opencv/opencv-3.4.0/data/haarcascades/haarcascade_frontalface_alt.xml"); #endif if(!nRet) { printf("load xml failed.\n"); return -1; } Mat frame; vector<Rect> faces; while(1) { capture >> frame; if(frame.empty()) { continue; } Mat frame1 = frame.clone(); DetectAndDraw( frame1, faceCascade, scale ); if(waitKey(1) > 0) // delay ms 等待按键退出 { break; } } return 0; } void DetectAndDraw( Mat& img, CascadeClassifier& cascade, double scale ) { double t = 0; vector<Rect> faces; Mat gray, smallImg; double fx = 1 / scale; cvtColor( img, gray, COLOR_BGR2GRAY ); // 将源图像转为灰度图 /* 缩放图像 */ #ifdef VERSION_2_4 resize( gray, smallImg, Size(), fx, fx, INTER_LINEAR ); #else resize( gray, smallImg, Size(), fx, fx, INTER_LINEAR_EXACT ); #endif 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) ); t = (double)getTickCount() - t; printf( "detection time = %g ms\n", t*1000/getTickFrequency()); /* 画矩形框出目标 */ for ( size_t i = 0; i < faces.size(); i++ ) // faces.size():检测到的目标数量 { Rect rectFace = faces[i]; rectangle( img, Point(rectFace.x, rectFace.y) * scale, Point(rectFace.x + rectFace.width, rectFace.y + rectFace.height) * scale, Scalar(0, 255, 0), 2, 8); } imshow( "FaceDetect", img ); // 显示 }
运行效果:
detection time = 23.5718 ms detection time = 27.5776 ms detection time = 22.7952 ms detection time = 31.5242 ms detection time = 39.568 ms detection time = 31.5325 ms
可以看到,检测速度提高了10倍左右,视频卡顿效果也基本消除了。