Mask2Former代码详解--ADE200KDataset数据集

这里解析的是github里的mask2former简化版,该版本解耦了detectron2<我真受不了原版和detectron2混在一起的版本,根本看不懂啊喂!!!>

1、init方法

1.1 ADE200KDataset

class ADE200kDataset(BaseDataset):
    def __init__(self, odgt, opt, dynamic_batchHW=False, **kwargs):
        super(ADE200kDataset, self).__init__(odgt, opt, **kwargs)
        self.root_dataset = opt.DATASETS.ROOT_DIR
        # down sampling rate of segm labe
        self.segm_downsampling_rate = opt.MODEL.SEM_SEG_HEAD.COMMON_STRIDE # 网络输出相对于输入缩小的倍数
        self.dynamic_batchHW = dynamic_batchHW  # 是否动态调整batchHW, cswin_transformer需要使用固定image size
        self.num_querys = opt.MODEL.MASK_FORMER.NUM_OBJECT_QUERIES
        # self.visualize = ADEVisualize()

        self.aug_pipe = self.get_data_aug_pipe()

1) odgt:dataset/training.odgt — 数据集列表文件

在这里插入图片描述
在这里插入图片描述

{“fpath_img”:“ADEChallengeData2016/images/training/ADE_train_00000001.jpg”,“fpath_segm”:“ADEChallengeData2016/annotations/training/ADE_train_00000001.png”, “width”: 683, “height”: 512}

2) 其余初始化参数变量

  • self.root_dataset – “data/” – 数据集root地址
  • segm_downsampling_rate – 分割标签的下采样率
  • dynamic_batchHW – 是否动态调整batchHW
  • num_querys – MaskFormer模型的查询数量
  • aug_pipe – 数据增强pipline

3) aug_pipe

    # 随机生成一个数据增强操作序列(可能包含1-2种增强方法)
    def get_data_aug_pipe(self):
        pipe_aug = []
        if random.random() > 0.5:  # 50%的概率进行增强
            # 增强操作a:旋转、缩放、平移、模糊、翻转、仿射剪切、对比度调整
            # 增强概率p:5、   25、 20、 25、 15、 5、      5
            aug_list = [pipe_sequential_rotate, pipe_sequential_scale, pipe_sequential_translate, pipe_someof_blur,
                        pipe_someof_flip, pipe_sometimes_mpshear, pipe_someone_contrast]
            index = np.random.choice(a=[0, 1, 2, 3, 4, 5, 6],
                                    p=[0.05, 0.25, 0.20, 0.25, 0.15, 0.05, 0.05])

            # 当选择旋转/翻转/剪切时,有50%概率额外叠加一个增强操作
            if (index == 0 or index == 4 or index == 5) and random.random() < 0.5:  
                index2 = np.random.choice(a=[1, 2, 3], p=[0.4, 0.3, 0.3])  # 缩放/平移/模糊
                pipe_aug = [aug_list[index], aug_list[index2]]
            else:
                pipe_aug = [aug_list[index]]
        return pipe_aug

1.2 BaseDataset

class BaseDataset(torch.utils.data.Dataset):
    def __init__(self, odgt, opt, **kwargs):
        # parse options        
        self.imgSizes = opt.INPUT.CROP.SIZE  # imgSizes=[224, 320, 480, 512]
        self.imgMaxSize = opt.INPUT.CROP.MAX_SIZE  # imgMaxSize = [1024, 576]
        # 网格参数
        self.padding_constant = 2**5  # resnet 总共下采样5次

        # 当 odgt 参数非空时,调用 parse_input_list 方法解析数据列表
        if odgt is not None:
            self.parse_input_list(odgt, **kwargs)

        # 数据标准化
        self.pixel_mean = np.array(opt.DATASETS.PIXEL_MEAN)
        self.pixel_std = np.array(opt.DATASETS.PIXEL_STD)

1)参数初始化

  • imgSizes – [224, 320, 480, 512]
  • imgMaxSize – [1024, 576]
  • padding_constant – 网格参数 – 2**5(resnet总共下采样5次)
  • 数据标准化 – pixel_mean & pixel_std

