利用opencv内置程序训练一个自己的分类器

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Zgorange/article/details/44677749

这几天废了九牛二虎之力,训练出了一个分类器。分享一下方法

第一步,也是最重要的一步,就是采集样品,样品的采集直接影响到以后的结果。这里要注意的是,正样品的大小必须相同(采集的时候可以不同,采集完成后可以使用工具修改,但是比例一定要相同,不然修改以后也会不同),等下给出采集样品用到的工具,负样品的尺寸大小一般要比正样品的大一些。数量的比例大概为正样品:负样品=1:3最好。

还有要注意的就是负样品中不能包含正样品。另外,数目要多一点,负样本尽量

为背景图片,不然最后训练的虽然快,但是,没什么效果。

第二步,生成一个描述文件,先说负样品,描述文件的内容为全部样品的名称,建立保存负样本的文件夹(如:neg),并在neg目录下建立negdata.dat描述文件
Negdata.dat的内容如下:


1.bmp
2.bmp
3.bmp

可以利用工具先全部改下名字,方便查看,然后进入命令行程序--cmd.exe,进入到相应的文件夹,我的是cd C:\Users\zqj\Desktop\classfier\neg,然后dir /b >negdata.dat,就会生成一个相应的文件,不过要记得去掉最后一行呦。

正样品稍微麻烦一点,建立保存正样本的文件夹(如:pos),并在pos目录下建立posdata.dat描述文件,到这里与负样本的准备是一致的。不同之处在于正样本的描述中需要指出目标在图像中的数量和位置比如1.bmp中包含一辆汽车,它的描述应写成1.bmp 1 x1 y1 x2 y2 ,其中(x1,y1,x2,y2)指出这个目标所在的矩形框。
由于所有正样本都是统一size,只要在记事本(Ctrl + h)中编辑描述文件将bmp替换成bmp 1 0 0 width height 即可,width和height是图像的宽和高。

这样基本工作算是完成了。

第三步,生成正样品vec文件。opencv中有相应的程序在OpenCV2.3\bin\Release中,先进入命令行程序,进入相应文件夹 cd C:\OpenCV2.3\bin\Release,然后opencv_createsamples.exe -info C:\Users\zqj\Desktop\test\pos\posdata.dat -vec C:\Users\zqj\Desktop\test\pos\pos.vec -num 249 -w 50 -h 50,生成了一个就vec文件,其参数:

-info posdata.dat 正样本描述文件
                -vec pos.vec        生成的.vec文件名
                -num  5323          正样本的数量
                -w 50                    样本的宽度
                -h  50                    样本的高度

第四步,生成xml文件,完成自己分类器的训练。cd C:\OpenCV2.3\bin\Release,

opencv_haartraining.exe -data C:\Users\zqj\Desktop\test\data -vec C:\Users\zqj\Desktop\test\pos\pos.vec -bg C:\Users\zqj\Desktop\test\neg\neg.dat -npos 249 -nneg 1123 -nsplits 2 -mem 512 -nonsym -w 50 -h 50 -minpos 100 -nstages 4

参数:

 -data 生成的分类器名称和路径,包括级联文件夹和.xml文件两部分,二者是相同的;
                  -vec   正样本的.vec文件路径
                  -bg     负样本的描述文件路径
                  -npos  正样本数量
                  -nneg  负样本数量
                  -nstages 级联分类器的层数
                  -mem      分配的内存空间,越大训练过程越快
                  -sym     目标是否对称
                  -minhitrate  要达成的检测率
                  -maxfalsealarm  要达成的虚警率
                  -mode   选取的特征模式
                  -w         正样本宽度
                  -h          正样本高度
当级数达到nstages或者检测率、虚警率同时满足时,训练结束,程序退出

(再解释下各个参数的含义  -data 指定生成的文件目录, -vec vec文件名, -bg 负样本描述文件路径, -nstage 20 指定训练层数,推荐15~20,层数越高,耗时越长。-nsplits 分裂子节点数目,选取默认值 2 -minhitrate 最小命中率,即训练目标准确度。-maxfalsealarm最大虚警(误检率),每一层训练到这个值小于0.5时训练结束,进入下一层训练,-npos 正样本数目,-nneg  负样本数目 这个值可以设置大于真正的负样本图像数目,程序可以自动从负样本图像中切割出和正样本大小一致的 -nneg张图 这个参数一半设置为正样本数目的1~3倍, -w -h意思很明确, -mem 程序可使用的内存,这个设置为256即可,实际运行时根本就不怎么耗内存。 -mode ALL指定haar特征的类型数目

之后的工作就只有等待了,时间有长有短,,少则几分钟,多则几天都有可能。再送上一个程序吧,可以测试一下分类器效果,我做的是皮肤检测,效果不是特别好。

 string skin_cascade_name = "skin.xml";
 CascadeClassifier skin_cascade;
 string window_name = "Capture - Skin detection";
 RNG rng(12345);


 /** @主函数 */
int main( int argc, const char** argv )
{
CvCapture* capture;
Mat frame;
//-- 1. 加载级联分类器文件
if( !skin_cascade.load( skin_cascade_name ) ){
cerr<<"ERROR: Could not load classifier cascade"<<endl;
return -1;
}
capture = capture = cvCreateFileCapture("0.avi");
if( capture )
{
while( true )
{
frame = cvQueryFrame( capture );
resize(frame,frame,cvSize(352,288));
   //-- 3. 对当前帧使用分类器进行检测
if( !frame.empty() )
{
detectAndDisplay( frame ); 
}
else
{
cout<<" --(!) No captured frame -- Break!"<<endl; 
break; 
}
       int c = waitKey(10);
       if( (char)c == 'c' ) { break; }
      }
   }
   return 0;
 }


/** @函数 detectAndDisplay */
void detectAndDisplay( Mat frame )
{
std::vector<Rect> skin;
Mat frame_gray;


cvtColor( frame, frame_gray, CV_BGR2GRAY );
equalizeHist( frame_gray, frame_gray );


  //-- 多尺寸检测皮肤
  skin_cascade.detectMultiScale( frame_gray, skin, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(50, 50) );


  for( int i = 0; i < skin.size(); i++ )
  {
 rectangle(frame, cvPoint(skin[i].x, skin[i].y), 
cvPoint(skin[i].x+skin[i].width, skin[i].y+skin[i].height), cvScalar(255,0,0), 1);
  }
  //-- 显示结果图像
  imshow( window_name, frame );
}

分享结束,第一篇博客,嘻嘻,对了,给链接,http://pan.baidu.com/s/1sjFOBRv

展开阅读全文

没有更多推荐了,返回首页