本文为笔者读书笔记,欢迎转载,请注明本博,谢谢。如有不足,请大家多多指教。
1 CvBackgrounData和CvBackgroundReader
/*
*存放负样本文件的结构体
*/
typedef struct CvBackgroundData
{
int count; //负样本的数量
char** filename; //负样本的文件名包括绝对路径和扩展名
int last;
int round;
CvSize winsize; //大小
} CvBackgroundData;
/*
*在训练过程中,由于负样本的大小不一定是等于正样本的(必须是大于等于正样本),
*所以在训练过程中,需要抠出与正样本一样大的ROI区域,就是该结构体表示roi区域
*/
typedef struct CvBackgroundReader{ CvMat src; //未处理的负样本原图像
CvMat img; //扣取的负样本
CvPoint offset; //扣取负样本的左上角的坐标
float scale; //代表了缩放的比例
float scalefactor; //不知道为什么两个缩放因子
float stepfactor;
CvPoint point;
} CvBackgroundReader
2 icvGetBackgroundImage
/*
*icvGetBackgroundImage获取负样本,训练的负样本可以比正样本大
*但是该函数索取的负样本是在负样本中取得跟正样本一样大的区域
*/
static void icvGetBackgroundImage( CvBackgroundData* data, //如上所示
CvBackgroundReader* reader, CvMat* img )
{ CvMat mat;
assert( data != NULL && reader != NULL && img != NULL );
assert( CV_MAT_TYPE( img->type ) == CV_8UC1 );
assert( img->cols == data->winsize.width );
assert( img->rows == data->winsize.height );
/*在if中的reader->img.data.ptr 这个data与CvBackgroundData* data中的data是不一样的
*reader->img.data.ptr:这个data是个union(共同体),data中的ptr存储的是data数据的第一个元素。
*CvBackgroundData* data:如上所示
*/
if( reader->img.data.ptr == NULL ) //含义是如果reader读入的图片的数据为空
{
icvGetNextFromBackgroundData( data, reader );
} mat = cvMat( data->winsize.height, data->winsize.width, CV_8UC1 );
cvSetData(&mat, (void*) (reader->img.data.ptr + reader->point.y * reader->img.step + reader->point.x * sizeof( uchar )), reader->img.step ); cvCopy( &mat, img, 0 );
//若负样本图像很大,我们可以在一幅图中不断调整切割的位置
//直至遍历完整个图像
//沿x方向移动
if( (int) ( reader->point.x + (1.0F + reader->stepfactor ) * data->winsize.width )
< reader->img.cols )
{
reader->point.x += (int) (reader->stepfactor * data->winsize.width);
}
else
{ //置为x.offset(相当于x方向移动不下去了,按y方向移动)
reader->point.x = reader->offset.x;
//延y方向移动
if( (int) ( reader->point.y + (1.0F + reader->stepfactor ) * data->winsize.height )
< reader->img.rows )
{
reader->point.y += (int) (reader->stepfactor * data->winsize.height);
}
else
{
reader->point.y = reader->offset.y;
reader->scale *= reader->scalefactor;
if( reader->scale <= 1.0F )
{
reader->img = cvMat( (int) (reader->scale * reader->src.rows),
(int) (reader->scale * reader->src.cols),
CV_8UC1, (void*) (reader->img.data.ptr) );
cvResize( &(reader->src), &(reader->img) );
}
else
{
icvGetNextFromBackgroundData( data, reader );
}
}
}
}
3 icvGetNextFromBackgroundData
有些代码我还没有看懂,不敢乱注释,以免误导大家,请友友们见谅哈
/*
*icvGetNextFromBackgroundData
*功能:将负样本的属性信息存放在reader中,属性信息有负样本的长,宽,数量等
*/
static
void icvGetNextFromBackgroundData( CvBackgroundData* data,
CvBackgroundReader* reader )
{
IplImage* img = NULL;
char* filename = NULL;
size_t datasize = 0;
int round = 0;
int i = 0;
CvPoint offset = cvPoint(0,0);
assert( data != NULL && reader != NULL );
if( reader->src.data.ptr != NULL )
{
cvFree( &(reader->src.data.ptr) );
reader->src.data.ptr = NULL;
}
if( reader->img.data.ptr != NULL )
{
cvFree( &(reader->img.data.ptr) );
reader->img.data.ptr = NULL;
}
#ifdef _OPENMP
#pragma omp critical(c_background_data)
#endif /* _OPENMP */
{
for( i = 0; i < data->count; i++ )
{
round = data->round;
//#ifdef CV_VERBOSE
// printf( "Open background image: %s\n", data->filename[data->last] );
//#endif /* CV_VERBOSE */
img = cvLoadImage( data->filename[data->last++], 0 );
if( !img )
continue;
data->round += data->last / data->count;
data->round = data->round % (data->winsize.width * data->winsize.height);
data->last %= data->count;
offset.x = round % data->winsize.width;
offset.y = round / data->winsize.width;
offset.x = MIN( offset.x, img->width - data->winsize.width );
offset.y = MIN( offset.y, img->height - data->winsize.height );
if( img != NULL && img->depth == IPL_DEPTH_8U && img->nChannels == 1 &&
offset.x >= 0 && offset.y >= 0 )
{
break;
}
if( img != NULL )
cvReleaseImage( &img );
img = NULL;
}
}
if( img == NULL )
{
/* no appropriate image */
#ifdef CV_VERBOSE
printf( "Invalid background description file.\n" );
#endif /* CV_VERBOSE */
assert( 0 );
exit( 1 );
}
datasize = sizeof( uchar ) * img->width * img->height;
reader->src = cvMat( img->height, img->width, CV_8UC1, (void*) cvAlloc( datasize ) );
cvCopy( img, &reader->src, NULL );
cvReleaseImage( &img );
img = NULL;
//reader->offset.x = round % data->winsize.width;
//reader->offset.y = round / data->winsize.width;
reader->offset = offset;
reader->point = reader->offset;
reader->scale = MAX(
((float) data->winsize.width + reader->point.x) / ((float) reader->src.cols),
((float) data->winsize.height + reader->point.y) / ((float) reader->src.rows) );
//将负样本大小放缩到包含正样本大小的最小尺寸
reader->img = cvMat( (int) (reader->scale * reader->src.rows + 0.5F),
(int) (reader->scale * reader->src.cols + 0.5F),
CV_8UC1, (void*) cvAlloc( datasize ) );
cvResize( &(reader->src), &(reader->img) );
}
也有人说这是个抠图的过程,比如http://blog.csdn.net/longzaitianya1989/article/details/8174768
具体抠图过程为:
1) 确定抠图区域的左上角坐标(Point.x, Point.y)
2) 确定一个最小缩放比例,使得原负样本图像缩放后恰好包含选中负样本区域
3) 对原负样本图象按计算好的缩放比例进行缩放
4) 在缩放后的图像上抠出负样本
如图:
本图选自http://blog.csdn.net/lampqiu/article/details/40188763
参考内容:
1 《学习opencv》于仕琪
2 http://blog.csdn.net/lampqiu/article/details/40188763