欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 八卦 > labelme标注数据转mask(用于mmsegmentation)

labelme标注数据转mask(用于mmsegmentation)

2024/10/25 6:34:59 来源:https://blog.csdn.net/onepunch_k/article/details/143096609  浏览:    关键词:labelme标注数据转mask(用于mmsegmentation)

mmsegmentation原本支持的数据格式主要有以下几种:

mmsegmentation
├── mmseg
├── tools
├── configs
├── data
│   ├── cityscapes
│   │   ├── leftImg8bit
│   │   │   ├── train
│   │   │   ├── val
│   │   ├── gtFine
│   │   │   ├── train
│   │   │   ├── val
│   ├── VOCdevkit
│   │   ├── VOC2012
│   │   │   ├── JPEGImages
│   │   │   ├── SegmentationClass
│   │   │   ├── ImageSets
│   │   │   │   ├── Segmentation
│   │   ├── VOC2010
│   │   │   ├── JPEGImages
│   │   │   ├── SegmentationClassContext
│   │   │   ├── ImageSets
│   │   │   │   ├── SegmentationContext
│   │   │   │   │   ├── train.txt
│   │   │   │   │   ├── val.txt
│   │   │   ├── trainval_merged.json
│   │   ├── VOCaug
│   │   │   ├── dataset
│   │   │   │   ├── cls
│   ├── ade
│   │   ├── ADEChallengeData2016
│   │   │   ├── annotations
│   │   │   │   ├── training
│   │   │   │   ├── validation
│   │   │   ├── images
│   │   │   │   ├── training
│   │   │   │   ├── validation
│   ├── coco_stuff10k
│   │   ├── images
│   │   │   ├── train2014
│   │   │   ├── test2014
│   │   ├── annotations
│   │   │   ├── train2014
│   │   │   ├── test2014
│   │   ├── imagesLists
│   │   │   ├── train.txt
│   │   │   ├── test.txt
│   │   │   ├── all.txt
│   ├── coco_stuff164k
│   │   ├── images
│   │   │   ├── train2017
│   │   │   ├── val2017
│   │   ├── annotations
│   │   │   ├── train2017
│   │   │   ├── val2017
│   ├── CHASE_DB1
│   │   ├── images
│   │   │   ├── training
│   │   │   ├── validation
│   │   ├── annotations
│   │   │   ├── training
│   │   │   ├── validation
│   ├── DRIVE
│   │   ├── images
│   │   │   ├── training
│   │   │   ├── validation
│   │   ├── annotations
│   │   │   ├── training
│   │   │   ├── validation
│   ├── HRF
│   │   ├── images
│   │   │   ├── training
│   │   │   ├── validation
│   │   ├── annotations
│   │   │   ├── training
│   │   │   ├── validation
│   ├── STARE
│   │   ├── images
│   │   │   ├── training
│   │   │   ├── validation
│   │   ├── annotations
│   │   │   ├── training
│   │   │   ├── validation
|   ├── dark_zurich
|   │   ├── gps
|   │   │   ├── val
|   │   │   └── val_ref
|   │   ├── gt
|   │   │   └── val
|   │   ├── LICENSE.txt
|   │   ├── lists_file_names
|   │   │   ├── val_filenames.txt
|   │   │   └── val_ref_filenames.txt
|   │   ├── README.md
|   │   └── rgb_anon
||   ├── val
||   └── val_ref
|   ├── NighttimeDrivingTest
|   |   ├── gtCoarse_daytime_trainvaltest
|   |   │   └── test
|   |   │       └── night
|   |   └── leftImg8bit
|   |   |   └── test
|   |   |       └── night
│   ├── loveDA
│   │   ├── img_dir
│   │   │   ├── train
│   │   │   ├── val
│   │   │   ├── test
│   │   ├── ann_dir
│   │   │   ├── train
│   │   │   ├── val
│   ├── potsdam
│   │   ├── img_dir
│   │   │   ├── train
│   │   │   ├── val
│   │   ├── ann_dir
│   │   │   ├── train
│   │   │   ├── val
│   ├── vaihingen
│   │   ├── img_dir
│   │   │   ├── train
│   │   │   ├── val
│   │   ├── ann_dir
│   │   │   ├── train
│   │   │   ├── val
│   ├── iSAID
│   │   ├── img_dir
│   │   │   ├── train
│   │   │   ├── val
│   │   │   ├── test
│   │   ├── ann_dir
│   │   │   ├── train
│   │   │   ├── val
│   ├── synapse
│   │   ├── img_dir
│   │   │   ├── train
│   │   │   ├── val
│   │   ├── ann_dir
│   │   │   ├── train
│   │   │   ├── val
│   ├── REFUGE
│   │   ├── images
│   │   │   ├── training
│   │   │   ├── validation
│   │   │   ├── test
│   │   ├── annotations
│   │   │   ├── training
│   │   │   ├── validation
│   │   │   ├── test
│   ├── mapillary
│   │   ├── training
│   │   │   ├── images
│   │   │   ├── v1.2
|   │   │   │   ├── instances
|   │   │   │   ├── labels
|   │   │   │   └── panoptic
│   │   │   ├── v2.0
|   │   │   │   ├── instances
|   │   │   │   ├── labels
|   │   │   │   ├── panoptic
|   │   │   │   └── polygons
│   │   ├── validation
│   │   │   ├── images
|   │   │   ├── v1.2
|   │   │   │   ├── instances
|   │   │   │   ├── labels
|   │   │   │   └── panoptic
│   │   │   ├── v2.0
|   │   │   │   ├── instances
|   │   │   │   ├── labels
|   │   │   │   ├── panoptic
|   │   │   │   └── polygons
│   ├── bdd100k
│   │   ├── images
│   │   │   └── 10k
|   │   │   │   ├── test
|   │   │   │   ├── train
|   │   │   │   └── val
│   │   └── labels
│   │   │   └── sem_seg
|   │   │   │   ├── colormaps
|   │   │   │   │   ├──train
|   │   │   │   │   └──val
|   │   │   │   ├── masks
|   │   │   │   │   ├──train
|   │   │   │   │   └──val
|   │   │   │   ├── polygons
|   │   │   │   │   ├──sem_seg_train.json
|   │   │   │   │   └──sem_seg_val.json
|   │   │   │   └── rles
|   │   │   │   │   ├──sem_seg_train.json
|   │   │   │   │   └──sem_seg_val.json
│   ├── nyu
│   │   ├── images
│   │   │   ├── train
│   │   │   ├── test
│   │   ├── annotations
│   │   │   ├── train
│   │   │   ├── test
│   ├── HSIDrive20
│   │   ├── images
│   │   │   ├── train
│   │   │   ├── validation
│   │   │   ├── test
│   │   ├── annotations
│   │   │   ├── train
│   │   │   ├── validation
│   │   │   ├── test

