在之前的那篇文章中:深度学习图像分割(一)——PASCAL-VOC2012数据集(vocdevkit、Vocbenchmark_release)详细介绍 我们大概了解了VOC2012图像分割数据集的基本格式,现在我们来讨论一下我们具体需要什么样的数据格式和我们如何去制作自己的数据集。
实际我们在使用FCN算法进行深度学习训练过程中,对于图像的分割我们只需要两种数据:
一种是原始图像,就是我们要进行训练的图像:
而另一种是可以携带图像分割信息的图像或者标记语言文件,相当于分类中的label,不论是图像还是标记语言文件,我们都可以通过程序来得到我们需要的图像格式,一般来说我们最终需要的结果是一维的图像(这里的一维是指像灰度图一样只有一个通道的图像,图像中像素点只有固定的几个类型像素点,比如背景是0,分割物分别是1、2、3…):
"shapes": [
{
"label": "plane",
"line_color": null,
"fill_color": red,
"points": [
[
54,
120
],
[
85,
115
],
[
118,
116
],
[
164,
127
],
[
212,
145
],
[
259,
161
],
[
272,
165
],
[
280,
157
],
[
283,
142
],
[
288,
122
],
[
292,
109
],
[
298,
110
],
[
292,
167
],
[
297,
173
],
[
299,
178
],
[
356,
175
],
[
363,
177
],
[
363,
180
],
[
497,
174
],
[
498,
180
],
[
452,
184
],
[
397,
189
],
....
]
}
],
"lineColor": [
0,
255,
0,
128
],
"fillColor": [
255,
0,
0,
128
],
"imagePath": "2007_000033.jpg",
"imageData": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUEBAMEBgUGBgYFBgYGBwkIBgcJBwYGCAsICQoKCgoKBggLDAsKDAkKCgr/2wBDAQICAgICAgUDAwUKBwYHCgoKCgoK
...
}
刚才说到在训练过程中,我们投入原图和携带分割信息的图片。
这里有个地方需要注意一下,VOC数据集中的png标记图是8-bit彩色图像:
我们平时使用的彩色图是24-bit真彩色图,也就是RGB三通道都是8bit,值的范围分别是0-255,。而8-bit彩色图则是假彩色图片,这8位中是这样分配的:
Bit 7 6 5 4 3 2 1 0
Data R R R G G G B B
R、G各占3位,B占2位,组合起来能表示256种颜色。
我们通过程序来读取一下:
In[4]: import PIL.Image
# 通过PIL库读取8bit的png标记图
In[5]: img = PIL.Image.open('/home/prototype/Desktop/PycharmProjects/pytorch-fcn-master/examples/voc/VOC/VOCdevkit/VOC2012/SegmentationClass/2007_000039.png')
In[6]: import numpy as np
In[7]: img_32 = np.array(img, dtype=np.int32) # 将读取的png标记图转化为numpy数组
In[8]: import scipy
In[9]: import scipy.io
# 通过scipy库读取携带图像分割信息的.mat文件
In[10]: mat = scipy.io.loadmat('/home/prototype/Desktop/PycharmProjects/pytorch-fcn-master/examples/voc/VOC/benchmark_RELEASE/dataset/cls/2008_000008.mat')
# 取出.mat文件中有关标记信息的部分
In[11]: lbl = mat['GTcls'][0]['Segmentation'][0].astype(np.int32)
In[12]: lbl.shape
Out[12]: (442, 500) # .mat文件中的标记信息格式
In[15]: lbl_r[lbl_r > 0]
Out[15]: array([15, 15, 15, ..., 13, 13, 13], dtype=int32)
In[16]: img_32[img_32>0]
Out[16]: array([255, 255, 255, ..., 255, 255, 255], dtype=int32)
In[19]: img_32[img_32==255] = -1
In[20]: img_32[img_32>0]
Out[20]: array([20, 20, 20, ..., 20, 20, 20], dtype=int32)
我们在通过PIL读取的时候已经将8-bit的图像数据格式进行了转化,将8-bit彩色转化为8-bit灰度图,灰度的值就是这个假彩色的值。而且要注意上面我们把通过PIL读取然后转化为numpy数组的图像进行了这个img_32[img_32==255] = -1
操作,这个操作会作用是什么,我们发现了在png标记图中,每个要分割的内容颜色填充都有一层白色轮廓:
这个白色边框在训练中这白色边框所占的像素点并不参与训练,边框只是为了能够更加清晰地显示要分割的目标,以及更好地和背景进行区分而设置的,实际操作中我们其实是可以忽略的。所以上面的执行代码就是将这些白色边框抹掉,赋予-1值在之后的训练中可以通过操作过滤掉。
制作数据集有很多工具,matlab上面自带工具但是比较繁琐,这里我们使用wkentaro编写的labelme,这个软件是使用pyqt编写的轻量级软件,github地址:https://github.com/wkentaro/labelme。
这是软件界面。
至于软件怎么使用github项目页面上都有详细的介绍,我这也就不多赘述了。
唯一需要注意的是这个软件标记出来的文件是json文件,然后通过python代码将json文件转化为我们需要的png标记图,这个标记图的读取方式和我之前写的类似,作者也是建议使用PIL去读取然后转化为numpy格式,最后转化为上面说到的我们需要的格式:
# see load_label_png.py also.
>>> import numpy as np
>>> import PIL.Image
>>> label_png = 'apc2016_obj3_json/label.png'
>>> lbl = np.asarray(PIL.Image.open(label_png))
>>> print(lbl.dtype)
dtype('int32')
>>> np.unique(lbl)
array([0, 1, 2, 3], dtype=int32)
>>> lbl.shape
(907, 1210)
大概就说这么些,下篇文章介绍使用FCN做图像分割训练的原理。
文章来源于:https://oldpan.me/