|
|
|
/*M///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
|
|
|
//
|
|
|
|
// By downloading, copying, installing or using the software you agree to this license.
|
|
|
|
// If you do not agree to this license, do not download, install,
|
|
|
|
// copy or use the software.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// Intel License Agreement
|
|
|
|
// For Open Source Computer Vision Library
|
|
|
|
//
|
|
|
|
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
|
|
|
// Third party copyrights are property of their respective owners.
|
|
|
|
//
|
|
|
|
// Redistribution and use in source and binary forms, with or without modification,
|
|
|
|
// are permitted provided that the following conditions are met:
|
|
|
|
//
|
|
|
|
// * Redistribution's of source code must retain the above copyright notice,
|
|
|
|
// this list of conditions and the following disclaimer.
|
|
|
|
//
|
|
|
|
// * Redistribution's in binary form must reproduce the above copyright notice,
|
|
|
|
// this list of conditions and the following disclaimer in the documentation
|
|
|
|
// and/or other materials provided with the distribution.
|
|
|
|
//
|
|
|
|
// * The name of Intel Corporation may not be used to endorse or promote products
|
|
|
|
// derived from this software without specific prior written permission.
|
|
|
|
//
|
|
|
|
// This software is provided by the copyright holders and contributors "as is" and
|
|
|
|
// any express or implied warranties, including, but not limited to, the implied
|
|
|
|
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
|
|
|
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
|
|
|
// indirect, incidental, special, exemplary, or consequential damages
|
|
|
|
// (including, but not limited to, procurement of substitute goods or services;
|
|
|
|
// loss of use, data, or profits; or business interruption) however caused
|
|
|
|
// and on any theory of liability, whether in contract, strict liability,
|
|
|
|
// or tort (including negligence or otherwise) arising in any way out of
|
|
|
|
// the use of this software, even if advised of the possibility of such damage.
|
|
|
|
//
|
|
|
|
//M*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* performance.cpp
|
|
|
|
*
|
|
|
|
* Measure performance of classifier
|
|
|
|
*/
|
|
|
|
#include "opencv2/core/core.hpp"
|
|
|
|
#include "opencv2/core/internal.hpp"
|
|
|
|
|
|
|
|
#include "cv.h"
|
|
|
|
#include "highgui.h"
|
|
|
|
|
|
|
|
#include <cstdio>
|
|
|
|
#include <cmath>
|
|
|
|
#include <ctime>
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
/* use clock() function insted of time() */
|
|
|
|
#define time( arg ) (((double) clock()) / CLOCKS_PER_SEC)
|
|
|
|
#endif /* _WIN32 */
|
|
|
|
|
|
|
|
#ifndef PATH_MAX
|
|
|
|
#define PATH_MAX 512
|
|
|
|
#endif /* PATH_MAX */
|
|
|
|
|
|
|
|
typedef struct HidCascade
|
|
|
|
{
|
|
|
|
int size;
|
|
|
|
int count;
|
|
|
|
} HidCascade;
|
|
|
|
|
|
|
|
typedef struct ObjectPos
|
|
|
|
{
|
|
|
|
float x;
|
|
|
|
float y;
|
|
|
|
float width;
|
|
|
|
int found; /* for reference */
|
|
|
|
int neghbors;
|
|
|
|
} ObjectPos;
|
|
|
|
|
|
|
|
int main( int argc, char* argv[] )
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
char* classifierdir = NULL;
|
|
|
|
//char* samplesdir = NULL;
|
|
|
|
|
|
|
|
int saveDetected = 1;
|
|
|
|
double scale_factor = 1.2;
|
|
|
|
float maxSizeDiff = 1.5F;
|
|
|
|
float maxPosDiff = 0.3F;
|
|
|
|
|
|
|
|
/* number of stages. if <=0 all stages are used */
|
|
|
|
int nos = -1, nos0;
|
|
|
|
|
|
|
|
int width = 24;
|
|
|
|
int height = 24;
|
|
|
|
|
|
|
|
int rocsize;
|
|
|
|
|
|
|
|
FILE* info;
|
|
|
|
char* infoname;
|
|
|
|
char fullname[PATH_MAX];
|
|
|
|
char detfilename[PATH_MAX];
|
|
|
|
char* filename;
|
|
|
|
char detname[] = "det-";
|
|
|
|
|
|
|
|
CvHaarClassifierCascade* cascade;
|
|
|
|
CvMemStorage* storage;
|
|
|
|
CvSeq* objects;
|
|
|
|
|
|
|
|
double totaltime;
|
|
|
|
|
|
|
|
infoname = (char*)"";
|
|
|
|
rocsize = 40;
|
|
|
|
if( argc == 1 )
|
|
|
|
{
|
|
|
|
printf( "Usage: %s\n -data <classifier_directory_name>\n"
|
|
|
|
" -info <collection_file_name>\n"
|
|
|
|
" [-maxSizeDiff <max_size_difference = %f>]\n"
|
|
|
|
" [-maxPosDiff <max_position_difference = %f>]\n"
|
|
|
|
" [-sf <scale_factor = %f>]\n"
|
|
|
|
" [-ni]\n"
|
|
|
|
" [-nos <number_of_stages = %d>]\n"
|
|
|
|
" [-rs <roc_size = %d>]\n"
|
|
|
|
" [-w <sample_width = %d>]\n"
|
|
|
|
" [-h <sample_height = %d>]\n",
|
|
|
|
argv[0], maxSizeDiff, maxPosDiff, scale_factor, nos, rocsize,
|
|
|
|
width, height );
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for( i = 1; i < argc; i++ )
|
|
|
|
{
|
|
|
|
if( !strcmp( argv[i], "-data" ) )
|
|
|
|
{
|
|
|
|
classifierdir = argv[++i];
|
|
|
|
}
|
|
|
|
else if( !strcmp( argv[i], "-info" ) )
|
|
|
|
{
|
|
|
|
infoname = argv[++i];
|
|
|
|
}
|
|
|
|
else if( !strcmp( argv[i], "-maxSizeDiff" ) )
|
|
|
|
{
|
|
|
|
maxSizeDiff = (float) atof( argv[++i] );
|
|
|
|
}
|
|
|
|
else if( !strcmp( argv[i], "-maxPosDiff" ) )
|
|
|
|
{
|
|
|
|
maxPosDiff = (float) atof( argv[++i] );
|
|
|
|
}
|
|
|
|
else if( !strcmp( argv[i], "-sf" ) )
|
|
|
|
{
|
|
|
|
scale_factor = atof( argv[++i] );
|
|
|
|
}
|
|
|
|
else if( !strcmp( argv[i], "-ni" ) )
|
|
|
|
{
|
|
|
|
saveDetected = 0;
|
|
|
|
}
|
|
|
|
else if( !strcmp( argv[i], "-nos" ) )
|
|
|
|
{
|
|
|
|
nos = atoi( argv[++i] );
|
|
|
|
}
|
|
|
|
else if( !strcmp( argv[i], "-rs" ) )
|
|
|
|
{
|
|
|
|
rocsize = atoi( argv[++i] );
|
|
|
|
}
|
|
|
|
else if( !strcmp( argv[i], "-w" ) )
|
|
|
|
{
|
|
|
|
width = atoi( argv[++i] );
|
|
|
|
}
|
|
|
|
else if( !strcmp( argv[i], "-h" ) )
|
|
|
|
{
|
|
|
|
height = atoi( argv[++i] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cascade = cvLoadHaarClassifierCascade( classifierdir, cvSize( width, height ) );
|
|
|
|
if( cascade == NULL )
|
|
|
|
{
|
|
|
|
printf( "Unable to load classifier from %s\n", classifierdir );
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int* numclassifiers = new int[cascade->count];
|
|
|
|
numclassifiers[0] = cascade->stage_classifier[0].count;
|
|
|
|
for( i = 1; i < cascade->count; i++ )
|
|
|
|
{
|
|
|
|
numclassifiers[i] = numclassifiers[i-1] + cascade->stage_classifier[i].count;
|
|
|
|
}
|
|
|
|
|
|
|
|
storage = cvCreateMemStorage();
|
|
|
|
|
|
|
|
nos0 = cascade->count;
|
|
|
|
if( nos <= 0 )
|
|
|
|
nos = nos0;
|
|
|
|
|
|
|
|
strcpy( fullname, infoname );
|
|
|
|
filename = strrchr( fullname, '\\' );
|
|
|
|
if( filename == NULL )
|
|
|
|
{
|
|
|
|
filename = strrchr( fullname, '/' );
|
|
|
|
}
|
|
|
|
if( filename == NULL )
|
|
|
|
{
|
|
|
|
filename = fullname;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
filename++;
|
|
|
|
}
|
|
|
|
|
|
|
|
info = fopen( infoname, "r" );
|
|
|
|
totaltime = 0.0;
|
|
|
|
if( info != NULL )
|
|
|
|
{
|
|
|
|
int x, y;
|
|
|
|
IplImage* img;
|
|
|
|
int hits, missed, falseAlarms;
|
|
|
|
int totalHits, totalMissed, totalFalseAlarms;
|
|
|
|
int found;
|
|
|
|
float distance;
|
|
|
|
|
|
|
|
int refcount;
|
|
|
|
ObjectPos* ref;
|
|
|
|
int detcount;
|
|
|
|
ObjectPos* det;
|
|
|
|
int error=0;
|
|
|
|
|
|
|
|
int* pos;
|
|
|
|
int* neg;
|
|
|
|
|
|
|
|
pos = (int*) cvAlloc( rocsize * sizeof( *pos ) );
|
|
|
|
neg = (int*) cvAlloc( rocsize * sizeof( *neg ) );
|
|
|
|
for( i = 0; i < rocsize; i++ ) { pos[i] = neg[i] = 0; }
|
|
|
|
|
|
|
|
printf( "+================================+======+======+======+\n" );
|
|
|
|
printf( "| File Name | Hits |Missed| False|\n" );
|
|
|
|
printf( "+================================+======+======+======+\n" );
|
|
|
|
|
|
|
|
totalHits = totalMissed = totalFalseAlarms = 0;
|
|
|
|
while( !feof( info ) )
|
|
|
|
{
|
|
|
|
if( fscanf( info, "%s %d", filename, &refcount ) != 2 || refcount <= 0 ) break;
|
|
|
|
|
|
|
|
img = cvLoadImage( fullname );
|
|
|
|
if( !img ) continue;
|
|
|
|
|
|
|
|
ref = (ObjectPos*) cvAlloc( refcount * sizeof( *ref ) );
|
|
|
|
for( i = 0; i < refcount; i++ )
|
|
|
|
{
|
|
|
|
int w, h;
|
|
|
|
error = (fscanf( info, "%d %d %d %d", &x, &y, &w, &h ) != 4);
|
|
|
|
if( error ) break;
|
|
|
|
ref[i].x = 0.5F * w + x;
|
|
|
|
ref[i].y = 0.5F * h + y;
|
|
|
|
ref[i].width = sqrtf( 0.5F * (w * w + h * h) );
|
|
|
|
ref[i].found = 0;
|
|
|
|
ref[i].neghbors = 0;
|
|
|
|
}
|
|
|
|
if( !error )
|
|
|
|
{
|
|
|
|
cvClearMemStorage( storage );
|
|
|
|
|
|
|
|
cascade->count = nos;
|
|
|
|
totaltime -= time( 0 );
|
|
|
|
objects = cvHaarDetectObjects( img, cascade, storage, scale_factor, 1 );
|
|
|
|
totaltime += time( 0 );
|
|
|
|
cascade->count = nos0;
|
|
|
|
|
|
|
|
detcount = ( objects ? objects->total : 0);
|
|
|
|
det = (detcount > 0) ?
|
|
|
|
( (ObjectPos*)cvAlloc( detcount * sizeof( *det )) ) : NULL;
|
|
|
|
hits = missed = falseAlarms = 0;
|
|
|
|
for( i = 0; i < detcount; i++ )
|
|
|
|
{
|
|
|
|
CvAvgComp r = *((CvAvgComp*) cvGetSeqElem( objects, i ));
|
|
|
|
det[i].x = 0.5F * r.rect.width + r.rect.x;
|
|
|
|
det[i].y = 0.5F * r.rect.height + r.rect.y;
|
|
|
|
det[i].width = sqrtf( 0.5F * (r.rect.width * r.rect.width +
|
|
|
|
r.rect.height * r.rect.height) );
|
|
|
|
det[i].neghbors = r.neighbors;
|
|
|
|
|
|
|
|
if( saveDetected )
|
|
|
|
{
|
|
|
|
cvRectangle( img, cvPoint( r.rect.x, r.rect.y ),
|
|
|
|
cvPoint( r.rect.x + r.rect.width, r.rect.y + r.rect.height ),
|
|
|
|
CV_RGB( 255, 0, 0 ), 3 );
|
|
|
|
}
|
|
|
|
|
|
|
|
found = 0;
|
|
|
|
for( j = 0; j < refcount; j++ )
|
|
|
|
{
|
|
|
|
distance = sqrtf( (det[i].x - ref[j].x) * (det[i].x - ref[j].x) +
|
|
|
|
(det[i].y - ref[j].y) * (det[i].y - ref[j].y) );
|
|
|
|
if( (distance < ref[j].width * maxPosDiff) &&
|
|
|
|
(det[i].width > ref[j].width / maxSizeDiff) &&
|
|
|
|
(det[i].width < ref[j].width * maxSizeDiff) )
|
|
|
|
{
|
|
|
|
ref[j].found = 1;
|
|
|
|
ref[j].neghbors = MAX( ref[j].neghbors, det[i].neghbors );
|
|
|
|
found = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( !found )
|
|
|
|
{
|
|
|
|
falseAlarms++;
|
|
|
|
neg[MIN(det[i].neghbors, rocsize - 1)]++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for( j = 0; j < refcount; j++ )
|
|
|
|
{
|
|
|
|
if( ref[j].found )
|
|
|
|
{
|
|
|
|
hits++;
|
|
|
|
pos[MIN(ref[j].neghbors, rocsize - 1)]++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
missed++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
totalHits += hits;
|
|
|
|
totalMissed += missed;
|
|
|
|
totalFalseAlarms += falseAlarms;
|
|
|
|
printf( "|%32.32s|%6d|%6d|%6d|\n", filename, hits, missed, falseAlarms );
|
|
|
|
printf( "+--------------------------------+------+------+------+\n" );
|
|
|
|
fflush( stdout );
|
|
|
|
|
|
|
|
if( saveDetected )
|
|
|
|
{
|
|
|
|
strcpy( detfilename, detname );
|
|
|
|
strcat( detfilename, filename );
|
|
|
|
strcpy( filename, detfilename );
|
|
|
|
cvvSaveImage( fullname, img );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( det ) { cvFree( &det ); det = NULL; }
|
|
|
|
} /* if( !error ) */
|
|
|
|
|
|
|
|
cvReleaseImage( &img );
|
|
|
|
cvFree( &ref );
|
|
|
|
}
|
|
|
|
fclose( info );
|
|
|
|
|
|
|
|
printf( "|%32.32s|%6d|%6d|%6d|\n", "Total",
|
|
|
|
totalHits, totalMissed, totalFalseAlarms );
|
|
|
|
printf( "+================================+======+======+======+\n" );
|
|
|
|
printf( "Number of stages: %d\n", nos );
|
|
|
|
printf( "Number of weak classifiers: %d\n", numclassifiers[nos - 1] );
|
|
|
|
printf( "Total time: %f\n", totaltime );
|
|
|
|
|
|
|
|
/* print ROC to stdout */
|
|
|
|
for( i = rocsize - 1; i > 0; i-- )
|
|
|
|
{
|
|
|
|
pos[i-1] += pos[i];
|
|
|
|
neg[i-1] += neg[i];
|
|
|
|
}
|
|
|
|
fprintf( stderr, "%d\n", nos );
|
|
|
|
for( i = 0; i < rocsize; i++ )
|
|
|
|
{
|
|
|
|
fprintf( stderr, "\t%d\t%d\t%f\t%f\n", pos[i], neg[i],
|
|
|
|
((float)pos[i]) / (totalHits + totalMissed),
|
|
|
|
((float)neg[i]) / (totalHits + totalMissed) );
|
|
|
|
}
|
|
|
|
|
|
|
|
cvFree( &pos );
|
|
|
|
cvFree( &neg );
|
|
|
|
}
|
|
|
|
|
|
|
|
delete[] numclassifiers;
|
|
|
|
|
|
|
|
cvReleaseHaarClassifierCascade( &cascade );
|
|
|
|
cvReleaseMemStorage( &storage );
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|