createsamples.cpp中生成vec文件的实现及详细注释、图解——人脸识别的尝试系列(三)
2015-03-31 18:41
417 查看
在我们开始训练我们的Haar分类器之前,首先要对样本进行处理。
人脸识别的尝试系列(一)中:/article/2440590.html
我们已经提到了如何准备我们的样本,在如下图准备好样本之后
需要在cmd窗口中调用类似如下的命令生成vec文件
opencv_createsamples.exe–vec pos.vec –info pos_image.txt –bg neg_image.txt –w 24 –h 24 –num 400
那么具体是如何生成的vec文件的,下面是具体的实现代码以及根据我个人理解加上的详细注释
为方便大家理解,代码中插入了两张图片,分别展示了相应区域代码的执行结果
人脸识别的尝试系列(一)中:/article/2440590.html
我们已经提到了如何准备我们的样本,在如下图准备好样本之后
需要在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; }
相关文章推荐
- Haar特征原理与icvCreateIntHaarFeatures方法的具体实现附详细注释—— 人脸识别的尝试系列(二)
- opencv中的createsamples.exe生成vec文件注意事项
- 使用TCP协议实现一个可以上传文件的客户端源代码(附详细注释)
- [原创]Enterprise Architecture V7.5 C++代码生成时,头文件中函数声明没有注释,CPP中函数定义却有注释。
- HIGHCHARTS 在WEB生成SVG图片导出到word的详细操作步骤 导出另存为以及文件中文名称的实现
- 今天看到了一个用java实现复制,剪切,删除文件或文件夹的示例,感觉不错,欢迎学习(带详细注释)
- Intellij IDEA 通过数据库表逆向生成带注释的实体类文件超级详细步骤,附详细解决方案
- 利用TEA算法实现加密密码文件生成与解密
- 6-jacob实现根据模板生成文件并打印
- 在CPP文件中自动添加函数注释的ADDIN
- WCF系列(三) -- WCF配置文件注释
- 将(Oracle)数据库表导出到Excel,并生成文件(C#实现)
- Excel开发系列二 解决.net生成Excel文件速度问题的若干方案
- 如何实现将用户上传的文件生成缩略图
- 用php实现动态生成rss文件
- 共创Linux桌面系统co-create 1.0.3光盘安装过程详细图解
- CreateKeyWord asp实现的由给定的字符串生成关键字的代码
- VC实现生成BMP文件(DDA算法画直线)
- VS2005 XML注释生成XML文档文件
- 用.net实现按透明度生成水印文件