opencv视频流(摄像头)的人脸检测的优化

温馨提示:本博文支持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倍左右,视频卡顿效果也基本消除了。


猜你喜欢

转载自blog.csdn.net/qq_30155503/article/details/79637231