zoukankan      html  css  js  c++  java
  • opencv_haar分类器的训练

    本文为作者原创,未经允许不得转载;原文由作者发表在博客园: http://www.cnblogs.com/panxiaochun/p/5345412.html

    HaarTraining步骤

    1.正负样本处理

    正样本处理需要对正样本进行归一化处理,一般情况下可以用Photoshop对图像进行尺寸统一处理,比如都是20*20或者24*24,其中其它尺寸比如240*15也可以做成样本的,不要求是正方形,或者20*20,24*24,。这是取决于你的目标的形状,不过正样本的分辨率不要太高,太高的话在训练时会内存分配不足引起crash

    错误如下:  OpenCV Error :insufficient memory <failed to allocate 250343435bytes> in cv::OutOfMemoryError

    memory1memory2

                                                           图1.1 正样本分辨率太大时引起的内存分配不足的crash

    不预先用Photoshop对正样本进行处理时,还可以使用opencv_createSamples工具进行处理,其实就算用Photoshop对样本进行过处理,在这里还是会对样本进行一次处理,Photoshop预先处理的好处就是样本的位置都为0,0。那么对正样本描述文件处理时就比较简单,特别是正样本数量足够大时,可以减少正样本描述文件的出错率,提高分类器的检测率。

     

    1.1正样本描述文件

    正样本描述文件的创建如下:

    一个.txt文件或者.dat文件里面包含正样本的信息,

    结构:

    包含正样本图片的相对路径或者全路径    正样本中包含的正样本数量    第一个正样本的位置x y   第一个正样本的宽和高w h  第二个正样本的位置x y   第二个正样本的宽和高w h  ……  第n个正样本的位置x y   第n个正样本的宽和高w h 

    img01.jpg 1 0 0 20 20

    img\img02.jpg 1 0 0 24 24

    e://img/img03.jpg 2 3 4 240 15 248 29 160 20

    ….

    在这里你就会明白为什么要在之前用Photoshop对图片进行处理,这样的话,所有图片都是只包含一个正样本的统一尺寸的图片,那么正样本描述文件就像下面那样:

    img01.jpg 1 0 0 20 20

    img02.jpg 1 0 0 20 20

    img03.jpg 1 0 0 20 20

    ……

    既然是是统一的话,就可以用批处理来完成:

    在Windows下用命令: dir imgDir /b > imgDiscr.txt

    (在linux下用: ls imgDir >imgDiscr.txt ,也可以保存为.sh文件,这样不用每次输入命令)

    我是直接保存为.bat文件,这样每次不用打命令,而是点击就生成包含所有正样本图片名的文件imgDiscr.txt :

    img01.jpg

    img02.jpg

    img03.jpg

    ….

    然后用编辑器打开,把jpg替换成jpg 1 0 0 20 20

    就可以快速生成正样本描述文件。

     

    1.2负样本描述文件的生成

    和正样本一样,不过不需要对负样本图片进行处理,只要负样本图片不比正样本图片的分辨率小就行,负样本描述文件只需要包含图片路径名:

    non-img01.jpg

    non-img02.jpg

    non-img03.jpg

    ….

    2.opencv_createsamples生成正样本.vec文件

    分类器在训练时并不会直接处理正样本描述文件,而是包含正样本的.vec文件,这是一个用matlab函数生成的向量文件。

    参数的设定如下:

    opencv_createsamples.exe -info imgDiscr.txt -vec samples.vec  -num 68  -w 20-h 20

    命令行参数:

    • [-vec <vec_file_name>]  输出文件,内含用于训练的正样本
    • [-img <image_file_name>] 输入图像文件名(例如一个公司的标志
    • [-bg <background_file_name>] 背景图像的描述文件,文件中包含一系列的图像文件名,这些图像将被随机选作物体的背景。
    • [-mun <number_of_samples>]生成的正样本的数目。
    • [-maxxangle <max_x_rotation_angle>]X轴最大旋转角度,必须以弧度为单位。
    • [-maxyangle <max_y_rotation_angle>]Y轴最大旋转角度,必须以弧度为单位。
    • [-maxzangle <max_z_rotation_angle>]Z轴最大旋转角度,必须以弧度为单位。
    • [-w <sample_width >] 输出样本的宽度(以像素为单位)
    • [-h <sample_height >]输出样本的高度(以像素为单位)。

    其中-num的数值应该为总的正样本数,也就是正样本描述文件中第二列数字总和

    -w -h是输出图像的宽和高,这里也会对正样本进行归一化处理,其中我们之前用Photoshop对图像进行过归一化处理,如果没有,那么在这里createsample工具也会对正样本进行归一化处理,所有的正样本大小都是一样的。而且,之前Photoshop归一化为20个像素后,在这里设置为24个像素,那么生成的.vec向量文件里面的图像是24个像素的。

    3.haarTraining训练分类器

    opencv_haarTraining训练器是一个被淘汰的训练器,在2.4.9里面还有,2.4.10后就没有了,不过用opencv_traincascade训练出来的分类器在示例程序中无法使用,而且3.10的opencv_traincascade在使用时出现问题,所以迫不得已找回了以前的haarTraining来使用。其中opencv_traincascade出现的错误如下:

    Train dataset for temp stage can not be filled.  Branch training terminated

    stackoverflow上的说是描述文件是在Windows下生成的,结尾是/r/n,而linux下的描述文件后面是/r没有/n,所有导致读取不到图像文件,但是在linux下训练时还是会出现问题,所以,我觉得问题不在描述文件上。训练分类器用以下命令:

    opencv_haartraining.exe -data block_xml/ -vec samples.vec -bg non-imgDiscr.txt -nstages 20 -nsplits 2 -minhitrate 0.999 -maxfalsealarm 0.5 -npos 200 -nneg 20 -w 240 -h 15 -mem 1024 -eqw 1 -mode ALL -bt GAB -minpos 32

    这里的正样本数量为200,负样本数量为20,样本的宽为240,高为15

    正样本最小命中率为0.999,因为级联-nstages为20,所以0.999^20 = 0.98 负样本的最大错误率为0.5 经过20个级联后错误率为0.5^20 = 0.0000009536
    基本参数:

    " -data <dir_name>
    "
     " -vec <vec_file_name>
    "
     " -bg <background_file_name>
    "
     " [-npos <number_of_positive_samples = %d>]
    "
     " [-nneg <number_of_negative_samples = %d>]
    "
     " [-nstages <number_of_stages = %d>]
    "
     " [-nsplits <number_of_splits = %d>]
    "
     " [-mem <memory_in_MB = %d>]
    "
     " [-sym (default)] [-nonsym]
    "
     " [-minhitrate <min_hit_rate = %f>]
    "
     " [-maxfalsealarm <max_false_alarm_rate = %f>]
    "
     " [-weighttrimming <weight_trimming = %f>]
    "
     " [-eqw]
    "
     " [-mode <BASIC (default) | CORE | ALL>]
    "
     " [-w <sample_width = %d>]
    "
     " [-h <sample_height = %d>]
    "
     " [-bt <DAB | RAB | LB | GAB (default)>]
    "
     " [-err <misclass (default) | gini | entropy>]
    "
     " [-maxtreesplits <max_number_of_splits_in_tree_cascade = %d>]
    "
     " [-minpos <min_number_of_positive_samples_per_cluster = %d>]
    ",

    要注意的是 –nneg 的参数 = 实际的负样本数 * maxfalsealarm

    因为第一次训练完成后,第二个级联的负样本数其实并没有百分百留下,其中有误判的负样本没有加载,所以-nneg如果为实际的负样本数,那么程序很有可能进入死循环,如果样本数不大,但是几个小时后还没有动静,那么就是进入死循环了,像上面的200个正样本,20个负样本基本上前10个级联是一分钟内完成,后面的级联几分钟一个,如果超过十分钟没有动静,那么就是进入死循环了。在这里,参数设置不正确,那么就会训练不成功,还有一个进入死循环的可能就是虚警率一直不能下来,就是maxfalsealarm的值一直居高不下,所以训练器一直在跑,导致结果一直不能停,如果训练一段时间,还在训练,参数没有问题的话,那么就应该适当的设置级联的数量,来停止训练,得到分类器。

       用opencv_traincascade来训练的话可以结合TBB来多核处理,在

    编译opencv时加入TBB。

      用opencv_haarTraining训练出来的分类器会保存在当前目录下用-data的参数命名的xml文件里。

    训练的过程可以随时停止,重新训练时,训练器会读取之前的参数,从停止的地方开始。

    训练结束:

    training1

  • 相关阅读:
    从头编写 asp.net core 2.0 web api 基础框架 (1)
    希腊字母表
    Python数据分析(二): Numpy技巧 (4/4)
    Python数据分析(二): Numpy技巧 (3/4)
    Python数据分析(二): Numpy技巧 (2/4)
    OLED液晶屏幕(3)串口读取文字并分割
    OLED液晶屏幕(2)取模软件
    OLED液晶屏幕(0)自动获取12ic地址液晶屏幕
    OLED液晶屏幕(1)OLED液晶屏幕ssd1306驱动芯片 arduino运行 ESP8266-07可以 12f不可以
    I2C 连接 12864 OLED 屏幕
  • 原文地址:https://www.cnblogs.com/panxiaochun/p/5345412.html
Copyright © 2011-2022 走看看