语义分割动手实践-bisenetv2模型训练

语义分割动手实践 - bisenetv2、deeplabv3+语义分割模型训练

接上文https://blog.csdn.net/Hu_helloworld/article/details/118610897?spm=1001.2014.3001.5501

我们已经可以通过labelme工具标注语义分割数据,然后根据labelme提供的labelme_json_to_dataset脚本,将所有json文件批量生成如下的训练数据:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tXa5wUXr-1635840679764)(https://raw.githubusercontent.com/RoboCuper-hujinlei/markdown-images/main/20210709171227801.png)]

然后我们通过方法

1、moveSrcMasksImage()分别将原图(img.png)和掩膜图像(label.png)移动整理到JPEGImages和SegmentationClass文件夹。

2、通过couple_img_masks()方法制作、划分数据集。

deeplabv3+训练

这样划分出的数据集是一个原图img.png对应一个根据类别颜色分割的掩膜图像label.png。

采用VOC格式的数据集,img.png 和 label.png分别放入JPEGImages和SegmentationClass文件夹中,划分数据集将文件名写入train.txt和val.txt。训练时可选择resnet、mobilenet等多个backbone

用这样的数据集训练deeplab系列模型没问题。具体使用参见官方repo:https://github.com/jfzhang95/pytorch-deeplab-xception

bisenetv2训练

但这些数据在bisenetv2训练时出现“RuntimeError: copy_if failed to synchronize: cudaErrorIllegalAddress: an illegal memory access was encountered”的报错,原因是bisenetv2要求输入的标签是单通道的灰度图。而我们的mask图像仍然是RGB图

我们知道RGB图像可以用颜色区分类别,而灰度图每个像素只有0-255的灰度值,如何用单通道的灰度图表示多种类别呢?

解决思路巧妙的将每个类别的rgb颜色值用单通道的0,1…255灰度值置换。

其中我们用labelme脚本labelme_json_to_dataset生成的__json文件夹中:

  • img.png 对应的局部的jpg原图文件,训练时要用
  • label.png 局部语义类别标签
  • label_names.txt 在这张图像上目标的分类名称
  • label_viz.png 可视化标签图,便于我们确认是否标记正确

我们得到RGB的label.png(局部语义类别标签)后,还需要进行灰度类别转换成单通道的标签图像:
灰度类别转换后,属于背景区域的像素点的值全是0,属于标记目标的像素点按照所有类别名的顺序1,2…255排列。如属于cat的像素点值全是1。若再加一个dog像素点值就全是2

灰度类别转换 (局部类别标签RGB—>全局类别标签GRAY)
'''
TODO:
提取__json目录下的原图、并将label.png转换为最终的单通道标签。
param:
    __jsondir: labelme生成的__json文件夹目录
    class_txt:  所有像素的类别(包括背景0)
    image_path: 提取的原图路径
    label_path: 提取并转换的单通道全局标签路径
    
输出转换的标签数量、原图和标签的路径
Note:
	__json文件夹已全部生成,并将img.png,label.png提取整理到不同路径
'''


def label2singlechannel(__jsondir, class_txt='class_name.txt', image_path=None, label_path=None):
    class_txt = open(class_txt, "r", encoding='utf-8')
    class_names = class_txt.read().splitlines()     # 全局类别

    if image_path==None and label_path==None:
        image_path = os.path.join(__jsondir.rsplit('/', 2)[0], 'JPEGImages')
        label_path = os.path.join(__jsondir.rsplit('/', 2)[0], 'SegmentationClass')

    if not os.path.exists(image_path):
        os.mkdir(image_path)
    if not os.path.exists(label_path):
        os.mkdir(label_path)

    for json_dir in os.listdir(__jsondir):
        src_path = os.path.join(__jsondir, json_dir, 'img.png')
        file_path = os.path.join(__jsondir, json_dir, 'label.png')

        if not os.path.exists(src_path) or not os.path.exists(file_path):   # 文件夹为空 img不存在
            continue
        label_names = os.path.join(__jsondir, json_dir, 'label_names.txt')
        src = Image.open(src_path)
        src.save(os.path.join(image_path, json_dir+'.png'))

        img = Image.open(file_path)
        with open(label_names, "r") as f:
            names = f.read().splitlines()       # x_json文件里面存在的类 局部的类
        new = Image.new("RGB", [np.shape(img)[1], np.shape(img)[0]])
        # 找到局部的类在全局中的类的序号
        for name in names:
            index_json = names.index(name)      # 局部类
            index_all = class_names.index(name)      # 全局类别
            # 将局部类转换成为全局类
            # 将原图img中像素点的值为index_json的像素点乘以其在全局中的像素点的所对应的类的序号 得到 其实际在数据集中像素点的值

            # 比如dog,在局部类(output/x_json/label_names)中它的序号为1,dog在原图中的像素点的值也为1.
            # 但是在全局的类(before/classes.txt)中其对应的序号为2,所以在新的图片中要将局部类的像素点的值*全局类的序号,从而得到标签文件
            new = new + np.expand_dims(index_all * (np.array(img) == index_json), -1)
        
        new = Image.fromarray(np.uint8(new))    
        # 将转变后的得到的新的最终的标签图片保存到make_dataset/png文件夹下
        new.save(os.path.join(label_path, json_dir + '.png'))
        print(f"save: - {os.path.join(label_path, json_dir + '.png')}")
        # 找到新的标签文件中像素点值的最大值和最小值,最大值为像素点对应的类在class_name.txt中的序号,最小值为背景,即0
        print(np.max(new), np.min(new))
    print(f"\nJPEGImages: {image_path}\nSegmentationClass: {label_path}") 
语义分割动手实践-bisenetv2模型训练_第1张图片

由于像素点灰度值0 1 2亮度值很小,最终生成参与训练的全局标签文件是这种全黑的。

用原图 + 单通道的标签图像即可训练BiseNetv2模型。

具体BiseNetv2的训练方式可参考官方repo:https://github.com/CoinCheung/BiSeNet或其他教程

件是这种全黑的。

用原图 + 单通道的标签图像即可训练BiseNetv2模型。

具体BiseNetv2的训练方式可参考官方repo:https://github.com/CoinCheung/BiSeNet或其他教程

你可能感兴趣的:(语义分割,pytorch,深度学习,python)