<gh_stars>1-10
"""
该文件用于操作数据集。
对应的数据集位于data/conc_data中。
"""
from common import *
import torchvision.datasets as dset
from torchvision.datasets.folder import make_dataset
from PIL import Image
import os
import torchvision.transforms as transforms
from torchvision.transforms import functional as F
import random
import torch.utils.data
# from config.resnet18_rgb_config import RESNET18_RGB_CONFIG


class ConcDataset(torch.utils.data.Dataset):
    def __init__(self, cfg, data_dir=None, transform=None, labeled=True):
        """
        :param cfg: config to use.
        :param transform: how to transform the pli img
        """
        self.cfg = cfg  # 导入config
        self.labeled = labeled
        self.data_dir = data_dir    # 导入数据文件夹
        self.transform = transform

        # 将指定文件夹下的Image Filename全部导入
        if labeled is False:
            # 此时该文件夹下仅有图像，没有多余文件夹
            self.images = op_file.get_images(data_dir, ["png"]) # data中仅包括.png图像文件
        else:
            # 此时需要分类各种Label
            dataset = dset.ImageFolder(data_dir)
            # 与学长使用的torchvision.dataset.folder.find_classes不同，因为当前版本中的函数为._find_class，是保护函数
            # repo url: https://github.com/pytorch/vision/blob/master/torchvision/datasets/folder.py
            self.classes = dataset.classes
            self.class_to_index = dataset.class_to_idx
            # print(self.classes, self.class_to_index)
            self.index_to_class = dict(zip(range(len(self.classes)), self.classes))
            # print(self.index_to_class)
            # self.class_to_index和self.index_to_class分别用dict表示了类别和索引的映射
            self.images = make_dataset(self.data_dir, self.class_to_index, extensions=("png"))  # 与TRecgNet中的代码不同，extensions中必须是tuple or str，不可以是list
            # print(self.images[0])
            # NOTE self.images是一个[tuple, tuple, ... ]的list，其中每个tuple的内容是(path, class_index).

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

    def __getitem__(self, item):
        if self.labeled is False:
            # 此时self.images单单仅有路径
            image_path = self.images[item]
        else:
            image_path, image_label = self.images[item]

        # os.path模块url: https://www.runoob.com/python/python-os-path.html
        RGB_D = Image.open(image_path).convert("RGB")
        # 由于采用的是RGB和HAA的编码，都是3通道，转换成为“RGB”模式
        # Image._show(RGB_D)

        # PIL模块文档url: https://www.osgeo.cn/pillow/reference/Image.html
        w, h = RGB_D.size   # 获取图像的宽和高
        w = int(w / 2)           # 进行一个宽度的修正，因为两张图像在同一行
        # print(w, h)

        # 需要对图像进行裁剪和缩放
        if w > self.cfg.LOAD_SIZE or h > self.cfg.LOAD_SIZE:
            # 此时需要缩小，因为图像的大小大于LOAD_SIZE
            # fixme TRecgNet中实现的方法是采用FINE_SIZE来进行判断，LOAD_SIZE来进行缩放，原因目前不明；而且只判定了w。
            # 2021.3.22修改了fixme中提到的判断和缩放的标准不一致的问题
            # 这不是一个问题，而是处理方式的不同
            # 笔者最终采用了一致的处理方式
            RGB = RGB_D.crop((0, 0, w, h)).resize((
                self.cfg.LOAD_SIZE, self.cfg.LOAD_SIZE
            ), Image.BICUBIC)   # Image.BICUBIC是三次样条插值方法
            D = RGB_D.crop((w, 0, 2 * w, h)).resize((
                self.cfg.LOAD_SIZE, self.cfg.LOAD_SIZE
            ), Image.BICUBIC)
        else:
            RGB = RGB_D.crop((0, 0, w, h))
            D = RGB_D.crop((w, 0, 2 * w, h))

        # 对是否有标签进行判断
        if self.labeled is False:
            data = {"RGB": RGB, "D": D, "image_name": os.path.basename(image_path)}
        else:
            data = {"RGB": RGB, "D": D, "image_name": os.path.basename(image_path), "label": image_label}

        # 这里在TRecgNet中存在一个参数transform=None，可以通过参数传递予以更改，其中还存在一段这样的代码：
        if self.transform:
            self.transform(data)

        return data


