createsamples.cpp中生成vec文件的实现及详细注释、图解——人脸识别的尝试系列(三)

在我们开始训练我们的Haar分类器之前,首先要对样本进行处理。

人脸识别的尝试系列(一)中:http://blog.csdn.net/u011583927/article/details/44627493

我们已经提到了如何准备我们的样本,在如下图准备好样本之后


需要在cmd窗口中调用类似如下的命令生成vec文件

opencv_createsamples.exe–vec pos.vec –info pos_image.txt –bg neg_image.txt –w 24 –h 24 –num 400

那么具体是如何生成的vec文件的,下面是具体的实现代码以及根据我个人理解加上的详细注释

为方便大家理解,代码中插入了两张图片,分别展示了相应区域代码的执行结果


/*
 * createsamples.cpp 生成vec文件的可执行程序的具体实现
 *
 * Create test/training samples        利用描述正样本和负样本的txt文件创建vec文件
 * 命令行示例:
opencv_createsamples.exe –vec pos.vec –info pos_image.txt –bg neg_image.txt –w 24 –h 24 –num 400
*需要先将命令行的地址调到当前文件夹下
 */

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <memory>

using namespace std;

#include "cvhaartraining.h"
#include "ioutput.h"


int main( int argc, char* argv[] )
{
	//参数初始化
    int i = 0;
    char* nullname   = (char*)"(NULL)";
    char* vecname    = NULL; /* .vec file name */
    char* infoname   = NULL; //file name with marked up image descriptions正样本描述文件路径
    char* imagename  = NULL; /* single sample image  单个正样本图片*/
    char* bgfilename = NULL; /* background  负样本描述文件路径 */
    int num = 1000;
    int bgcolor = 0;
    int bgthreshold = 80;
    int invert = 0;
    int maxintensitydev = 40;// max_intensity_deviation
    double maxxangle = 1.1;
    double maxyangle = 1.1;
    double maxzangle = 0.5;
    bool showsamples = false;
    /* the samples are adjusted to this scale in the sample preview window */
    double scale = 4.0;
    int width  = 24;
    int height = 24;
    bool pngoutput = false; /* whether to make the samples in png or in jpg*/

    srand((unsigned int)time(0));
	
	//如果只输入opencv_createsamples.exe 相当于查看命令行参数使用
    if( argc == 1 )
    {
        printf( "Usage: %s\n  [-info <collection_file_name>]\n"
                "  [-img <image_file_name>]\n"
                "  [-vec <vec_file_name>]\n"
                "  [-bg <background_file_name>]\n  [-num <number_of_samples = %d>]\n"
                "  [-bgcolor <background_color = %d>]\n"
                "  [-inv] [-randinv] [-bgthresh <background_color_threshold = %d>]\n"
                "  [-maxidev <max_intensity_deviation = %d>]\n"
                "  [-maxxangle <max_x_rotation_angle = %f>]\n"
                "  [-maxyangle <max_y_rotation_angle = %f>]\n"
                "  [-maxzangle <max_z_rotation_angle = %f>]\n"
                "  [-show [<scale = %f>]]\n"
                "  [-w <sample_width = %d>]\n  [-h <sample_height = %d>]\n"
                "  [-pngoutput]",
                argv[0], num, bgcolor, bgthreshold, maxintensitydev,
                maxxangle, maxyangle, maxzangle, scale, width, height );

        return 0;
    }

 for( i = 1; i < argc; ++i )
{
		//strcmp(str1,str2)函数:比较两个字符串。
//相等返回0;str1>str2返回正数;str1<str2返回负数
        if( !strcmp( argv[i], "-info" ) )
        {
			//argv[i]==”-info”
            infoname = argv[++i];
        }
        else if( !strcmp( argv[i], "-img" ) )
        {
            imagename = argv[++i];
        }
        else if( !strcmp( argv[i], "-vec" ) )
        {
            vecname = argv[++i];
        }
        else if( !strcmp( argv[i], "-bg" ) )
        {
            bgfilename = argv[++i];
        }
        else if( !strcmp( argv[i], "-num" ) )
        {
			//atoi 把一个字符串转化成整形
            num = atoi( argv[++i] );
        }
        else if( !strcmp( argv[i], "-bgcolor" ) )
        {
            bgcolor = atoi( argv[++i] );
        }
        else if( !strcmp( argv[i], "-bgthresh" ) )
        {
            bgthreshold = atoi( argv[++i] );
        }
        else if( !strcmp( argv[i], "-inv" ) )
        {
		   //输入含-inv指令
            invert = 1;
        }
        else if( !strcmp( argv[i], "-randinv" ) )
        {
		   //输入含-randinv指令
            invert = CV_RANDOM_INVERT;
        }
        else if( !strcmp( argv[i], "-maxidev" ) )
        {
            maxintensitydev = atoi( argv[++i] );
        }
        else if( !strcmp( argv[i], "-maxxangle" ) )
        {
            maxxangle = atof( argv[++i] );
        }
        else if( !strcmp( argv[i], "-maxyangle" ) )
        {
            maxyangle = atof( argv[++i] );
        }
        else if( !strcmp( argv[i], "-maxzangle" ) )
        {
            maxzangle = atof( argv[++i] );
        }
        else if( !strcmp( argv[i], "-show" ) )
        {
            showsamples = true;
            if( i+1 < argc && strlen( argv[i+1] ) > 0 && argv[i+1][0] != '-' )
            {
                double d;
                d = strtod( argv[i+1], 0 );
                if( d != -HUGE_VAL && d != HUGE_VAL && d > 0 ) scale = d;
                ++i;
            }
        }
        else if( !strcmp( argv[i], "-w" ) )
        {
            width = atoi( argv[++i] );
        }
        else if( !strcmp( argv[i], "-h" ) )
        {
            height = atoi( argv[++i] );
        }
        else if( !strcmp( argv[i], "-pngoutput" ) )
        {
            pngoutput = true;
        }
    }

    printf( "Info file name: %s\n", ((infoname == NULL) ?   nullname : infoname ) );
    printf( "Img file name: %s\n",  ((imagename == NULL) ?  nullname : imagename ) );
    printf( "Vec file name: %s\n",  ((vecname == NULL) ?    nullname : vecname ) );
    printf( "BG  file name: %s\n",  ((bgfilename == NULL) ? nullname : bgfilename ) );
    printf( "Num: %d\n", num );
    printf( "BG color: %d\n", bgcolor );
    printf( "BG threshold: %d\n", bgthreshold );
    printf( "Invert: %s\n", (invert == CV_RANDOM_INVERT) ? "RANDOM"
                                : ( (invert) ? "TRUE" : "FALSE" ) );
    printf( "Max intensity deviation: %d\n", maxintensitydev );
    printf( "Max x angle: %g\n", maxxangle );
    printf( "Max y angle: %g\n", maxyangle );
    printf( "Max z angle: %g\n", maxzangle );
    printf( "Show samples: %s\n", (showsamples) ? "TRUE" : "FALSE" );
    if( showsamples )
    {
        printf( "Scale applied to display : %g\n", scale );
    }
    if( !pngoutput)
    {
        printf( "Original image will be scaled to:\n");
        printf( "\tWidth: $backgroundWidth / %d\n", width );
        printf( "\tHeight: $backgroundHeight / %d\n", height );
    }

    /* determine action  (通过关键命令)确定行为*/
    if( imagename && vecname )
    {
        printf( "Create training samples from single image applying distortions...\n" );

        cvCreateTrainingSamples( vecname, imagename, bgcolor, bgthreshold, bgfilename,
                                 num, invert, maxintensitydev,
                                 maxxangle, maxyangle, maxzangle,
                                 showsamples, width, height );

        printf( "Done\n" );
    }
    else if( imagename && bgfilename && infoname)
    {
        printf( "Create data set from single image applying distortions...\n"
                "Output format: %s\n",
                (( pngoutput ) ? "PNG" : "JPG") );

        std::auto_ptr<DatasetGenerator> creator;
        if( pngoutput )
        {
            creator = std::auto_ptr<DatasetGenerator>( new PngDatasetGenerator( infoname ) );
        }
        else
        {
            creator = std::auto_ptr<DatasetGenerator>( new JpgDatasetGenerator( infoname ) );
        }
        creator->create( imagename, bgcolor, bgthreshold, bgfilename, num,
                        invert, maxintensitydev, maxxangle, maxyangle, maxzangle,
                        showsamples, width, height );

        printf( "Done\n" );
    }
    else if( infoname && vecname )
{
		//生成vec文件,我们使用的这种命令
		//命令包括正样本描述文件的文件名,准备生成的vec文件的文件名
        int total;
        printf( "Create training samples from images collection...\n" );
        total = cvCreateTrainingSamplesFromInfo( infoname, vecname, num, showsamples,
                                                 width, height );
        printf( "Done. Created %d samples\n", total );
    }
    else if( vecname )
{
		//查看vec文件
		//命令不包含正样本文件,背景样本文件,单个正样本图像,只包含vec文件路径

 printf( "View samples from vec file (press ESC to exit)...\n" );

        cvShowVecSamples( vecname, width, height, scale );

        printf( "Done\n" );
    }
    else
    {
        printf( "Nothing to do\n" );
    }

    return 0;
}


