OpenCV自学笔记13. 训练自己的分类器

来源:互联网 发布:股票庄家是谁 知乎 编辑:程序博客网 时间:2024/06/01 12:59

训练自己的分类器

本小节使用的图片为:

这里写图片描述

最近在项目中遇到了一个问题,需要识别图像中的红色圆形。首先尝试了Hough圆形检测,详细请见这篇文章
http://blog.csdn.net/u010429424/article/details/72989870

Hough变换的效果还可以,但是存在计算量大等问题,因此,还需要一种更为准确的方法,识别图像中的圆形。

在此前提下,我尝试训练级联分类器,尽管分类器的效果不甚理想,但是也收获颇丰。现把训练过程记录如下。

——把大象装进冰箱里需要几步?
——三步
——训练自己的分类器也不例外,三步

首先,准备正样本和负样本数据
然后,训练,得到分类器
最后,测试,看看分类器好不好用

详细步骤如下:

Step1. 准备正样本和负样本数据

不像人脸识别那样,有现成的数据集。有时候,针对特定的问题,需要我们自己构建正负样本。

(1). 正样本的构建
大家可以根据自己的问题构建正样本。在这个问题中,我通过录制视频,得到视频中每一帧的图像。对这些图像,利用Hough圆形检测的方法,分割出圆形区域,将圆形区域作为图像,保存到文件中,最后通过人工的方式删除误检的图形。最后构建了大约800个正样本。

这里写图片描述

注意: 正样本要求所有图片的大小必须统一,OpenCV中推荐的大小是20 * 20(我这里是32 * 32)。对于大小不一致的图像,可以通过

dst = cv2.resize(src, (32, 32), interpolation=cv2.INTER_AREA)

将图像大小缩放至32 * 32。

(2). 负样本的构建

负样本的构建就容易多了。只要图像的尺寸大于等于正样本图像就可以了。你可以用一些阿猫阿狗的图像,也可以用一些大海森林的图像,但是不推荐用这些图像当做负样本。应该根据实际问题,把常见的场景拿来做负样本。

我将视频中的每一帧图像,进行切割,得到负样本。 具体说来,帧图像的大小是480 * 640,按照32 *32的大小,均分成300张小图片。然后通过人工的方式,排除近似于正样本的小图片,剩下的就是负样本图片。对视频中每一帧都进行上述切割,最后得到一组负样本。当然,也可以按照48*64进行切割,只要保证负样本图片的尺寸大于等于正样本就可以。切割的步骤,可以参考这篇文章。
http://blog.csdn.net/u010429424/article/details/74377617

负样本的数量大约为2100个,网上推荐正样本和负样本的比例大致在1 : 2到1 : 3之间

这里写图片描述

(3). 把正样本和负样本的路径,写到文件里

什么是“把正样本和负样本的路径写到文件里”呢?比如你正样本在C://your/path/1.jpg,就把C://your/path/1.jpg
写到一个文件中,专业名词叫做路径列表,这里可以写绝对路径,也可以写相对路径。

方法有很多,我这里使用几行Python代码,实现了这个功能。当然你也可以用Java写,用C写,甚至自己写一个.bat脚本。

正样本的处理代码如下: 其中 0 0 32 32 表示红色圆形在图像中的范围,也就是正样本图像的大小。

path = 'train_img_set/ball/'dir = os.listdir(path) # 自动排序fopen = open('train_img_set/info.txt', 'w')for d in dir:    string = 'ball/' + d + ' 1 0 0 32 32' +'\n'    fopen.write(string)fopen.close()

负样本的处理代码如下:

path = 'train_img_set/non-ball/' # 替换为你的路径dir = os.listdir(path) # dir是目录下的全部文件fopen = open('train_img_set/bg.txt', 'w') # 替换为你的路径for d in dir: # d是每一个文件的文件名    string = 'non-ball/' + d + '\n' #拼接字符串并换行    fopen.write(string) # 写入文件中fopen.close()

正样本如下:
这里写图片描述

负样本如下:
这里写图片描述

(4). 生成正样本的描述文件

在cmd中 用一行命令搞定:

opencv_createsamples.exe -info info.txt -vec pos.vec -num 697 -w 32 -h 32