"""
除了上面定义一个Dataset类之外，还需要定义一些数据操作类。
类似于原本的transforms.Resize, transforms.RandomCrop
参考链接: https://zj-image-processing.readthedocs.io/zh_CN/stable/pytorch/[torchvision]%E8%87%AA%E5%AE%9A%E4%B9%89%E6%95%B0%E6%8D%AE%E9%9B%86%E5%92%8C%E9%A2%84%E5%A4%84%E7%90%86%E6%93%8D%E4%BD%9C.html
https://www.jianshu.com/p/1ae863c1e66d
"""


class Resize(transforms.Resize):
    # 自定义transforms.Resize类

    def __call__(self, sample):
        RGB, D = sample["RGB"], sample["D"]
        h = self.size[0]
        w = self.size[1]

        sample["RGB"] = F.resize(RGB, (h, w))
        sample["D"] = F.resize(D, (h, w))
        """
        该部分的文档可以参见链接：https://pytorch.apachecn.org/docs/1.0/torchvision_transforms.html
        """
        return sample


class ToTensor(object):
    def __call__(self, sample):
        RGB, D = sample["RGB"], sample["D"]

        sample["RGB"] = F.to_tensor(RGB)
        sample["D"] = F.to_tensor(D)

        return sample


class Normalize(transforms.Normalize):
    def __call__(self, sample):
        RGB, D = sample["RGB"], sample["D"]

        sample["RGB"] = F.normalize(RGB, self.mean, self.std)
        sample["D"] = F.normalize(D, self.mean, self.std)

        return sample


class RandomCrop(transforms.RandomCrop):
    def __call__(self, sample):
        RGB, D = sample["RGB"], sample["D"]
        # print(self.padding)
        if self.padding != None:
            """
            self.padding参数代表需要填充的大小
            如果是int，且为0，则代表不需要填充
            如果是长度位4的列表，则分别代表左上右下的填充大小
            """
            RGB = F.pad(RGB, self.padding)
            D = F.pad(D, self.padding)

        # 对宽度进行判定
        if self.pad_if_needed and RGB.size[0] < self.size[1]:
            """
            这里需要注意一下，torch中的size是(h,w)
            pil中的size是(w,h)
            """
            RGB = F.pad(RGB, (int((1 + self.size[1] - RGB.size[0]) / 2), 0))
            D = F.pad(D, (int((1 + self.size[1] - D.size[0]) / 2), 0))
            """
            传入的参数是二元组，则分别对应左右，上下
            """

        # 对高度进行判定
        if self.pad_if_needed and RGB.size[1] < self.size[0]:
            RGB = F.pad(RGB, (0, int((1 + self.size[0] - RGB.size[1]) / 2)))
            D = F.pad(D, (0, int((1 + self.size[0] - D.size[1]) / 2)))

        h1, w1, h2, w2 = self.get_params(RGB, self.size)
        sample["RGB"] = F.crop(RGB, h1, w1, h2, w2)
        sample["D"] = F.crop(D, h1, w1, h2, w2)

        return sample


class CenterCrop(transforms.CenterCrop):
    def __call__(self, sample):
        RGB, D = sample["RGB"], sample["D"]
        sample["RGB"] = F.center_crop(RGB, self.size)
        sample["D"] = F.center_crop(D, self.size)
        return sample


