最近需要做一个目标分割任务,但是没啥经验,所以准备从基础搞起,先学习如何使用经典的MaskRCNN来实现检测任务。
MaskRCNN的原始版本是用TensorFlow写的,但是我没啥TensorFlow的经验,Pytorch稍微熟悉一点,而且去网上查了下都说Pytorch版本的MaskRCNN好像训练速度更快、效果更好一些,这一点就不发表看法了。
MaskRCNN的数据集要比一般的分类任务、目标检测任务、语义分割任务的数据集都复杂一些,因为需要标注出不同种类的物体轮廓,同种物体的不同个体之间也要编号,如果只是练习使用MaskRCNN,网上有很多现成的数据集,最经典的就是COCO,大家可以自己去看看怎么安装,建议用Anaconda3安装,报了错也挺麻烦的。
但是真正要用MaskRCNN,那基本都是有自己的检测目标,所以如何将自己的目标图片做成数据集,其实网上也有很多教程,尤其是视频教程,非常建议大家跟着视频教程去做,我已经受够了那些粗略的文字教程,有的根本搞不清楚。
这篇博客倒也不是有什么原创性,只是把制作MaskRCNN数据集的步骤详细的记录下来,也方便自己做的时候来翻找。
安装labelme
首先先安装Anaconda3,不说了,教程一大堆一大堆。(本文都是Windows系统下, linux系统下的教程应该更多。)
在开始菜单进入Anaconda3 - Anaconda Prompt,打开命令行窗口,现在你应该处于一个base的虚拟环境里。你可以新建一个虚拟环境,然后把labelme装在新虚拟环境里,直接装在base环境里也可以。
在Anaconda命令行输入以下命令:
conda create --name=labelme python=3.6 # 这里只是给个例子,其实完全不需要新建一个环境只装个labelme
conda activate labelme # 安装labelme
如果之前装过labelme,需要更新升级,则使用:
pip install --upgrade labelme
使用labelme进行标注
准备工作
(1)新建一个大文件夹Dateset
(2)在Dataset下新建一个图片文件夹images(文件夹名可任取,后面指令里记得改就行),把待标注的图放进去,格式最好是jpg(png也行),图片尺寸建议长边不要超过1000pixel,虽然理论上MaskRCNN对输入图片的尺寸没有要求,但是图片尺寸过大(3000*4000以上)有可能导致CUDA out of memory(懂得都懂)
(3)在Dataset下新建一个labels.txt文件(文件名可任取,后面指令里记得改就行),其中存放你准备识别的类别的标签,有两个标签是必须的(永恒的第一个和第二个标签):
__ignore__ # 前后各两个下划线
_background_ # 前后各一个下划线
然后是你自己要识别的类别标签,往后分行列就行,比如我要识别cable、clip、jointer三类:
至此,准备工作结束。
图片标注
在Anaconda Prompt中,使用cd命令,cd到Dataset文件夹的位置,然后输入以下命令:
labelme images --labels labels.txt --nodata --validatelabel exact --config '{shift_auto_shape_color: -2}'
这行指令中,images是图片文件夹名,labels.txt是标签文件名,如果命名时有改动,这里也记得修改。
有时由于版本不同(通常是安装时labelme版本过新),这句指令会报错,报错的处理方法倒也有,但是没必要那么麻烦,直接把最后的一部分去掉,就能正常运行。
labelme images --labels labels.txt --nodata --validatelabel exact
然后,会打开一个labelme窗口,在这个窗口进行标注。
或者你也可以不用上述指令,直接在命令行中输入:
labelme
也能打开标注界面,然后在左侧选择open dir,打开刚才建好的图片文件夹。
在开始标注前,建议先点击一下file,选择save automatically,就能自动保存,不需要每标完一张图再专门去保存了。
开始标注,点击Create Polygons,然后用鼠标围着你要标注的物体轮廓走一圈,尽量贴合轮廓,最后一个点点击第一个点闭合,然后会自动跳出该界面:
这是已经建好了三个类,如果没有的话,就Enter object label,建过一次后就会有记录。
扣轮廓的时候如果觉得上个点的位置不行,想取消,就敲一下backspace就行,敲一次取消一个点。如果已经闭合,就点Edit Polygons,可以拖动单个点,或者拖动整个区域进行调整。
最后标好的图片大致如下:
这里不同种类的零件的框颜色都是绿色,这就是因为上面,运行时去掉了--config '{shift_auto_shape_color: -2}'
这一段指令,当然不影响接下来的操作,不同颜色的框的作用主要就是提醒你label有没有标错,一般不会标错的。
标注完一张图片后,点击Next Image,图片会自动保存一个对应的jason文件,然后跳到下一张待标注图片,一直标完即可。
用标注结果生成VOC格式的数据集
这里用到labelme github上提供的labelme2voc.py,大家可以去搜
https://github.com/wkentaro/labelme/tree/master/examples
也可以新建一个py文件,把下面的代码粘进去(或者直接复制粘贴成txt文件,然后把文件名后标改成.py文件):
如上图,examples底下有两个文件夹里都有labelme2voc文件,一个是semantic_segmentation,语义分割,一个是instance_segmentation,实例分割。我的目标是做实例分割,不仅需要切割出语义,也要切割出个体,所以选用了instance_segmentation下的labelme2voc.py文件。(而且instance_segmentation下的labelme2voc文件生成的数据集中也包含有做语义分割需要的数据集,一举两得)
把该py文件移动到Dataset文件夹下,和labels.txt和images文件夹同级。
然后,在Anaconda3 Prompt中,cd到Dataset文件夹,然后运行以下指令:
python labelme2voc.py images target --labels labels.txt
其中,target是输出目标文件夹名,可自行改动。target文件夹里面内容很多,然后就会自动生成数据集:
这里面,JPEGImages是原图,然后SegmentationClassPNG里面,则是语义分割级别的png遮罩图片;SegmentationObjectPNG则是实例分割级别的png遮罩图。
而SegmentationObjectVisualization里面则是原图+遮罩的叠加图,主要用来看看。最终用的上的两个文件夹就是JPEGImages和SegmentationObjectPNG两个。