pytorch炼金术-DataSet-PASCAL VOC 简介

PASCAL VOC 数据集简介

数据集在语义分割上SOTA模型

1. 简介

1.1 简介

该挑战赛的竞赛项目主要包括 图像分类与检测(Classification/Detection Competitions)、图像分割(Segmentation Competition)、人体动作分类(Action Classification Competition)、人体部位检测(Person Layout Taster Competition)等四项主要的视觉挑战赛。

  1. VOC2007

    包含9963张标注过的图片, 由train/val/test三部分组成, 共标注出24,640个物体。 VOC2007的test数据label已经公布, 之后的没有公布(只有图片,没有label)。

  2. VOC2012:

    VOC2012数据集是VOC2007数据集的升级版,一共有11530张图片。

    对于检测任务,VOC2012的trainval/test包含08-11年的所有对应图片。 trainval有11540张图片共27450个物体。

    对于分割任务, VOC2012的trainval包含07-11年的所有对应图片, test只包含08-11。trainval有2913张图片共6929个物体。

数据集分为20类,包括背景为21类,分别如下:
人:人
动物:鸟、猫、牛、狗、马、羊
车辆:飞机、自行车、船、巴士、汽车、摩托车、火车
室内:瓶、椅子、餐桌、盆栽植物、沙发、电视/监视器

1.2 格式介绍

.
├── Annotations 进行 detection 任务时的标签文件,xml 形式,文件名与图片名一一对应
├── ImageSets 包含三个子文件夹 Layout、Main、Segmentation,其中 Main 存放的是分类和检测的数据集分割文件
├── JPEGImages 存放 .jpg 格式的图片文件
├── SegmentationClass 存放按照 class 分割的图片
└── SegmentationObject 存放按照 object 分割的图片

├── Main
│   ├── train.txt 写着用于训练的图片名称, 共 2501 个
│   ├── val.txt 写着用于验证的图片名称,共 2510 个
│   ├── trainval.txt train与val的合集。共 5011 个
│   ├── test.txt 写着用于测试的图片名称,共 4952

2. 下载

Pascal VOC Dataset Mirror (pjreddie.com)

下载的内容包括训练验证集、测试集、开发工具和文档说明

3. 制作dataloader

import os

import numpy as np
import torch
from torch.utils.data import DataLoader, Dataset
from PIL import Image
from torchvision import transforms
from torchvision.transforms import functional as Ft
import matplotlib.pyplot as plt
import albumentations as A

# 接下来,对标签图片进行处理,将其转换为对应的标签矩阵。先列出标签中每个RGB的值及其对应类别,一共21类:
classes = ['background',
           'aeroplane',
           'bicycle',
           'bird',
           'boat',
           'bottle',
           'bus',
           'car',
           'cat',
           'chair',
           'cow',
           'diningtable',
           'dog',
           'horse',
           'motorbike',
           'person',
           'potted plant',
           'sheep',
           'sofa',
           'train',
           'tv/monitor']

# RGB color for each class
colormap = [[0, 0, 0], [128, 0, 0], [0, 128, 0], [128, 128, 0], [0, 0, 128],
            [128, 0, 128], [0, 128, 128], [128, 128, 128], [64, 0, 0], [192, 0, 0],
            [64, 128, 0], [192, 128, 0], [64, 0, 128], [192, 0, 128],
            [64, 128, 128], [192, 128, 128], [0, 64, 0], [128, 64, 0],
            [0, 192, 0], [128, 192, 0], [0, 64, 128]]
colormap = np.asarray(colormap)
cm2lbl = np.zeros(256 ** 3)

# 建立一个索引,将标签图片中每个像素的RGB值一对一映射到对应的类别索引:
for i, cm in enumerate(colormap):
    cm2lbl[(cm[0] * 256 + cm[1]) * 256 + cm[2]] = i


def image2label(im):
    data = np.array(im, dtype='int32')
    idx = (data[:, :, 0] * 256 + data[:, :, 1]) * 256 + data[:, :, 2]
    return np.array(cm2lbl[idx], dtype='int64')


image_transform = A.Compose([
    A.PadIfNeeded(min_height=512, min_width=512, border_mode=0, p=1, mask_value=255, value=(255, 255, 255)),
    A.CenterCrop(height=512, width=512, p=1),
    A.HorizontalFlip(p=0.5)
    # , A.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225))
])


