| import numpy as np |
| import os |
| import random |
| import torch |
| import copy |
| import torch.nn as nn |
| from lib.utils.tools import read_pkl |
| from lib.utils.utils_data import flip_data, crop_scale_3d |
| |
| class Augmenter2D(object): |
| """ |
| Make 2D augmentations on the fly. PyTorch batch-processing GPU version. |
| """ |
| def __init__(self, args): |
| self.d2c_params = read_pkl(args.d2c_params_path) |
| self.noise = torch.load(args.noise_path) |
| self.mask_ratio = args.mask_ratio |
| self.mask_T_ratio = args.mask_T_ratio |
| self.num_Kframes = 27 |
| self.noise_std = 0.002 |
|
|
| def dis2conf(self, dis, a, b, m, s): |
| f = a/(dis+a)+b*dis |
| shift = torch.randn(*dis.shape)*s + m |
| |
| shift = shift.to(dis.device) |
| return f + shift |
| |
| def add_noise(self, motion_2d): |
| a, b, m, s = self.d2c_params["a"], self.d2c_params["b"], self.d2c_params["m"], self.d2c_params["s"] |
| if "uniform_range" in self.noise.keys(): |
| uniform_range = self.noise["uniform_range"] |
| else: |
| uniform_range = 0.06 |
| motion_2d = motion_2d[:,:,:,:2] |
| batch_size = motion_2d.shape[0] |
| num_frames = motion_2d.shape[1] |
| num_joints = motion_2d.shape[2] |
| mean = self.noise['mean'].float() |
| std = self.noise['std'].float() |
| weight = self.noise['weight'][:,None].float() |
| sel = torch.rand((batch_size, self.num_Kframes, num_joints, 1)) |
| gaussian_sample = (torch.randn(batch_size, self.num_Kframes, num_joints, 2) * std + mean) |
| uniform_sample = (torch.rand((batch_size, self.num_Kframes, num_joints, 2))-0.5) * uniform_range |
| noise_mean = 0 |
| delta_noise = torch.randn(num_frames, num_joints, 2) * self.noise_std + noise_mean |
| |
| mean = mean.to(motion_2d.device) |
| std = std.to(motion_2d.device) |
| weight = weight.to(motion_2d.device) |
| gaussian_sample = gaussian_sample.to(motion_2d.device) |
| uniform_sample = uniform_sample.to(motion_2d.device) |
| sel = sel.to(motion_2d.device) |
| delta_noise = delta_noise.to(motion_2d.device) |
| |
| delta = gaussian_sample*(sel<weight) + uniform_sample*(sel>=weight) |
| delta_expand = torch.nn.functional.interpolate(delta.unsqueeze(1), [num_frames, num_joints, 2], mode='trilinear', align_corners=True)[:,0] |
| delta_final = delta_expand + delta_noise |
| motion_2d = motion_2d + delta_final |
| dx = delta_final[:,:,:,0] |
| dy = delta_final[:,:,:,1] |
| dis2 = dx*dx+dy*dy |
| dis = torch.sqrt(dis2) |
| conf = self.dis2conf(dis, a, b, m, s).clip(0,1).reshape([batch_size, num_frames, num_joints, -1]) |
| return torch.cat((motion_2d, conf), dim=3) |
| |
| def add_mask(self, x): |
| ''' motion_2d: (N,T,17,3) |
| ''' |
| N,T,J,C = x.shape |
| mask = torch.rand(N,T,J,1, dtype=x.dtype, device=x.device) > self.mask_ratio |
| mask_T = torch.rand(1,T,1,1, dtype=x.dtype, device=x.device) > self.mask_T_ratio |
| x = x * mask * mask_T |
| return x |
| |
| def augment2D(self, motion_2d, mask=False, noise=False): |
| if noise: |
| motion_2d = self.add_noise(motion_2d) |
| if mask: |
| motion_2d = self.add_mask(motion_2d) |
| return motion_2d |
| |
| class Augmenter3D(object): |
| """ |
| Make 3D augmentations when dataloaders get items. NumPy single motion version. |
| """ |
| def __init__(self, args): |
| self.flip = args.flip |
| if hasattr(args, "scale_range_pretrain"): |
| self.scale_range_pretrain = args.scale_range_pretrain |
| else: |
| self.scale_range_pretrain = None |
| |
| def augment3D(self, motion_3d): |
| if self.scale_range_pretrain: |
| motion_3d = crop_scale_3d(motion_3d, self.scale_range_pretrain) |
| if self.flip and random.random()>0.5: |
| motion_3d = flip_data(motion_3d) |
| return motion_3d |