class RandomHorizontalFlip(transforms.RandomHorizontalFlip):
    def __call__(self, sample):
        # print(sample)
        RGB, D = sample["RGB"], sample["D"]

        if random.random() > self.p:
            """
            原代码中此处"""
            RGB = F.hflip(RGB)
            D = F.hflip(D)

        sample["RGB"] = RGB
        sample["D"] = D

        return sample


class Lambda(transforms.Lambda):
    def __call__(self, sample):
        return self.lambd(sample)






"""
该文件用于操作数据集。
对应的数据集位于data/conc_data中。
"""
from common import *
import torchvision.datasets as dset
from torchvision.datasets.folder import make_dataset
from PIL import Image
import os
import torchvision.transforms as transforms
from torchvision.transforms import functional as F
import random
import torch.utils.data
# from config.resnet18_rgb_config import RESNET18_RGB_CONFIG


class ConcDataset(torch.utils.data.Dataset):
    def __init__(self, cfg, data_dir=None, transform=None, labeled=True):
        """
        :param cfg: config to use.
        :param transform: how to transform the pli img
        """
        self.cfg = cfg  # 导入config
        self.labeled = labeled
        self.data_dir = data_dir    # 导入数据文件夹
        self.transform = transform

        # 将指定文件夹下的Image Filename全部导入
        if labeled is False:
            # 此时该文件夹下仅有图像，没有多余文件夹
            self.images = op_file.get_images(data_dir, ["png"]) # data中仅包括.png图像文件
        else:
            # 此时需要分类各种Label
            dataset = dset.ImageFolder(data_dir)
            # 与学长使用的torchvision.dataset.folder.find_classes不同，因为当前版本中的函数为._find_class，是保护函数
            # repo url: https://github.com/pytorch/vision/blob/master/torchvision/datasets/folder.py
            self.classes = dataset.classes
            self.class_to_index = dataset.class_to_idx
            # print(self.classes, self.class_to_index)
            self.index_to_class = dict(zip(range(len(self.classes)), self.classes))
            # print(self.index_to_class)
            # self.class_to_index和self.index_to_class分别用dict表示了类别和索引的映射
            self.images = make_dataset(self.data_dir, self.class_to_index, extensions=("png"))  # 与TRecgNet中的代码不同，extensions中必须是tuple or str，不可以是list
            # print(self.images[0])
            # NOTE self.images是一个[tuple, tuple, ... ]的list，其中每个tuple的内容是(path, class_index).

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

    def __getitem__(self, item):
        if self.labeled is False:
            # 此时self.images单单仅有路径
            image_path = self.images[item]
        else:
            image_path, image_label = self.images[item]

        # os.path模块url: https://www.runoob.com/python/python-os-path.html
        RGB_D = Image.open(image_path).convert("RGB")
        # 由于采用的是RGB和HAA的编码，都是3通道，转换成为“RGB”模式
        # Image._show(RGB_D)

        # PIL模块文档url: https://www.osgeo.cn/pillow/reference/Image.html
        w, h = RGB_D.size   # 获取图像的宽和高
        w = int(w / 2)           # 进行一个宽度的修正，因为两张图像在同一行
        # print(w, h)

        # 需要对图像进行裁剪和缩放
        if w > self.cfg.LOAD_SIZE or h > self.cfg.LOAD_SIZE:
            # 此时需要缩小，因为图像的大小大于LOAD_SIZE
            # fixme TRecgNet中实现的方法是采用FINE_SIZE来进行判断，LOAD_SIZE来进行缩放，原因目前不明；而且只判定了w。
            # 2021.3.22修改了fixme中提到的判断和缩放的标准不一致的问题
            # 这不是一个问题，而是处理方式的不同
            # 笔者最终采用了一致的处理方式
            RGB = RGB_D.crop((0, 0, w, h)).resize((
                self.cfg.LOAD_SIZE, self.cfg.LOAD_SIZE
            ), Image.BICUBIC)   # Image.BICUBIC是三次样条插值方法
            D = RGB_D.crop((w, 0, 2 * w, h)).resize((
                self.cfg.LOAD_SIZE, self.cfg.LOAD_SIZE
            ), Image.BICUBIC)
        else:
            RGB = RGB_D.crop((0, 0, w, h))
            D = RGB_D.crop((w, 0, 2 * w, h))

        # 对是否有标签进行判断
        if self.labeled is False:
            data = {"RGB": RGB, "D": D, "image_name": os.path.basename(image_path)}
        else:
            data = {"RGB": RGB, "D": D, "image_name": os.path.basename(image_path), "label": image_label}

        # 这里在TRecgNet中存在一个参数transform=None，可以通过参数传递予以更改，其中还存在一段这样的代码：
        if self.transform:
            self.transform(data)

        return data


