【本文在本人赛迪博客上同期刊出:http://itrock.blog.ccidnet.com/blog-htm-do-showone-uid-255426-type-blog-itemid-1398414.html 转载请注明出处】
近两周一直在研读OpenCV中的光团跟踪例程blobtrack例程。在分析程序代码时,我发现其中有个子函数set_params()的核心代码不会被有效调用,似乎这个函数是冗余的。由于资料的匮乏及该例程中帮助文档不够详尽,以致于让我觉得自己发现了一处OpenCV的Bug。但今晚在调试该程序时,闪念间明白了这个函数的含义,发现自己之前误解了该函数。
/ OpenCV的blobtrack例程中的set_params()函数代码/
static void set_params(int argc, char* argv[], CvVSModule* pM, char* prefix, char* module)
{
int prefix_len = strlen(prefix);
int i;
for(i=0;i<argc;++i)
{
int j;
char* ptr_eq = NULL;
int cmd_param_len=0;
char* cmd = argv[i];
char* cmd2=NULL
if(strnicmp(prefix,cmd,prefix_len)!=0) continue;
cmd += prefix_len;
if(cmd[0]!=':')continue;
cmd++;
ptr_eq = strchr(cmd,'=');
if(ptr_eq)cmd_param_len = ptr_eq-cmd;
for(j=0;;++j)
{
int param_len;
char* param = pM->GetParamName(j);
if(param==NULL) break;
param_len = strlen(param);
if(cmd_param_len!=param_len) continue;
if(strnicmp(param,cmd,param_len)!=0) continue;
cmd+=param_len;
if(cmd[0]!='=')continue;
cmd++;
pM->SetParamStr(param,cmd);
printf("%s:%s param set to %g/n",module,param,pM->GetParam(param));
}
}
pM->ParamUpdate();
}/* set_params */
/
因为该例程中的参数传递中没有用到":"的地方,所以按照这种根本不会包含":"的命令行参数传递规则,语句“ if(cmd[0]!=':')continue; ”之后的内容根本就不可能有机会执行。显然,设置参数的核心语句“ pM->SetParamStr(param,cmd); ”也就不会被执行。这让我,同样让好多曾今试探深刻理解该程序的人们困惑不已。下面摘录的是例程的命令行参数传递规则:
blobtrack.exe [fg=<fg_name>] [bd=<bd_name>]
[bt=<bt_name>] [btpp=<btpp_name>]
[bt_corr=<bt_corr_way>]
[trackgen=<btgen_name>]
[track=<track_file_name>]
[scale=<scale val>]
[noise=<noise_name>] [IVar=<IVar_name>]
[res=<res_file_name>] [FGTrainFrames=<FGTrainFrames>]
<yml_file video1 video2 video3>|<avi_file>
事实上,不知道是由于OpenCV官方为了简化说明文档,还是由于疏忽的原因,对于命令行的参数传递规则,他们省略了下面我要叙说的部分,正是这部分的缺失导致我产生了之前的误解。
blobtrack的各模块CvFGDetector,CvBlobDetector,CvBlobTracker,CvBlobTrackGen,CvBlobTrackPostProc,CvBlobTrackAnalysis中有许多内部参数可以初始化(否则将用缺省值)。通过命令行参数初始化这些模块的参数的格式分别为:
[fg:<参数名1>=<参数值1>] [fg:<参数名2>=<参数值2>]
[bd:<参数名1>=<参数值1>] [bd:<参数名2>=<参数值2>]
[bt:<参数名1>=<参数值1>] [bt:<参数名2>=<参数值2>]
[btgen:<参数名1>=<参数值1>] [btgen:<参数名2>=<参数值2>]
[btpp:<参数名1>=<参数值1>] [btpp:<参数名2>=<参数值2>]
[bta:<参数名1>=<参数值1>] [bta:<参数名2>=<参数值2>]
当以这种方式从命令行输入参数时,set_params()函数便会把参数值赋值到相应模块的相应参数。例如CvFGDetector中有个参数是char * alpha1,设需要处理的avi文件位于D:/test.avi,则我们在命令行键入如下命令:
blobtrack.exe bt=test_bt.avi D:/test.avi fg:alpha1=3.14
则运行程序blobtrack.exe,对D盘的test.avi视频进行运动跟踪处理,并将CvFGDetector模块的内部参数alpha1用3.14来初始化。实际上,各个模块的内部参数很多,具体的可以通过语句“ char* param = pM->GetParamName(j); ”来查询。
为了验证如上我所说的,我们可以在set_params()处设置断点,单步调试程序来查看相关变量。