使用FDDB人脸样本检测库,测试自己的人脸检测算法性能并生成ROC曲线。

Posted 晴堂

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用FDDB人脸样本检测库,测试自己的人脸检测算法性能并生成ROC曲线。相关的知识,希望对你有一定的参考价值。

一,说明及环境

网上有关FDDB人脸检测库的使用以及ROC文件生成的文章太少,并且都无法检测opencv中自带的人脸检测算法。最近

工作的原因,需要用到FDDB库检测我们自己的人脸检测算法性能。所以认真研究了FDDB库的使用,并生成了ROC文件。

所有代码在Win10,VS2013,opencv2411下亲测可用。

二,过程及代码

1,下载FDDB图片库,注解文件以及生成ROC文件的源代码。官网地址:http://vis-www.cs.umass.edu/fddb/

      所有需要的资料以及代码,我已经上传,在评论里留下邮箱,我会尽快发到你邮箱。

2,编译FDDB源代码,直接导入到win32控制台项目中即可,源代码中已经写好了main方法。

3,根据自己的人脸检测算法生成FDDB必须的表述自己算法结果的txt文件。

      FDDB官网中的readme.txt文件已经说明了自己生成的txt文件的内容格式,如下:

<image name i>///写入自己检测的图片名称,
<number of faces in this image =im>///检测到的人脸个数
<face i1> ///检测到的人脸矩形或椭圆信息以及信心值也可说是准确率detection_score
<face i2>
...
<face im>
...
where the representation of a face depends on the specifics
of the shape of the hypothesized image region. The evaluation
code supports the following shapes:
  
  4 a. Rectangular regions
               Each face region is represented as:
                              <left_x top_y width height detection_score> 
  
         4 b. Elliptical regions
                          Each face region is represented as:
                              <major_axis_radius minor_axis_radius angle center_x center_y detection_score>.

Also, the order of images in the output file is expected to be 
        the same as the order in the file annotatedList.txt.

     我们必须对FDDB库中提供的图片,使用我们自己的算法对图片进行人脸检测,将每一张的检测结果信息按照如上

格式写入到txt文件,图片的读入顺序按照下载的annotatedList.txt文件中列举的图片路径以及名称顺序,内容如下:

2002/08/11/big/img_591
2002/08/26/big/img_265
2002/07/19/big/img_423
2002/08/24/big/img_490
2002/08/31/big/img_17676
        .........

2002/08/07/big/img_1453
2002/08/02/big/img_760

生成opencv中人脸检测算法的结果文件,代码如下:

// evaluation.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

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

#include <cctype>
#include <iostream>
#include<fstream>
#include <iterator>
#include <stdio.h>

using namespace std;
using namespace cv;

bool isOverlap(Rect r1,Rect r2);
//实现识别并绘制出面部矩形框,参数依次是图片,人脸检测分类器,允许的缩小比,检测出人脸准确分值,
//返回检测出的人脸矩形
vector<Rect> detectAndDraw( Mat& img, CascadeClassifier& cascade,double scale,int * score);
//人脸模型文件,为xml文件结构记录了一个标准的人脸模特数据;
string cascadeName = "haarcascade_frontalface_alt.xml";
int main( int argc, const char** argv )

	Mat frame, frameCopy, image;//OpenCV中存储数据的通用类型,较旧的版本中为
	string inputName;
	string dir;
	bool tryflip = false;
	CascadeClassifier cascade;
	double scale = 1;
	cascade.load( cascadeName );
	ifstream in_txt("FDDB-fold-01.txt");//文件直接放在程序当前目录下,自己根据情况修改
	ofstream out_txt1("output.txt");//生成的算法检测结果文件
	out_txt1.close();
	while(!in_txt.eof())
	
		getline(in_txt,inputName);//读取图片路径
		dir=dir1+inputName;
		dir+=".jpg";
		image = imread(dir,CV_LOAD_IMAGE_COLOR);
		if( !image.empty() )
		
			ofstream out_txt("output.txt",ios::app);
			int scoreBuffer[50];
			vector<Rect> faces=detectAndDraw( image, cascade,scale,scoreBuffer);
			out_txt<<inputName<<endl<<faces.size()<<endl;
			out_txt.close();
			for(int i=0;i<faces.size();i++)
			
				ofstream out_txt1("output.txt",ios::app);
				//写入结果文件
				out_txt1<<faces[i].x<<" "<<faces[i].y<<" "<<faces[i].width<<" "<<faces[i].height<<" "<<scoreBuffer[i]<<endl;
				out_txt1.close();
			
			faces.clear();
		
	
	waitKey(0);
	return 0;