命令行参数如下:

-info 正样本说明文件

-vec 输出文件,内含用于训练的正样本。

-num 生成的正样本的数目。

-w 输出样本的宽度(以像素为单位)。

-h 输出样本的高度(以像素为单位)。

注:除了上述参数外,还可以配置其他参数,详细请见
http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/user_guide/ug_traincascade.html

在命令行中运行这个命令后,可以得到一个叫 pos.vec 的文件

注意,在运行前,需要用到opencv_createsamples.exe,这个文件可以从网上下载,也可以在OpenCV的安装目录下找到,我的是:D:\Program Files\OpenCV\OpenCV-249\opencv\build\x64\vc10\bin

Step2. 对样本进行训练

准备好样本后,对样本进行训练,使用一行命令:

opencv_haartraining.exe -data xml -vec pos.vec -bg bg.txt -nsplits 1 -npos 150 -nneg 450 -nonsym -w 32 -h 32 -mode all -mem 1280

命令行参数如下:

-data 目录名,用于存放训练好的分类器。

-vec 包含正样本的vec文件名(由 opencv_createsamples 程序生成)。

-bg 背景描述文件,也就是包含负样本文件名的那个描述文件。

-numPos 每级分类器训练时所用的正样本数目。

-numNeg 每级分类器训练时所用的负样本数目,可以大于 -bg 指定的图片数目。

-numStages 训练的分类器的级数。

-w 训练样本的宽(单位为像素)

-h 训练样本的高(单位为像素)

必须跟训练样本创建(使用 opencv_createsamples 程序创建)时的尺寸保持一致。

-mode all指定haar特征的种类,all表示使用垂直以及45度旋转特征

参数的详细说明请见:
http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/user_guide/ug_traincascade.html

注意,在运行前,需要用到opencv_haartraining.exe,这个文件的找法与opencv_createsamples.exe类似(见上文)。

训练的过程如下所示:

这里写图片描述

这里写图片描述

我在训练的过程中,程序会死掉(无法结束),可能是由于正负样本负样本差距不大所致,还需要继续研究一下。

程序死掉也别急,在xml目录下能看到生成了0、1、2、3几个文件,这些文件是训练时,各层的中间文件。我们可以使用convert_cascade.exe生成最后的xml文件,convert_cascade.exe可以从网上下载。

命令如下:

convert_cascade --size=32x32 C://Users//lijialin//PycharmProjects//Hockey//train_img_set//xml C://Users//lijialin//PycharmProjects//Hockey//train_img_set//xml//haar_adaboost.xml 

这里写图片描述

最后,在xml文件中,能看到一个haar_adaboost.xml文件,这个文件就是我们的通过训练得到分类器。

接下来测试这个分类器的效果。

Step3. 测试

测试程序如下:

cascade = cv2.CascadeClassifier('train_img_set/xml/haar_adaboost.xml')img = cv2.imread('images/1111.png')cv2.imshow('img', img)gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)circles = cascade.detectMultiScale(gray, 1.3, 5)if faces is not None:    # x, y, w, h = circles[0]    for (x, y, w, h) in faces:        cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)cv2.imshow('img', img)cv2.waitKey(0)cv2.destroyAllWindows()

测试结果如下,首先对一幅简单图片进行测试,可以看出,分类器准确地识别出了图像中的红色圆形:

这里写图片描述

然后对一幅稍微复杂的图片进行测试,可以看到,分类器仅仅识别出了部分红色圆形,准确率是很低的,大概 4 / 9 = 44.4%:

这里写图片描述

参考资料:

训练分类器:
http://blog.csdn.net/yangleo1987/article/details/52883864
http://blog.csdn.net/woaipaoche/article/details/41517089
http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/user_guide/ug_traincascade.html
http://blog.csdn.net/autoliuweijie/article/details/51911289

Hough识别圆形:
http://blog.csdn.net/u010429424/article/details/72989870

图像切割:
http://blog.csdn.net/u010429424/article/details/74377617

Python获取目录下的全部文件名,并写入文件中:
http://blog.csdn.net/u010429424/article/details/74390342

今天就到这里吧~

这里写图片描述

原创粉丝点击