# -*- coding: utf-8 -*- # Max-Planck-Gesellschaft zur Förderung der Wissenschaften e.V. (MPG) is # holder of all proprietary rights on this computer program. # You can only use this computer program if you have closed # a license agreement with MPG or you get the right to use the computer # program from someone who is authorized to grant you that right. # Any use of the computer program without a valid license is prohibited and # liable to prosecution. # # Copyright©2019 Max-Planck-Gesellschaft zur Förderung # der Wissenschaften e.V. (MPG). acting on behalf of its Max Planck Institute # for Intelligent Systems. All rights reserved. # # Contact: ps-license@tuebingen.mpg.de import os.path as osp import kornia import numpy as np import torchvision.transforms as transforms from PIL import Image from termcolor import colored class NormalDataset: def __init__(self, cfg, split="train"): self.split = split self.root = cfg.root self.bsize = cfg.batch_size self.opt = cfg.dataset self.datasets = self.opt.types self.input_size = self.opt.input_size self.scales = self.opt.scales # input data types and dimensions self.in_nml = [item[0] for item in cfg.net.in_nml] self.in_nml_dim = [item[1] for item in cfg.net.in_nml] self.in_total = self.in_nml + ["normal_F", "normal_B"] self.in_total_dim = self.in_nml_dim + [3, 3] if self.split != "train": self.rotations = range(0, 360, 120) else: self.rotations = np.arange(0, 360, 360 // self.opt.rotation_num).astype(np.int) self.datasets_dict = {} for dataset_id, dataset in enumerate(self.datasets): dataset_dir = osp.join(self.root, dataset) self.datasets_dict[dataset] = { "subjects": np.loadtxt(osp.join(dataset_dir, "all.txt"), dtype=str), "scale": self.scales[dataset_id], } self.subject_list = self.get_subject_list(split) # PIL to tensor self.image_to_tensor = transforms.Compose([ transforms.Resize(self.input_size), transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)), ]) # PIL to tensor self.mask_to_tensor = transforms.Compose([ transforms.Resize(self.input_size), transforms.ToTensor(), transforms.Normalize((0.0, ), (1.0, )), ]) def get_subject_list(self, split): subject_list = [] for dataset in self.datasets: split_txt = osp.join(self.root, dataset, f"{split}.txt") if osp.exists(split_txt) and osp.getsize(split_txt) > 0: print(f"load from {split_txt}") subject_list += np.loadtxt(split_txt, dtype=str).tolist() if self.split != "test": subject_list += subject_list[:self.bsize - len(subject_list) % self.bsize] print(colored(f"total: {len(subject_list)}", "yellow")) bug_list = sorted(np.loadtxt(osp.join(self.root, 'bug.txt'), dtype=str).tolist()) subject_list = [subject for subject in subject_list if (subject not in bug_list)] # subject_list = ["thuman2/0008"] return subject_list def __len__(self): return len(self.subject_list) * len(self.rotations) def __getitem__(self, index): rid = index % len(self.rotations) mid = index // len(self.rotations) rotation = self.rotations[rid] subject = self.subject_list[mid].split("/")[1] dataset = self.subject_list[mid].split("/")[0] render_folder = "/".join([dataset + f"_{self.opt.rotation_num}views", subject]) if not osp.exists(osp.join(self.root, render_folder)): render_folder = "/".join([dataset + f"_36views", subject]) # setup paths data_dict = { "dataset": dataset, "subject": subject, "rotation": rotation, "scale": self.datasets_dict[dataset]["scale"], "image_path": osp.join(self.root, render_folder, "render", f"{rotation:03d}.png"), } # image/normal/depth loader for name, channel in zip(self.in_total, self.in_total_dim): if f"{name}_path" not in data_dict.keys(): data_dict.update({ f"{name}_path": osp.join(self.root, render_folder, name, f"{rotation:03d}.png") }) data_dict.update({ name: self.imagepath2tensor(data_dict[f"{name}_path"], channel, inv=False, erasing=False) }) path_keys = [key for key in data_dict.keys() if "_path" in key or "_dir" in key] for key in path_keys: del data_dict[key] return data_dict def imagepath2tensor(self, path, channel=3, inv=False, erasing=False): rgba = Image.open(path).convert("RGBA") mask = rgba.split()[-1] image = rgba.convert("RGB") image = self.image_to_tensor(image) mask = self.mask_to_tensor(mask) # simulate occlusion if erasing: mask = kornia.augmentation.RandomErasing( p=0.2, scale=(0.01, 0.2), ratio=(0.3, 3.3), keepdim=True )(mask) image = (image * mask)[:channel] return (image * (0.5 - inv) * 2.0).float()