def voc_transform(image, target):
    result = image_transform(image=np.array(image), mask=np.array(target))
    image = result["image"].transpose(2, 0, 1) / 255.0
    target = result["mask"]
    return image, target


class VOCSegmentation(Dataset):
    """

    最后,通过torch.utls.data.Dataset自定义数据集类,
    通过._getitem__函数,访问数据集中索引为idx 的输入图像及其对应的标签矩阵。
    由于数据集中有些图像的尺寸可能小于随机裁剪所指定的输出尺寸,这些样本需要通过自定义的fiter 函数所移除。
    此外,还对输入图像的RGB三个通道的值分别做标准化。

    """

    def __init__(self, voc_root, shape=(520, 520), year="2012", transforms=None, txt_name: str = "train.txt"):
        """
        :param voc_root: 放置数据集的位置
        :param year: 年份,我这里只放置了2012年的
        :param transforms: 是否对图片进行裁剪,transforms =None不进行裁剪
        :param txt_name:
        """
        self.shape = shape
        super(VOCSegmentation, self).__init__()
        assert year in ["2007", "2012"], "year must be in ['2007', '2012']"
        root = os.path.join(voc_root, "VOCdevkit", f"VOC{
      
      year}")
        # 拼接字符串
        assert os.path.exists(root), "path '{}' does not exist.".format(root)
        image_dir = os.path.join(root, 'JPEGImages')
        # 掩膜的路径位置,就是分割好的图片
        mask_dir = os.path.join(root, 'SegmentationClass')
        #
        txt_path = os.path.join(root, "ImageSets", "Segmentation", txt_name)
        assert os.path.exists(txt_path), "file '{}' does not exist.".format(txt_path)

        with open(os.path.join(txt_path), "r") as f:
            file_names = [x.strip() for x in f.readlines() if len(x.strip()) > 0]

        # 根据Segmentation 文件夹下所以提供的train.txt,来进行图片的加载
        self.images = [os.path.join(image_dir, x + ".jpg") for x in file_names]
        # 掩膜图片位置
        self.masks = [os.path.join(mask_dir, x + ".png") for x in file_names]
        assert (len(self.images) == len(self.masks))
        self.transforms = transforms

    def __getitem__(self, index):
        """
        Args:
            index (int): 索引值
        Returns:
            返回元祖信息,一个是原始图片信息,一个是分割好的图片信息
            tuple: (image, target) where target is the image segmentation.
        """
        img = Image.open(self.images[index]).convert('RGB')
        target = Image.open(self.masks[index]).convert('P')
        img, target = voc_transform(img, target)

        return img, target

    def __len__(self):
        return len(self.images)


def get_dataloader(mode=True, batch_size=4, shape=(512, 512)):
    """
    获取数据集加载
    :param mode:
    :return:
    """
    if mode:
        # 2. 实例化,准备dataloader
        dataset = VOCSegmentation(voc_root=r"E:\note\cv\data\VOC_Train",
                                  shape=shape,
                                  )
        dataloader = DataLoader(dataset=dataset, batch_size=batch_size, shuffle=True)
    else:
        dataset = VOCSegmentation(voc_root=r"E:\note\cv\data\VOC_Train",
                                  shape=shape,
                                  txt_name="val.txt",
                                  )
        dataloader = DataLoader(dataset=dataset, batch_size=batch_size, shuffle=True)
    return dataloader


cm = np.array(colormap).astype('uint8')


def show_image(tensor):
    plt.figure()
    image = tensor.numpy().transpose(1, 2, 0)
    plt.imshow(image)
    plt.show()


def show_label(label):
    print(label.shape)
    plt.figure()
    labels = cm[label]
    plt.imshow(labels)
    plt.show()


def show_label_2(label):
    plt.figure()
    # print(np.unique(label.numpy()))
    label = label.numpy().astype('uint8')
    label[label == 255] = 0
    label = colormap[label]
    print(label.shape)
    plt.imshow(label)
    plt.show()


if __name__ == '__main__':
    train_dataloader = get_dataloader(True, batch_size=2)

    for images, labels in train_dataloader:
        show_image(images[0])
        show_label_2(labels[0])
        break

猜你喜欢

转载自blog.csdn.net/wujing1_1/article/details/124683609