labelme标注得到的数据是jpg(或者png)、json混合在一个文件夹里的。如果用于语义分割,通常需要将json数据转为mask图像。mmseg支持的数据集类型比较多,对应的也有自己的数据集结构。对此,我选择的是按照DRIVE,CHASE-DB1这些数据的格式来做的,即:

│   ├── DRIVE
│   │   ├── images
│   │   │   ├── training
│   │   │   ├── validation
│   │   ├── annotations
│   │   │   ├── training
│   │   │   ├── validation

代码参考了https://github.com/TommyZihao/Label2Everything/tree/main/labelme2mask,
整体代码如下:

import os
import json
import numpy as np
import cv2
import glob
import shutil
from tqdm import tqdm
from sklearn.model_selection import train_test_splitdef labelme2mask_single_img(img_path, labelme_json_path):'''输入原始图像路径和labelme标注路径,输出 mask'''img_bgr = cv2.imread(img_path)# 创建空白图像 0-背景img_mask = np.zeros(img_bgr.shape[:2])with open(labelme_json_path, 'r', encoding='utf-8') as f:labelme = json.load(f)# 按顺序遍历每一个类别for one_class in class_info:# 遍历所有标注,找到属于当前类别的标注for each in labelme['shapes']:if each['label'] == one_class['label']:# polygon 多段线标注if one_class['type'] == 'polygon':# 获取点的坐标points = [np.array(each['points'], dtype=np.int32).reshape((-1, 1, 2))]# 在空白图上画 mask(闭合区域)img_mask = cv2.fillPoly(img_mask, points, color=one_class['color'])# line 或者 linestrip 线段标注elif one_class['type'] == 'line' or one_class['type'] == 'linestrip':# 获取点的坐标points = [np.array(each['points'], dtype=np.int32).reshape((-1, 1, 2))]# 在空白图上画 mask(非闭合区域)img_mask = cv2.polylines(img_mask, points, isClosed=False, color=one_class['color'],thickness=one_class['thickness'])# circle 圆形标注elif one_class['type'] == 'circle':points = np.array(each['points'], dtype=np.int32)center_x, center_y = points[0][0], points[0][1]  # 圆心点坐标edge_x, edge_y = points[1][0], points[1][1]  # 圆周点坐标radius = np.linalg.norm(np.array([center_x, center_y] - np.array([edge_x, edge_y]))).astype('uint32')  # 半径img_mask = cv2.circle(img_mask, (center_x, center_y), radius, one_class['color'],one_class['thickness'])else:print('未知标注类型', one_class['type'])return img_maskif __name__ == '__main__':#  1.label设置:# 根据根据json文件中的shape情况,分别设置每个label的名称、类型、以及颜色,其中颜色要从1开始编号,因为背景为0class_info = [{'label': 'space', 'type': 'polygon', 'color': 1},  # polygon 多段线# {'label': 'condyl', 'type': 'polygon', 'color': 1},# {'label': 'fossa', 'type': 'polygon', 'color': 3},# {'label': 'bone marrow', 'type': 'polygon', 'color': 4},# {'label':'clock', 'type':'circle', 'color':11, 'thickness':-1},   # circle 圆形,-1表示填充# {'label':'lane', 'type':'line', 'color':12, 'thickness':5},       # line 两点线段,填充线宽# {'label':'sign', 'type':'linestrip', 'color':13, 'thickness':3}   # linestrip 多段线,填充线宽]#  2.路径设置:# labelme文件路径labelme_path = r"F:\Data\doctor_research\Arthritis"# 储存文件路径,这边准备采用的是chase_db1的数据格式,为了减少代码修改量,我直接命名为CHASE_DB1saved_path = r"F:\Data\doctor_research\DRIVE_space"if not os.path.exists(saved_path):os.makedirs(saved_path)# 1.images文件路径:## images路径:img_path = os.path.join(saved_path, 'images')## training images路径:train_img_path = os.path.join(img_path, 'training')## validation images路径:val_img_path = os.path.join(img_path, 'validation')# 创建文件夹if not os.path.exists(img_path):os.makedirs(img_path)if not os.path.exists(train_img_path):os.makedirs(train_img_path)if not os.path.exists(val_img_path):os.makedirs(val_img_path)# 2.mask文件路径## mask路径:mask_path = os.path.join(saved_path, 'annotations')## training mask路径:train_annotation_path = os.path.join(mask_path, 'training')## validation mask路径:val_annotation_path = os.path.join(mask_path, 'validation')print('reading...')#  创建文件夹if not os.path.exists(mask_path):os.makedirs(mask_path)if not os.path.exists(train_annotation_path):os.makedirs(train_annotation_path)if not os.path.exists(val_annotation_path):os.makedirs(val_annotation_path)# 获取images目录下所有的json文件列表json_list_path = glob.glob(labelme_path + "/*.json")print('数据集总量为:', len(json_list_path))# 划分训练集和验证集# 验证集和训练集比例为1:9,可以根据自己需要更改train_path, val_path = train_test_split(json_list_path, test_size=0.1, train_size=0.9)print("训练集数据量为:", len(train_path), '验证集数据量为:', len(val_path))# 依次对两个数据集进行转换:# 对训练集进行转换:for train_json in tqdm(train_path):try:# 1.将训练图像复制到images/training# 获取对应的图像文件地址train_img = os.path.join(train_json.split('.')[0] + '.png')# 分离文件名与路径path_1, img_name_1 = os.path.split(train_img)# 复制到新的文件夹tmp_img_path_1 = os.path.join(train_img_path, img_name_1)shutil.copy(train_img, tmp_img_path_1)# 2.将json文件转为mask图像train_img_mask = labelme2mask_single_img(train_img, train_json)# 将mask文件保存到annotations/trainingtmp_mask_path_1 = os.path.join(train_annotation_path, img_name_1)cv2.imwrite(tmp_mask_path_1, train_img_mask)except Exception as E:print(train_json, '转换失败', E)# 对测试集进行转换:for val_json in tqdm(val_path):try:# 1.将测试集图像复制到images/validation# 获取对应的图像文件地址val_img = os.path.join(val_json.split('.')[0] + '.png')# 分离文件名与路径path_2, img_name_2 = os.path.split(val_img)# 复制到新的文件夹tmp_img_path_2 = os.path.join(val_img_path, img_name_2)shutil.copy(val_img, tmp_img_path_2)# 2.将json文件转为mask图像val_img_mask = labelme2mask_single_img(val_img, val_json)# 将mask文件保存到annotations/validationtmp_mask_path_2 = os.path.join(val_annotation_path, img_name_2)cv2.imwrite(tmp_mask_path_2, val_img_mask)except Exception as E:print(val_json, '转换失败', E)