"""
除了上面定义一个Dataset类之外，还需要定义一些数据操作类。
类似于原本的transforms.Resize, transforms.RandomCrop
参考链接: https://zj-image-processing.readthedocs.io/zh_CN/stable/pytorch/[torchvision]%E8%87%AA%E5%AE%9A%E4%B9%89%E6%95%B0%E6%8D%AE%E9%9B%86%E5%92%8C%E9%A2%84%E5%A4%84%E7%90%86%E6%93%8D%E4%BD%9C.html
https://www.jianshu.com/p/1ae863c1e66d
"""


class Resize(transforms.Resize):
    # 自定义transforms.Resize类

    def __call__(self, sample):
        RGB, D = sample["RGB"], sample["D"]
        h = self.size[0]
        w = self.size[1]

        sample["RGB"] = F.resize(RGB, (h, w))
        sample["D"] = F.resize(D, (h, w))
        """
        该部分的文档可以参见链接：https://pytorch.apachecn.org/docs/1.0/torchvision_transforms.html
        """
        return sample


class ToTensor(object):
    def __call__(self, sample):
        RGB, D = sample["RGB"], sample["D"]

        sample["RGB"] = F.to_tensor(RGB)
        sample["D"] = F.to_tensor(D)

        return sample


class Normalize(transforms.Normalize):
    def __call__(self, sample):
        RGB, D = sample["RGB"], sample["D"]

        sample["RGB"] = F.normalize(RGB, self.mean, self.std)
        sample["D"] = F.normalize(D, self.mean, self.std)

        return sample


class RandomCrop(transforms.RandomCrop):
    def __call__(self, sample):
        RGB, D = sample["RGB"], sample["D"]
        # print(self.padding)
        if self.padding != None:
            """
            self.padding参数代表需要填充的大小
            如果是int，且为0，则代表不需要填充
            如果是长度位4的列表，则分别代表左上右下的填充大小
            """
            RGB = F.pad(RGB, self.padding)
            D = F.pad(D, self.padding)

        # 对宽度进行判定
        if self.pad_if_needed and RGB.size[0] < self.size[1]:
            """
            这里需要注意一下，torch中的size是(h,w)
            pil中的size是(w,h)
            """
            RGB = F.pad(RGB, (int((1 + self.size[1] - RGB.size[0]) / 2), 0))
            D = F.pad(D, (int((1 + self.size[1] - D.size[0]) / 2), 0))
            """
            传入的参数是二元组，则分别对应左右，上下
            """

        # 对高度进行判定
        if self.pad_if_needed and RGB.size[1] < self.size[0]:
            RGB = F.pad(RGB, (0, int((1 + self.size[0] - RGB.size[1]) / 2)))
            D = F.pad(D, (0, int((1 + self.size[0] - D.size[1]) / 2)))

        h1, w1, h2, w2 = self.get_params(RGB, self.size)
        sample["RGB"] = F.crop(RGB, h1, w1, h2, w2)
        sample["D"] = F.crop(D, h1, w1, h2, w2)

        return sample


