使用Opencv训练自己的级联分类器

4 篇文章 0 订阅
1 篇文章 0 订阅

最近需要实现一个模式识别的项目,要识别鱼并计数但是我不会搭建神经网络实现物体识别,以前了解过opencv记得可以训练分类器,所以用opencv来训练自己的级联分类器这里记录一下过程和踩过的坑.

环境

opencv3.X
ubuntu16.04
cmake


这里可以不下载opencv,直接使用opencv_createsample.exe 和opencv_traincascade.exe就可以完成训练,网上有下载.网上有使用opencv_harrcascade.exe这个工具是在opencv2.x以前使用过官方在3.x后不在支持了改用opencv_traincascade.exe训练工具下载

如果不下载训练工具就需要编译opencv,opencv的下载和编译比较简单,但容易出问题,在官网下载opencv的代码和需要的依赖工具,创建一个空目录,进入该目录,cmake编译就行了.这几个工具在/bin目录下

#把opencv的代码放在这个目录中
mkdir OpencvInstall/
#在代码的同级目录下创建build目录
mkdir build/
cd build
cmake ..
make

如上命令就把整个项目编译完成了,这里注意不要编译部分代码,因为整个项目的每个目录中都有CMakeList.txt文件,可以编译,但是会报错.编译整个项目就不会报错了.

训练过程

在环境准备就绪后,就是重要的训练过程了.首先创建一个目录结构如下
在这里插入图片描述
neg/ 目录存放负样本,即不还有要检测的物体
pos/ 目录存放正样本数据,即包含要检测的物体
xml/ 目录存放训练后的分类器,是个xml文件
pos.vec 是opencv_createsamples创建的.vec文件生成的文件
opencv_createsamples是用于创建样本和vec文件的程序
opencv_traincascade是用于训练的程序
neg.txt是包含负样本的绝对路径+文件名生成的文件

/path/to/file.jpg
/path/to/fiel2.jpg
...

pos.txt存放正样本的绝对路径+文件名+图片中要识别物体个数+左上角坐标+物体的长+ 物体的宽生成的文件

/path/to/file.jpg  1  0 0 20 20
/path/to/file2.jpg 2  0 0 20 20  50 30 25 25
...

首先注意,正样本可以自己收集也可以通过opencv_createsamples创建,官方文档上说对于刚性物体比如logo可以通过生成来创建正样本,这样可以简化操作也可以自己收集,比如人脸等最好自己收集图片来形成正样本.对于正负样本的数量官网上并没有具体说明,官网文档也是说网上说一般在成百到上千的数据量效果好,这里我查了一些文档和博客有的说是最好正负样本比1:3,但是还要看个体差异具体分析.
我在训练过程中走了许多弯路,第一次是正样本数200,负样本数200,第二次是正样本数736,负样本数500,第三次是正样本数1070,负样本数2200.根据效果来看数量级肯定越大越好,但是正负样本比例并没有要求 但是在训练时正负样本比例最好是2:1或者3:1
还有就是图片的大小在准备时正负样本大小只要比检测窗口大就行了比如30x30等等,但是在训练时生成的图片一般选择20x20的,当然这个没有具体的要求.

总结一下就是在样本准备阶段,正负样本的数量越多越好,大小要保持一致且要大于检测窗口大小(检测窗口多大我也不知道,hahaha~),且要灰度化,正样本最好没有背景,在训练阶段,样本的大小要和正样本的大小一样,且正负样本比例要保证在2:1以上.
在这里插入图片描述在这里插入图片描述
关于正样本的创建可以通过一个样本来生成,但是前提你要有负样本数据,即neg.txt,opencv_createsampels创建正样本是把你给的图片各种扭曲拉伸然后与负样本做背景合成新的图片,这也就是在官网和许多博客上说负样本叫背景图片的原因了.关于负样本的选择可以是任意不包含待检测物体的图片,但是还是建议根据应用场景适当选择.

创建正样本
./opencv_createsamples -img  pos.jpg -bg neg.txt -info pos.txt -pngoutput pos/ -maxxangle 0.5 -maxyangle 0.5 -num 2000

-img 创建正样本使用的图片
-bg 背景图片的文件
-info 产生包含正样本数据信息的文件
-pngoutput 正样本的输出目录
-num 产生的样本数量
如果是自己准备图片的话,pos,txt和neg.txt要自己准备好

生成vec文件
./opencv_createsample -vec pos.vec -info pos.txt -num 2000 -w 20 -h 20

-vec 后面是要生成的vec文件
-num 是正样本的数量
-w,-h 是图片的大小,这里不是图片真正的大小,比如真正图片大小是50*50,只是要写到这个文件里面的信息
在这里插入图片描述

训练级联分类器
./opencv_traincascade -data classifier -vec pos.vec -bg neg.txt -numStages 10 -minHitRate 0.999 -maxFalseAlarmRate 0.5 -numPos 1800 -numNeg 900 -w 20 -h 20 -mode ALL -precalcValBufSize 1024 -precalcIdxBufSize 1024 -featureType LBP

这里需要注意如果在训练过程中报错或者N<=2或者训练后生成的.xml文件数少于你设定的层数都是训练不成功,比如我的训练层数是10但是生成了5个stage.xml就证明没有训练完成,但是生成的cascade.xml还能用,就是检测效果不好.
注意,在训练完成后如果成功完成,生成的stage.xml文件会大于层数.因为级联分类器是多个分类器分层处理的,在训练完成后官网上说中间生成的这些文件可以删掉,因为用的话也只用cascade.xml但是建议在运行一遍训练命令只不过把-numStages的数字改为所有stage文件的数量和,这样就会把每个stage的数据进行合成,与原声生成的cascade.xml文件相比就是数据量会大些
还有一个比较重要的点就是在使用分类器时有一个detectMultiScale函数,因为在训练时使用的图片大小是20*20的,所以分类器在检测时会对小一些的图片匹配的效果会好些,如果匹配的太多可以改改这个函数的参数,具体可以查查官方文档.官方文档
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

测试代码与结果展示
import cv2 as cv
imgPath = "/home/yuan/Downloads/ImageAssistant/serpae_tetra/duo.jpeg"
path = "./data/pics/xml/cascade.xml"
detector = cv.CascadeClassifier(path)
img = cv.imread(imgPath)
print("img load success")
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
#gray = cv.equalizeHist(gray)
fish = detector.detectMultiScale(gray, 20, 30)#这里的参数自己测试试试
for (x,y,w,h) in fish:
    cv.rectangle(img, (x,y), (x+w,y+h),(255,0,0),2)

cv.imshow("img", img)
if cv.waitKey(0) & 0xFF == 27:
    cv.destroyAllWindows()

我的这个效果不太好,背景也可以检测出来.凑活着看吧.
在这里插入图片描述在这里插入图片描述

参考

https://www.bilibili.com/video/av13924091/?p=17
https://docs.opencv.org/3.4.7/dc/d88/tutorial_traincascade.html
https://docs.opencv.org/3.4.7/db/d28/tutorial_cascade_classifier.html
http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/user_guide/ug_traincascade.html
https://blog.csdn.net/guwuchangtian/article/details/73838650
https://blog.csdn.net/weixin_41799483/article/details/80567909
https://blog.csdn.net/qq_32502511/article/details/79010509
https://blog.csdn.net/yangdashi888/article/details/80385041
https://zhuanlan.zhihu.com/p/26390670
https://www.kancloud.cn/aollo/aolloopencv/267591

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

siyan985

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值