Object Recognition and Scene Understanding(五)OpenCV中peopledetect详细介绍

opencv2以后加入了hog相关的内容,并且给出了示例,用的是法国人Navneet Dalal最早在CVPR2005会议上提出的方法。

先是使用HOG进行People Detection的,已经提供了完整的方法,在peopledetect.cpp中,主要的方法有HOG特征提取以及训练还有识别,你可以通过 hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());用已经训练好的模型直接检测。用hog.detectMultiScale...)进行检测。

 

1.程序说明

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"

#include <stdio.h>
#include <string.h>
#include <ctype.h>

using namespace cv;
using namespace std;

//const char* image_filename = "people.jpg";
const char* image_filename = "./../2.jpg";

void help()
{
	printf(
			"\nDemonstrate the use of the HoG descriptor using\n"
			"  HOGDescriptor::hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());\n"
			"Usage:\n"
			"./peopledetect (<image_filename> | <image_list>.txt)\n\n");
}

int main(int argc, char** argv)
{
    Mat img;
    FILE* f = 0;
    char _filename[1024];

    if( argc == 1 )
    {
        printf("Usage: peopledetect (<image_filename> | <image_list>.txt)\n");
        //return 0;
    }

	if (argc >1)
	{
		image_filename = argv[1];
	}

    img = imread(image_filename);
	if (!img.data)
	{
		printf( "Unable to load the image\n"
                "Pass it as the first parameter: hogpeopledetect <path to people.jpg> \n" );
		return -1;
	}

    if( img.data )
    {
	    strcpy(_filename, image_filename);
    }
    else
    {
        f = fopen(argv[1], "rt");
        if(!f)
        {
		    fprintf( stderr, "ERROR: the specified file could not be loaded\n");
		    return -1;
	    }
    }

    HOGDescriptor hog;
    hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());
    namedWindow("people detector", 1);

    for(;;)
    {
	    char* filename = _filename;
	    if(f)
	    {
		    if(!fgets(filename, (int)sizeof(_filename)-2, f))
			    break;
		    //while(*filename && isspace(*filename))
		    //	++filename;
		    if(filename[0] == '#')
			    continue;
		    int l = strlen(filename);
		    while(l > 0 && isspace(filename[l-1]))
			    --l;
		    filename[l] = '\0';
		    img = imread(filename);
	    }
	    printf("%s:\n", filename);
	    if(!img.data)
		    continue;
		
	    fflush(stdout);
	    vector<Rect> found, found_filtered;
	    double t = (double)getTickCount();
	    // run the detector with default parameters. to get a higher hit-rate
	    // (and more false alarms, respectively), decrease the hitThreshold and
	    // groupThreshold (set groupThreshold to 0 to turn off the grouping completely).
	    hog.detectMultiScale(img, found, 0, Size(8,8), Size(32,32), 1.05, 2);
	    t = (double)getTickCount() - t;
	    printf("tdetection time = %gms\n", t*1000./cv::getTickFrequency());
	    size_t i, j;
	    for( i = 0; i < found.size(); i++ )
	    {
		    Rect r = found[i];
		    for( j = 0; j < found.size(); j++ )
			    if( j != i && (r & found[j]) == r)
				    break;
		    if( j == found.size() )
			    found_filtered.push_back(r);
	    }
	    for( i = 0; i < found_filtered.size(); i++ )
	    {
		    Rect r = found_filtered[i];
		    // the HOG detector returns slightly larger rectangles than the real objects.
		    // so we slightly shrink the rectangles to get a nicer output.
		    r.x += cvRound(r.width*0.1);
		    r.width = cvRound(r.width*0.8);
		    r.y += cvRound(r.height*0.07);
		    r.height = cvRound(r.height*0.8);
		    rectangle(img, r.tl(), r.br(), cv::Scalar(0,255,0), 3);
	    }
	    imshow("people detector", img);
	    int c = waitKey(0) & 255;
	    if( c == 'q' || c == 'Q' || !f)
            break;
    }
    if(f)
        fclose(f);
    return 0;
}


 

 程序代码简要说明
1) getDefaultPeopleDetector() 获得3780维检测算子(105 blocks with 4 histograms each and 9 bins per histogram there are 3,780 values)
2).cv::HOGDescriptor hog; 创建类的对象 一系列变量初始化  
winSize(64,128), blockSize(16,16), blockStride(8,8),
cellSize(8,8), nbins(9), derivAperture(1), winSigma(-1),
histogramNormType(L2Hys), L2HysThreshold(0.2), gammaCorrection(true)