2) parse_input_list

    def parse_input_list(self, odgt, max_sample=-1, start_idx=-1, end_idx=-1):
        # 如果odgt是列表,则直接使用现有列表, eg: [{"image": "1.jpg", "mask": "1.png"}, ...]
        if isinstance(odgt, list):
            self.list_sample = odgt
        # 从json文件中加载,得到字典,其中包含四个值--1)img路径 2)mask路径 3)高度 4)宽度
        elif isinstance(odgt, str):
            self.list_sample = [json.loads(x.rstrip()) for x in open(odgt, 'r')]
        # 限制最大样本数
        if max_sample > 0:
            self.list_sample = self.list_sample[0:max_sample]
        if start_idx >= 0 and end_idx >= 0:     # 切片范围
            self.list_sample = self.list_sample[start_idx:end_idx]

        self.num_sample = len(self.list_sample)
        assert self.num_sample > 0
        print('# samples: {}'.format(self.num_sample))

2、 getitem方法

    def __getitem__(self, index):        
        this_record = self.list_sample[index]
        # load image and label  加载图像和标签
        image_path = os.path.join(self.root_dataset, this_record['fpath_img'])
        segm_path = os.path.join(self.root_dataset, this_record['fpath_segm'])
        
        img = Image.open(image_path).convert('RGB')
        segm = Image.open(segm_path).convert('L')

        # data augmentation   数据增强         
        img = np.array(img)
        segm = np.array(segm)
        for seq in self.aug_pipe:
            img, segm = imgaug_mask(img, segm, seq)

        output = dict()
        output['image'] = img
        output['mask'] = segm

        return output

3、数据加载器Dataloader

    dataset_train = ADE200kDataset(cfg.DATASETS.TRAIN, cfg, dynamic_batchHW=True)
    if cfg.ngpus > 1:
        train_sampler = torch.utils.data.distributed.DistributedSampler(dataset_train, rank=cfg.local_rank)
    else:
        train_sampler = None                            
    loader_train = torch.utils.data.DataLoader(  # 将dataset包装成可迭代的批量数据流
        dataset_train,
        batch_size=cfg.TRAIN.BATCH_SIZE,  # batch大小
        shuffle=False if train_sampler is not None else True,  
        collate_fn=dataset_train.collate_fn,  # 自定义批次合并函数:固定尺寸+img&mask的协同处理
        num_workers=cfg.TRAIN.WORKERS,  # 数据加载的子进程数
        drop_last=True,  # 是否丢弃不完整批次
        pin_memory=True,  # 是否使用锁页内存
        sampler=train_sampler)  # 自定义采样器

3.1 自定义合并函数–collate_fn

    def collate_fn(self, batch):
        batch_width, batch_height = self.get_batch_size(batch)  # 计算批次尺寸
        out = {}
        images = []
        masks = []
        raw_images = []

        for item in batch:
            img = deepcopy(item['image'])
            segm = item['mask']

            img = Image.fromarray(img)  # 将numpy数组转为PIL图像
            segm = Image.fromarray(segm)

            img = self.resize_padding(img, (batch_width, batch_height))
            img = self.img_transform(img)
            segm = self.resize_padding(segm, (batch_width, batch_height), Image.NEAREST)
            segm = segm.resize((batch_width // self.segm_downsampling_rate, batch_height // self.segm_downsampling_rate), Image.NEAREST)

            images.append(torch.from_numpy(img).float())
            masks.append(torch.from_numpy(np.array(segm)).long())
            raw_images.append(item['image'])

        out['images'] = torch.stack(images)
        out['masks'] = torch.stack(masks)
        out['raw_img'] = raw_images
        return out   

输出返回out为字典,有三个变量:

  • raw_img:原始输入图像,list列表。
  • images:将原始输入图像进行缩放填充到固定大小,然后进行数值归一化、标准化,并将h,w,c更换为维度c,h,w。
  • masks:将mask进行缩放和填充。
    在这里插入图片描述

1)得到批量尺寸大小

动态调整批量图像尺寸,使其不超过定义的最大值
在这里插入图片描述
在这里插入图片描述

2) resize_padding

