语义分割标签制作全过程(适合新手)

本人刚接触这方面不久,在网上搜索了很多文章,发现很多文章都存在一些弊端,自己做了一些总结,方法比较基础,但亲测有效。
首先,我们得有一些原始图片,然后通过labelme标注后得到json文件(labelme使用大家可以去搜一下),接下来我们需要做的是将json文件转换为可用于训练的标签集。
网上很多说python中自带了一个脚本json_to_dataset.py可以转换(路径在python安装路径下,比如我的是在D:\python3.6.7\Lib\site-packages\labelme\cli中),调用方法是在cmd下输入: labelme_json_to_dataset <文件名>.json,就可以得到标签图片(保存路径就是json文件目录下),但有一个问题就是,一次性只能转换一张标签,这多麻烦啊。于是,很多人写了脚本,可以批量化转换,但就我目前看到批量转换脚本,大多存在着一个致命的问题,就是对于不同图片,他的类别标注是对应不上的(这些脚本只是负责把图送到json_to_dataset.py,并没有对标签进行其他处理),看下图:
语义分割标签制作全过程(适合新手)_第1张图片 语义分割标签制作全过程(适合新手)_第2张图片
从上面两张图片可以看出,两种完全不是同一类别的东西都被赋予相同的颜色(也即相同标签),这肯定不是我们想要的。
然后就想尝试了一个比较官方的方法:先将json文件转换为voc格式的文件(为什么要这样做呢,因为voc格式算是比较官方的格式,针对其的转换程序也是正规的,解决了批量转换和不同类别时被赋予不同的像素的问题),然后就在github上找打了一个voc的转换脚本,链接在这里:https://github.com/wkentaro/labelme/tree/master/examples/semantic_segmentation,里面有教程教你怎么调用,这里就直接写下吧,cmd下输入:
python ./labelme2voc.py(尽量写绝对路径) 图片和json文件存放的路径(放在一起) 保存路径 --labels labels.txt路径(中间都是空格隔开)
这里需要注意的是,你需要将你自己的标签类别制作成一个txt文本(也就是上面调用命令中的labels.txt),你可以仿照上面那个链接中的labels.txt做,这个程序会根据你的类别去转换,然后你就会得到四个文件夹,其中有用的只有两个JPEGImages(原图像),SegmentationClassPNG(voc格式的标签图像),转换后的标签如下图所示:
语义分割标签制作全过程(适合新手)_第3张图片 语义分割标签制作全过程(适合新手)_第4张图片
可以看到,两种不同的东西被赋予了不同的标签,但是这种图片是索引图(索引图是为了增强灰度图的差异性,其实他也是单通道的,只不过每一个灰度都对应着一种颜色),如果你的模型是要求索引图作为标签,那么到这里就已经完成了;如果你的模型是要求灰度图作为标签,那么还得进行第二步转换(错把索引图当做灰度图作为标签,可能出现label out of boundary的错误提示),即将voc格式的索引图转换为可用于训练的灰度图(看上去是全黑的)。这里有两种方法:
1.先读取索引图中各种类别的像素值,然后一一改过来,比如上面球像素值是125,然后遍历就把所有图片中的125的像素值都改为1(表示第一个类别),而红色的是225,就把所有图片中的225都改为2,然后再保存为灰度图格式就可以了。这种方法对于类别较多的就比较麻烦,而且遍历每一个像素值耗时很大。
2.第二种是我在网上找到的转换脚本,很快很好用


"""Removes the color map from segmentation annotations.
Removes the color map from the ground truth segmentation annotations and save
the results to output_dir.
"""
#源程序链接:https://github.com/tensorflow/models/tree/master/research/deeplab/datasets
#该程序用于将voc格式的索引图片转换为可用于语义分割的灰度图片,因为TensorFlow版本的缘故,在原程序上做了少许改动
#tf.__version__==1.12

import glob
import os.path
import numpy as np
from PIL import Image
import tensorflow as tf

#FLAGS = tf.compat.v1.flags.FLAGS
FLAGS = tf.flags.FLAGS
tf.flags.DEFINE_string('original_gt_folder',#读取voc格式的png图片路径
                                 'F:\Dataset_segmentaion\data_dataset_voc\SegmentationClassPNG',#default
                                 'Original ground truth annotations.')#help
tf.flags.DEFINE_string('segmentation_format', 'png', 'Segmentation format.')
tf.flags.DEFINE_string('output_dir',#保存路径
                                 'F:\Dataset_segmentaion\data_dataset_voc\labels',
                                 'folder to save modified ground truth annotations.')


def _remove_colormap(filename):
  """Removes the color map from the annotation.
  Args:
    filename: Ground truth annotation filename.
  Returns:
    Annotation without color map.
  """
  return np.array(Image.open(filename))


def _save_annotation(annotation, filename):
  """Saves the annotation as png file.
  Args:
    annotation: Segmentation annotation.
    filename: Output filename.
  """
  
  pil_image = Image.fromarray(annotation.astype(dtype=np.uint8))
  '''
  with tf.io.gfile.GFile(filename, mode='w') as f:
  #with open(filename, mode='w') as f:
    print(f)
    pil_image.save(f, 'PNG')
    '''
  pil_image.save(filename)


def main(unused_argv):
  # Create the output directory if not exists.
  if not os.path.exists(FLAGS.output_dir):
    os.makedirs(FLAGS.output_dir)
  #if not tf.io.gfile.isdir(FLAGS.output_dir):
    #tf.io.gfile.makedirs(FLAGS.output_dir)

  annotations = glob.glob(os.path.join(FLAGS.original_gt_folder,
                                       '*.' + FLAGS.segmentation_format))
  for annotation in annotations:
    raw_annotation = _remove_colormap(annotation)
    filename = os.path.basename(annotation)[:-4]
    _save_annotation(raw_annotation,
                     os.path.join(
                         FLAGS.output_dir,
                         filename + '.' + FLAGS.segmentation_format))


if __name__ == '__main__':
  #tf.compat.v1.app.run()
  tf.app.run()

只需要将上面存放voc格式的png图像路径以及保存路径改成你自己的路径即可,转换后的图片是这样的:
语义分割标签制作全过程(适合新手)_第5张图片 语义分割标签制作全过程(适合新手)_第6张图片
你没有看错,就是全黑的,但只是看上去,除了背景像素值为零,其他的像素值不是零(可以调用np.unique(image)看看),比如你有21个类别,那么,对应的像素就是0-21,但看上去就是一团黑,不好分辨,因此才有了上面的索引图。到这里,标签图片就只做完成了,希望对大家有帮助。

你可能感兴趣的:(深度学习)