3). 调用函数:detectMultiScale(img, found, 0, cv::Size(8,8), cv::Size(24,16), 1.05, 2); 
  参数分别为待检图像、返回结果列表、门槛值hitThreshold、窗口步长winStride、图像padding margin、比例系数、门槛值groupThreshold;通过修改参数发现,就所用的某图片,参数0改为0.01就检测不到,改为0.001可以;1.05改为1.1就不行,1.06可以;2改为1可以,0.8以下不行,(24,16)改成(0,0)也可以,(32,32)也行

该函数内容如下
   (1) 得到层数 levels 
某图片(530,402)为例,lg(402/128)/lg1.05=23.4 则得到层数为24
 (2) 循环levels次,每次执行内容如下
HOGThreadData& tdata = threadData[getThreadNum()];
Mat smallerImg(sz, img.type(), tdata.smallerImgBuf.data);
    调用以下核心函数
detect(smallerImg, tdata.locations, hitThreshold, winStride, padding);
其参数分别为,该比例下图像、返回结果列表、门槛值、步长、margin
该函数内容如下:
(a)得到补齐图像尺寸paddedImgSize
(b)创建类的对象 HOGCache cache(this, img, padding, padding, nwindows == 0, cacheStride); 在创建过程中,首先初始化 HOGCache::init,包括:计算梯度 descriptor->computeGradient、得到块的个数105、每块参数个数36 
(c)获得窗口个数nwindows,以第一层为例,其窗口数为(530+32*2-64)/8+1、(402+32*2-128)/8+1 =67*43=2881,其中(32,32)为winStride参数,也可用(24,16)
(d)在每个窗口执行循环,内容如下
在105个块中执行循环,每个块内容为:通过getblock函数计算HOG特征并归一化,36个数分别与算子中对应数进行相应运算;判断105个块的总和 s >= hitThreshold 则认为检测到目标 
4)主体部分就是以上这些,但很多细节还需要进一步弄清。

详细的步骤说明看作者的论文吧。 

2.存在的误区

OpenCV自带的分类器是利用Navneet Dalal和Bill Triggs提供的样本进行训练的,不见得能适用于你的应用场合。因此,针对你的特定应用场景,很有必要进行重新训练得到适合你的分类器。

在上一个专题中()曾经提到利用SVM训练样本得到分类器并且可以保存成XML文件

svm.train( data_mat, res_mat, Mat(), Mat(), param );      
 //☆☆利用训练数据和确定的学习参数,进行SVM学习☆☆☆☆       
svm.save( "E:/apple/SVM_DATA.xml" );  

 

那这些文件是否可以直接利用去检测目标呢?

HOGDescriptor hog1;
hog1.load("SVM_DATA.xml");
hog1.detectMultiScale(img,found);

答案显然是否定的,SVM训练出来的是分类器,但hogdescriptor需要的是一个detector,二者是有本质区别的。

下面贴出上个专题中训练得到的分类器(xml文件),其中支持向量太多省略,其中各个参数的含义,不做详细介绍了,明白SVM的应该很容易理解。

<?xml version="1.0"?>
<opencv_storage>
<my_svm type_id="opencv-ml-svm">
  <svm_type>C_SVC</svm_type>
  <kernel><type>RBF</type>
    <gamma>8.9999999999999997e-002</gamma></kernel>
  <C>10.</C>
  <term_criteria><epsilon>1.1920928955078125e-007</epsilon>
    <iterations>2147483647</iterations></term_criteria>
  <var_all>1764</var_all>
  <var_count>1764</var_count>
  <class_count>2</class_count>
  <class_labels type_id="opencv-matrix">
    <rows>1</rows>
    <cols>2</cols>
    <dt>i</dt>
    <data>
      0 1</data></class_labels>
  <sv_total>5</sv_total>
  <support_vectors>
    <_>
支持向量省略
</_></support_vectors>
  <decision_functions>
    <_>
      <sv_count>5</sv_count>
      <rho>-2.9438931041848948e-001</rho>
      <alpha>
        3.0069228814749499e-001 4.8593661661382231e-001
        3.3096444767386463e-001 3.3785525729586080e-001
        -1.4554486097310426e+000</alpha>
      <index>
        0 1 2 3 4</index></_></decision_functions></my_svm>
</opencv_storage>


 

 

detector只是一个向量,可以通过分类器直接转化。

 

3.解决方法

关于如何训练样本,且利用分类器求取detector的方法,下一篇博文介绍

参考:

OpenCV2.0 peopledetect 学习体会:http://www.opencv.org.cn/forum/viewtopic.php?f=1&t=9146

 

 
 

 

你可能感兴趣的:(Object Recognition and Scene Understanding(五)OpenCV中peopledetect详细介绍)