cvCreateTrainingSamplesFromInfo函数的具体实现
为方便理解,对应于上面我们输入的命令来进行解释
-infoname    pos_image.txt 正样本描述文件文件名
-vecfilename pos.vec 这个参数相当于指定创建的vec文件的名字,函数执行前这个vec文件并不存在
-num         400 正样本总数 
-showsamples false 是否显示样本
-width
-height
int cvCreateTrainingSamplesFromInfo( const char* infoname, const char* vecfilename,
                                     int num,
                                     int showsamples,
                                     int winwidth, int winheight )
{
    char fullname[PATH_MAX];
    char* filename;

    FILE* info;
    FILE* vec;
    IplImage* src=0;
    IplImage* sample;
    int line;
    int error;
    int i;
    int x, y, width, height;
    int total;
	
	/*
#include <assert.h>
void assert( int expression );
assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行。*/

    assert( infoname != NULL );
    assert( vecfilename != NULL );

    total = 0;
    if( !icvMkDir( vecfilename ) )
{
		// icvMkDir() 
//个人理解:判断文件名vecfilename是否只包含文件名,不包含路径
		//例如:pos.veg返回1  D:\\pos.veg返回0
		//若只包含文件名,返回1,否则返回0

#if CV_VERBOSE
        fprintf( stderr, "Unable to create directory hierarchy: %s\n", vecfilename );
#endif /* CV_VERBOSE */

        return total;
    }

    info = fopen( infoname, "r" );//以只读方式打开文件infoname,若文件不存在不创建该文件(即返回null)
    if( info == NULL )
    {

#if CV_VERBOSE
        fprintf( stderr, "Unable to open file: %s\n", infoname );
#endif /* CV_VERBOSE */

        return total;
    }

    vec = fopen( vecfilename, "wb" );// 以二进制写方式打开文件,若文件不存在则创建该文件
    if( vec == NULL )
    {

#if CV_VERBOSE
        fprintf( stderr, "Unable to open file: %s\n", vecfilename );
#endif /* CV_VERBOSE */

        fclose( info );

        return total;
    }
	
	//创建一个单通道byte图像
    sample = cvCreateImage( cvSize( winwidth, winheight ), IPL_DEPTH_8U, 1 );

	//写vec文件头
    icvWriteVecHeader( vec, num, sample->width, sample->height );

    if( showsamples )
    {
        cvNamedWindow( "Sample", CV_WINDOW_AUTOSIZE );
    }

strcpy( fullname, infoname );

/*strrchr() 函数查找字符在指定字符串中从后面开始的第一次出现的位置,如果成功,则返回从该位置到字符串结尾的所有字符,如果失败,则返回 false。与之相对应的是strchr()函数,它查找字符串中首次出现指定字符的位置。*/
    filename = strrchr( fullname, '\\' );//获取正样本描述文件的文件名,剔除路径
    if( filename == NULL )
    {
        filename = strrchr( fullname, '/' );
    }
    if( filename == NULL )
    {
        filename = fullname;
    }
    else
{
		//正常情况,将指针指向‘\’后面的第一个字符
        filename++;
    }
	
	//遍历每张正样本图片,将其信息写入vec文件
    for( line = 1, error = 0, total = 0; total < num ;line++ )
    {
        int count;
		
/* 
fscanf功能: 从一个流中执行格式化输入,fscanf遇到空格和换行时结束,注意空格时也结束。
intfscanf(FILE*stream,constchar*format,[argument...]);
FILE *stream:文件指针;
char *format:格式字符串;
[argument...]:输入列表。
返回值:整型,成功读入的参数的个数
*/
        error = ( fscanf( info, "%s %d", filename, &count ) != 2 ); 
//info——正样本描述文件的文件流   
// 正样本描述文件每一行的格式  pos_image/0.bmp 1 0 0 24 24
//注意!filename是指向fullname的指针。所以这里以filename作为读入数据的参数,实际上修改的是fullname的内容。读入信息后fullname表示某一个正样本图片的地址(相对路径)
//count 表示文件的个数
        
if( !error )//说明读取是正确的,获取样本图片
        {
            src = cvLoadImage( fullname, 0 );//读取一副正样本图像(强制转化为灰度图像)
            error = ( src == NULL );
            if( error )
            {

#if CV_VERBOSE
                fprintf( stderr, "Unable to open image: %s\n", fullname );
#endif /* CV_VERBOSE */

            }
        }

	    //遍历当前样本图片中的所有子窗口样本。
   	    //一般情况下的使用方法是只有一个子窗口也就是整幅样本图片,
即count=1,且x=0 y=0 width height就是样本的宽和高 
        for( i = 0; (i < count) && (total < num); i++, total++ )
        {
            error = ( fscanf( info, "%d %d %d %d", &x, &y, &width, &height ) != 4 );
		   //读取当前图像的顶点坐标以及长宽
            if( error ) break;
		   // cvSetImageROI 基于给定的矩形设置图像的ROI(感兴趣区域)
            cvSetImageROI( src, cvRect( x, y, width, height ) );
		   
void cvResize( const CvArr* src, CvArr* dst, int interpolation=CV_INTER_LINEAR );
		   函数cvResize()功能: 重新调整图像src(或它的ROI),使它精确匹配目标dst(或其ROI)。这里需要说明的是,cvResize可以用来调整3通道图像(如RGB图像)和单通道图像的大小。
		   src 源图像;  dst 目标图像
            cvResize( src, sample, width >= sample->width &&
                      height >= sample->height ? CV_INTER_AREA : CV_INTER_LINEAR );

            if( showsamples )
            {
                cvShowImage( "Sample", sample );
                if( cvWaitKey( 0 ) == 27 )
                {
                    showsamples = 0;
                }
            }
		   //将当前这幅样本图片信息写入vec文件中
            icvWriteVecSample( vec, sample );
        }
		
	    //释放当前的图片占用的内存
        if( src )
        {
            cvReleaseImage( &src );
        }

        if( error )
        {

#if CV_VERBOSE
            fprintf( stderr, "%s(%d) : parse error", infoname, line );
#endif /* CV_VERBOSE */

            break;
        }
    }

    if( sample )
    {
        cvReleaseImage( &sample );
    }

    fclose( vec );
    fclose( info );

    return total;
}




  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值