class CenterCrop(transforms.CenterCrop):
    def __call__(self, sample):
        RGB, D = sample["RGB"], sample["D"]
        sample["RGB"] = F.center_crop(RGB, self.size)
        sample["D"] = F.center_crop(D, self.size)
        return sample


class RandomHorizontalFlip(transforms.RandomHorizontalFlip):
    def __call__(self, sample):
        # print(sample)
        RGB, D = sample["RGB"], sample["D"]

        if random.random() > self.p:
            """
            原代码中此处"""
            RGB = F.hflip(RGB)
            D = F.hflip(D)

        sample["RGB"] = RGB
        sample["D"] = D

        return sample


class Lambda(transforms.Lambda):
    def __call__(self, sample):
        return self.lambd(sample)
该文件用于操作数据集。 对应的数据集位于data/conc_data中。 # from config.resnet18_rgb_config import RESNET18_RGB_CONFIG :param cfg: config to use.         :param transform: how to transform the pli img # 导入config # 导入数据文件夹 # 将指定文件夹下的Image Filename全部导入 # 此时该文件夹下仅有图像，没有多余文件夹 # data中仅包括.png图像文件 # 此时需要分类各种Label # 与学长使用的torchvision.dataset.folder.find_classes不同，因为当前版本中的函数为._find_class，是保护函数 # repo url: https://github.com/pytorch/vision/blob/master/torchvision/datasets/folder.py # print(self.classes, self.class_to_index) # print(self.index_to_class) # self.class_to_index和self.index_to_class分别用dict表示了类别和索引的映射 # 与TRecgNet中的代码不同，extensions中必须是tuple or str，不可以是list # print(self.images[0]) # NOTE self.images是一个[tuple, tuple, ... ]的list，其中每个tuple的内容是(path, class_index). # 此时self.images单单仅有路径 # os.path模块url: https://www.runoob.com/python/python-os-path.html # 由于采用的是RGB和HAA的编码，都是3通道，转换成为“RGB”模式 # Image._show(RGB_D) # PIL模块文档url: https://www.osgeo.cn/pillow/reference/Image.html # 获取图像的宽和高 # 进行一个宽度的修正，因为两张图像在同一行 # print(w, h) # 需要对图像进行裁剪和缩放 # 此时需要缩小，因为图像的大小大于LOAD_SIZE # fixme TRecgNet中实现的方法是采用FINE_SIZE来进行判断，LOAD_SIZE来进行缩放，原因目前不明；而且只判定了w。 # 2021.3.22修改了fixme中提到的判断和缩放的标准不一致的问题 # 这不是一个问题，而是处理方式的不同 # 笔者最终采用了一致的处理方式 # Image.BICUBIC是三次样条插值方法 # 对是否有标签进行判断 # 这里在TRecgNet中存在一个参数transform=None，可以通过参数传递予以更改，其中还存在一段这样的代码： 除了上面定义一个Dataset类之外，还需要定义一些数据操作类。 类似于原本的transforms.Resize, transforms.RandomCrop 参考链接: https://zj-image-processing.readthedocs.io/zh_CN/stable/pytorch/[torchvision]%E8%87%AA%E5%AE%9A%E4%B9%89%E6%95%B0%E6%8D%AE%E9%9B%86%E5%92%8C%E9%A2%84%E5%A4%84%E7%90%86%E6%93%8D%E4%BD%9C.html https://www.jianshu.com/p/1ae863c1e66d # 自定义transforms.Resize类 该部分的文档可以参见链接：https://pytorch.apachecn.org/docs/1.0/torchvision_transforms.html # print(self.padding) self.padding参数代表需要填充的大小             如果是int，且为0，则代表不需要填充             如果是长度位4的列表，则分别代表左上右下的填充大小 # 对宽度进行判定 这里需要注意一下，torch中的size是(h,w)             pil中的size是(w,h) 传入的参数是二元组，则分别对应左右，上下 # 对高度进行判定 # print(sample) 原代码中此处