在这里插入图片描述

3)img_transformer

    def img_transform(self, img):
        # 0-255 to 0-1,像素值归一化
        img = np.float32(np.array(img)) / 255.   
        img = (img - self.pixel_mean) / self.pixel_std   # 像素值标准化
        img = img.transpose((2, 0, 1))  # [c, h, w],更换维度
        return img

4)mask进行两次尺寸变换

segm = self.resize_padding(segm, (batch_width, batch_height), Image.NEAREST)
segm = segm.resize((batch_width // self.segm_downsampling_rate, batch_height // self.segm_downsampling_rate), Image.NEAREST)
  • 第一次变换
    将mask和图像进行同样的变换,目的是在空间上进行对齐
  • 第二次变换
    将mask进行下采样,使其大小和model的输出大小一致
### Mask2Former 相关的数据集 对于Mask2Former模型而言,所涉及的数据集通常需满足特定格式要求以便于实例分割和语义分割任务的有效执行。具体来说,在准备用于Mask2Former训练的数据集中,不仅要有图像文件,还应包含对应的掩码(mask)信息以及可能的深度图(dem),这些构成了完整的输入样本[^1]。 #### COCO 数据集 COCO(Common Objects in Context)是一个广泛应用于目标检测、分割等领域的大规模数据集。为了适应Mask2Former的需求,该数据集被进一步处理成既含有实例级标注又具备像素级别的类别标签形式,从而支持更复杂的视觉理解任务。通过调整`datasets/prepare_ade20k_sem_seg.py`脚本可以生成适合Mask2Former框架下操作的标准数据结构[^2]。 #### Bijie Landslide Dataset 这是一个专注于滑坡灾害识别的研究型数据集合,由武汉大学基于Triplesat卫星影像构建而成。它特别适用于研究地质灾害中的变化监测等问题。此数据集内含770组带有滑坡特征的信息(包括图片、掩膜、高程模型DEM及其边界坐标),另有2003条无滑坡现象的相关记录可供对比分析。由于其独特的应用场景,使得这个数据源成为测试Mask2Former在特殊领域表现的理想选择之一[^3]。 ```python import os from mask2former.data.datasets.builtin import register_builtin_datasets # 注册内置数据集, 如COCO等 register_builtin_datasets() # 对于自定义数据集如Bijie Landslide Dataset,则需要额外注册 def register_landslide_dataset(): from detectron2.data import MetadataCatalog, DatasetCatalog # 假设路径为本地存储位置 DATASET_PATH = "/path/to/Bijie_Landslide_Dataset" def get_bijie_dicts(img_dir): json_file = os.path.join(DATASET_PATH, "annotations.json") with open(json_file) as f: dataset_dicts = json.load(f) for i in range(len(dataset_dicts)): record = {} filename = os.path.join(img_dir, dataset_dicts[i]["file_name"]) height, width = cv2.imread(filename).shape[:2] record["file_name"] = filename record["height"] = height record["width"] = width annos = dataset_dicts[i].get("annotations", []) objs = [] for anno in annos: obj = { "bbox": anno['bbox'], "category_id": anno['category_id'] - 1, "segmentation": anno.get('segmentation', None), ... } objs.append(obj) record["annotations"] = objs yield record img_dirs = ["train/images", "val/images"] names = ["bijie_train", "bijie_val"] for d, name in zip(img_dirs, names): DatasetCatalog.register(name, lambda d=d: get_bijie_dicts(os.path.join(DATASET_PATH, d))) MetadataCatalog.get(name).set( thing_classes=["landslide"], # 或者更多分类依据实际情况设定 evaluator_type="coco", ignore_label=255, image_root=os.path.join(DATASET_PATH, d.split("/")[0]), json_file=os.path.join(DATASET_PATH, "annotations.json"), ) register_landslide_dataset() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值