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

  • 相关阅读:
    LeetCode 83. Remove Duplicates from Sorted List (从有序链表中去除重复项)
    LeetCode 21. Merge Two Sorted Lists (合并两个有序链表)
    LeetCode 720. Longest Word in Dictionary (字典里最长的单词)
    LeetCode 690. Employee Importance (职员的重要值)
    LeetCode 645. Set Mismatch (集合不匹配)
    LeetCode 500. Keyboard Row (键盘行)
    LeetCode 463. Island Perimeter (岛的周长)
    115.Distinct Subsequences
    55.Jump Game
    124.Binary Tree Maximum Path Sum
  • 原文地址:https://www.cnblogs.com/panxiaochun/p/5345412.html
Copyright © 2011-2022 走看看