vector<Rect> detectAndDraw( Mat& img, CascadeClassifier& cascade,
	double scale,int * scoreBuffer)

	vector<Rect> faces, faces2;
	Mat gray, smallImg( cvRound (img.rows/scale), cvRound(img.cols/scale), CV_8UC1 );

	cvtColor( img, gray, CV_BGR2GRAY );
	resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR );
	equalizeHist( smallImg, smallImg );
	//检测出人脸位置
	cascade.detectMultiScale( smallImg, faces,1.05,0, 0|CV_HAAR_SCALE_IMAGE,Size(20, 20));
	//获取opencv检测人脸过程中,所有的匹配框,因为opencv每检测出一张脸都要检测出若干个子矩形框,
	//最终进行合并成一个矩形框,所以子矩形框越多,准确路越高。
	cascade.detectMultiScale( smallImg, faces2,1.05,2, 0|CV_HAAR_SCALE_IMAGE,Size(20, 20));

	int i=0;
	for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); r++,i++)
	
		 //计算每张脸的准确率分值,
		 int score=0;
		 for( vector<Rect>::const_iterator s = faces.begin(); s != faces.end(); s++)
		 
			 if(isOverlap(*r,*s))//如果重复就说明这个子矩形框是正确的,可以加分
			 
				score++;
			 
		 
		 scoreBuffer[i]=score;
		 cout<<score<<endl;
	
	return faces2;

bool isOverlap(Rect r1,Rect r2)//判断矩形是否重叠


	int x0=r1.x>r2.x?r1.x:r2.x;
	int y0=r1.y>r2.y?r1.y:r2.y;
	int x1=r1.x+r1.width;
	int y1=r1.y+r1.height;
	int x2=r2.x+r2.width;
	int y2=r2.y+r2.height;
	int x3=x1<x2?x1:x2;
	int y3=y1<y2?y1:y2;
	if(x3<x0||y3<y0)
	
		return false;
	
	else
	
		return true;
	
   代码运行结束,就会生成描述算法结果的txt文件。

4,使用FDDB的源代码程序,读入自己算法的结果程序,以及对应自己结果程序的FDDB注解文件,这个注解文件其实

存储了每张图片人脸的正确位置,FDDB的源代码程序会按照顺序和我们自己的算法程序结果进行比对。需要注意的是,

我们自己的算法结果文件中,信心值也可说是准确率detection_score有多少个不同的值,最终生成的ROC文件就会有多

少组数据。FDDB代码的使用方法如下:

只需要修改带有main方法的.CPP文件,将其中定义读入文件路径的代码修改为:

  //存放FDDB图片的根文件夹,为当前文件夹
  string baseDir = "";
  //存储读取图片顺序的txt
  string listFile = "FDDB-fold-01.txt";
  //自己算法生成的结果文件
  string detFile = "output.txt";
  //记录了每张图片的人脸检测答案
  string annotFile = "FDDB-fold-01-ellipseList.txt";
我的项目文件目录截图如下:

         

      程序运行结束,会在程序当前目录下生成tempContROC.txt和tempDiscROC.txt分别是非离散和离散的ROC曲线文件。

至于怎么显示ROC曲线,在matlab里使用plot函数即可。



以上是关于使用FDDB人脸样本检测库,测试自己的人脸检测算法性能并生成ROC曲线。的主要内容,如果未能解决你的问题,请参考以下文章

FDDB 评估代码

如何计算 OpenCV 人脸检测器的检测分数?

收集adaboost算法的负样本进行人脸检测

opencv 人脸识别 训练样本的处理

Adaboost算法详解(haar人脸检测)

dlib代码解读人脸关键点检测器的训练