这边需要修改的就是路径以及class_info。具体怎么使用mmseg训练自己的数据集,我另外一篇blog提到了。这里简单提一下,主要是修改几个地方:

1.修改num_classes

这个在config/base/models里找到自己想用的那个模型修改就好。要记得把自己的类别数量加1,因为背景也算1类。

2.修改路径

这个在config/base/datasets,找到自己想用的数据集格式,比如DRIVE,就在drive.py里面,改一下路径。

3.修改label种类

在mmseg/datasets中对应的数据集格式里:

class DRIVEDataset(BaseSegDataset):"""DRIVE dataset.In segmentation map annotation for DRIVE, 0 stands for background, which isincluded in 2 categories. ``reduce_zero_label`` is fixed to False. The``img_suffix`` is fixed to '.png' and ``seg_map_suffix`` is fixed to'_manual1.png'."""METAINFO = dict(classes=('background', 'space'),palette=[[120, 120, 120], [6, 230, 230]])def __init__(self,img_suffix='.png',# seg_map_suffix='_manual1.png',seg_map_suffix='.png',reduce_zero_label=False,**kwargs) -> None:super().__init__(img_suffix=img_suffix,seg_map_suffix=seg_map_suffix,reduce_zero_label=reduce_zero_label,**kwargs)assert fileio.exists(self.data_prefix['img_path'], backend_args=self.backend_args)

需要修改的有3处:
1.classes,把自己的label加上去就行
2.palette,对应label的颜色,别重复就行
3.seg_map_suffix,这个要注意改一下,是各个数据集自己用来识别是否为mask的一个文件拓展名,嫌麻烦就删掉了

4.修改训练参数

这方面看个人需求,主要在config/base/default_runtime.py和config/base/schedules/schedule_40k.py里修改,我主要是改一下学习率和迭代次数。单卡训练的话,0.01的学习率有点大,我一般改为0.0025,迭代次数从文件名就可以看出来,40K就是40000次,注意,这里是iteration,不是epoch。

目前就想到这么多,有什么不懂的可以问,后续我想起来也会继续更新

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com