Download training/dataset/sbi_api.py from DeepfakeGenome/DeepfakeGenome_Codebase: direct link, hf CLI and curl.
- Browser
- Download file 11.1 kB
-
https://huggingface.co/DeepfakeGenome/DeepfakeGenome_Codebase/resolve/main/training/dataset/sbi_api.py
- Command line
-
hf download hf://DeepfakeGenome/DeepfakeGenome_Codebase/training/dataset/sbi_api.py
-
curl -L -o sbi_api.py https://huggingface.co/DeepfakeGenome/DeepfakeGenome_Codebase/resolve/main/training/dataset/sbi_api.py
11.1 kB
| # Created by: Kaede Shiohara | |
| # Yamasaki Lab at The University of Tokyo | |
| # shiohara@cvm.t.u-tokyo.ac.jp | |
| # Copyright (c) 2021 | |
| # 3rd party softwares' licenses are noticed at https://github.com/mapooon/SelfBlendedImages/blob/master/LICENSE | |
| import torch | |
| from torchvision import datasets,transforms,utils | |
| from torch.utils.data import Dataset,IterableDataset | |
| from glob import glob | |
| import os | |
| import numpy as np | |
| from PIL import Image | |
| import random | |
| import cv2 | |
| from torch import nn | |
| import sys | |
| import scipy as sp | |
| from skimage.measure import label, regionprops | |
| from training.dataset.library.bi_online_generation import random_get_hull | |
| import albumentations as alb | |
| import warnings | |
| warnings.filterwarnings('ignore') | |
| def alpha_blend(source,target,mask): | |
| mask_blured = get_blend_mask(mask) | |
| img_blended=(mask_blured * source + (1 - mask_blured) * target) | |
| return img_blended,mask_blured | |
| def dynamic_blend(source,target,mask): | |
| mask_blured = get_blend_mask(mask) | |
| blend_list=[0.25,0.5,0.75,1,1,1] | |
| blend_ratio = blend_list[np.random.randint(len(blend_list))] | |
| mask_blured*=blend_ratio | |
| img_blended=(mask_blured * source + (1 - mask_blured) * target) | |
| return img_blended,mask_blured | |
| def get_blend_mask(mask): | |
| H,W=mask.shape | |
| size_h=np.random.randint(192,257) | |
| size_w=np.random.randint(192,257) | |
| mask=cv2.resize(mask,(size_w,size_h)) | |
| kernel_1=random.randrange(5,26,2) | |
| kernel_1=(kernel_1,kernel_1) | |
| kernel_2=random.randrange(5,26,2) | |
| kernel_2=(kernel_2,kernel_2) | |
| mask_blured = cv2.GaussianBlur(mask, kernel_1, 0) | |
| mask_blured = mask_blured/(mask_blured.max()) | |
| mask_blured[mask_blured<1]=0 | |
| mask_blured = cv2.GaussianBlur(mask_blured, kernel_2, np.random.randint(5,46)) | |
| mask_blured = mask_blured/(mask_blured.max()) | |
| mask_blured = cv2.resize(mask_blured,(W,H)) | |
| return mask_blured.reshape((mask_blured.shape+(1,))) | |
| def get_alpha_blend_mask(mask): | |
| kernel_list=[(11,11),(9,9),(7,7),(5,5),(3,3)] | |
| blend_list=[0.25,0.5,0.75] | |
| kernel_idxs=random.choices(range(len(kernel_list)), k=2) | |
| blend_ratio = blend_list[random.sample(range(len(blend_list)), 1)[0]] | |
| mask_blured = cv2.GaussianBlur(mask, kernel_list[0], 0) | |
| # print(mask_blured.max()) | |
| mask_blured[mask_blured<mask_blured.max()]=0 | |
| mask_blured[mask_blured>0]=1 | |
| # mask_blured = mask | |
| mask_blured = cv2.GaussianBlur(mask_blured, kernel_list[kernel_idxs[1]], 0) | |
| mask_blured = mask_blured/(mask_blured.max()) | |
| return mask_blured.reshape((mask_blured.shape+(1,))) | |
| class RandomDownScale(alb.core.transforms_interface.ImageOnlyTransform): | |
| def apply(self,img,**params): | |
| return self.randomdownscale(img) | |
| def randomdownscale(self,img): | |
| keep_ratio=True | |
| keep_input_shape=True | |
| H,W,C=img.shape | |
| ratio_list=[2,4] | |
| r=ratio_list[np.random.randint(len(ratio_list))] | |
| img_ds=cv2.resize(img,(int(W/r),int(H/r)),interpolation=cv2.INTER_NEAREST) | |
| if keep_input_shape: | |
| img_ds=cv2.resize(img_ds,(W,H),interpolation=cv2.INTER_LINEAR) | |
| return img_ds | |
| def get_boundary(mask, apply_dilation=True, apply_motion_blur=True): | |
| if len(mask.shape) == 3: | |
| mask = mask[:, :, 0] | |
| mask = cv2.GaussianBlur(mask, (3, 3), 0) | |
| if mask.max() > 1: | |
| boundary = mask / 255. | |
| else: | |
| boundary = mask | |
| boundary = 4 * boundary * (1. - boundary) | |
| boundary = boundary * 255 | |
| boundary = random_dilate(boundary) | |
| if apply_motion_blur: | |
| boundary = random_motion_blur(boundary) | |
| boundary = boundary / 255. | |
| return boundary | |
| def random_dilate(mask, max_kernel_size=5): | |
| kernel_size = random.randint(1, max_kernel_size) | |
| kernel = np.ones((kernel_size, kernel_size), np.uint8) | |
| dilated_mask = cv2.dilate(mask, kernel, iterations=1) | |
| return dilated_mask | |
| def random_motion_blur(mask, max_kernel_size=5): | |
| kernel_size = random.randint(1, max_kernel_size) | |
| kernel = np.zeros((kernel_size, kernel_size)) | |
| anchor = random.randint(0, kernel_size - 1) | |
| kernel[:, anchor] = 1 / kernel_size | |
| motion_blurred_mask = cv2.filter2D(mask, -1, kernel) | |
| return motion_blurred_mask | |
| class SBI_API: | |
| def __init__(self,phase='train',image_size=256): | |
| assert phase == 'train', f"Current SBI API only support train phase, but got {phase}" | |
| self.image_size=(image_size,image_size) | |
| self.phase=phase | |
| self.transforms=self.get_transforms() | |
| self.source_transforms = self.get_source_transforms() | |
| self.bob_transforms = self.get_source_transforms_for_bob() | |
| def __call__(self,img,landmark=None): | |
| try: | |
| assert landmark is not None, "landmark of the facial image should not be None." | |
| # img_r,img_f,mask_f=self.self_blending(img.copy(),landmark.copy()) | |
| if random.random() < 1.0: | |
| # apply sbi | |
| img_r,img_f,mask_f=self.self_blending(img.copy(),landmark.copy()) | |
| else: | |
| # apply boundary motion blur (bob) | |
| img_r,img_f,mask_f=self.bob(img.copy(),landmark.copy()) | |
| if self.phase=='train': | |
| transformed=self.transforms(image=img_f.astype('uint8'),image1=img_r.astype('uint8')) | |
| img_f=transformed['image'] | |
| img_r=transformed['image1'] | |
| return img_f,img_r | |
| except Exception as e: | |
| print(e) | |
| return None,None | |
| def get_source_transforms(self): | |
| return alb.Compose([ | |
| alb.Compose([ | |
| alb.RGBShift((-20,20),(-20,20),(-20,20),p=0.3), | |
| alb.HueSaturationValue(hue_shift_limit=(-0.3,0.3), sat_shift_limit=(-0.3,0.3), val_shift_limit=(-0.3,0.3), p=1), | |
| alb.RandomBrightnessContrast(brightness_limit=(-0.1,0.1), contrast_limit=(-0.1,0.1), p=1), | |
| ],p=1), | |
| alb.OneOf([ | |
| RandomDownScale(p=1), | |
| alb.Sharpen(alpha=(0.2, 0.5), lightness=(0.5, 1.0), p=1), | |
| ],p=1), | |
| ], p=1.) | |
| def get_transforms(self): | |
| return alb.Compose([ | |
| alb.RGBShift((-20,20),(-20,20),(-20,20),p=0.3), | |
| alb.HueSaturationValue(hue_shift_limit=(-0.3,0.3), sat_shift_limit=(-0.3,0.3), val_shift_limit=(-0.3,0.3), p=0.3), | |
| alb.RandomBrightnessContrast(brightness_limit=(-0.3,0.3), contrast_limit=(-0.3,0.3), p=0.3), | |
| alb.ImageCompression(quality_lower=40,quality_upper=100,p=0.5), | |
| ], | |
| additional_targets={f'image1': 'image'}, | |
| p=1.) | |
| def randaffine(self,img,mask): | |
| f=alb.Affine( | |
| translate_percent={'x':(-0.03,0.03),'y':(-0.015,0.015)}, | |
| scale=[0.95,1/0.95], | |
| fit_output=False, | |
| p=1) | |
| g=alb.ElasticTransform( | |
| alpha=50, | |
| sigma=7, | |
| alpha_affine=0, | |
| p=1, | |
| ) | |
| transformed=f(image=img,mask=mask) | |
| img=transformed['image'] | |
| mask=transformed['mask'] | |
| transformed=g(image=img,mask=mask) | |
| mask=transformed['mask'] | |
| return img,mask | |
| def get_source_transforms_for_bob(self): | |
| return alb.Compose([ | |
| alb.Compose([ | |
| alb.ImageCompression(quality_lower=40,quality_upper=100,p=1), | |
| ],p=1), | |
| alb.OneOf([ | |
| RandomDownScale(p=1), | |
| alb.Sharpen(alpha=(0.2, 0.5), lightness=(0.5, 1.0), p=1), | |
| ],p=1), | |
| ], p=1.) | |
| def bob(self,img,landmark): | |
| H,W=len(img),len(img[0]) | |
| if np.random.rand()<0.25: | |
| landmark=landmark[:68] | |
| # mask=np.zeros_like(img[:,:,0]) | |
| # cv2.fillConvexPoly(mask, cv2.convexHull(landmark), 1.) | |
| hull_type = random.choice([0, 1, 2, 3]) | |
| mask=random_get_hull(landmark,img,hull_type)[:,:,0] | |
| source = img.copy() | |
| source = self.bob_transforms(image=source.astype(np.uint8))['image'] | |
| source, mask = self.randaffine(source,mask) | |
| mask = get_blend_mask(mask) | |
| # get boundary with motion blur | |
| boundary = get_boundary(mask) | |
| blend_list = [0.25,0.5,0.75,1,1,1] | |
| blend_ratio = blend_list[np.random.randint(len(blend_list))] | |
| boundary *= blend_ratio | |
| boundary = np.repeat(boundary[:, :, np.newaxis], 3, axis=2) | |
| img_blended = (boundary * source + (1 - boundary) * img) | |
| img_blended = img_blended.astype(np.uint8) | |
| img = img.astype(np.uint8) | |
| return img,img_blended,boundary.squeeze() | |
| def self_blending(self,img,landmark): | |
| H,W=len(img),len(img[0]) | |
| if np.random.rand()<0.25: | |
| landmark=landmark[:68] | |
| # mask=np.zeros_like(img[:,:,0]) | |
| # cv2.fillConvexPoly(mask, cv2.convexHull(landmark), 1.) | |
| hull_type = random.choice([0, 1, 2, 3]) | |
| mask=random_get_hull(landmark,img,hull_type)[:,:,0] | |
| source = img.copy() | |
| if np.random.rand()<0.5: | |
| source = self.source_transforms(image=source.astype(np.uint8))['image'] | |
| else: | |
| img = self.source_transforms(image=img.astype(np.uint8))['image'] | |
| source, mask = self.randaffine(source,mask) | |
| img_blended,mask=dynamic_blend(source,img,mask) | |
| img_blended = img_blended.astype(np.uint8) | |
| img = img.astype(np.uint8) | |
| return img,img_blended,mask | |
| def reorder_landmark(self,landmark): | |
| landmark_add=np.zeros((13,2)) | |
| for idx,idx_l in enumerate([77,75,76,68,69,70,71,80,72,73,79,74,78]): | |
| landmark_add[idx]=landmark[idx_l] | |
| landmark[68:]=landmark_add | |
| return landmark | |
| def hflip(self,img,mask=None,landmark=None,bbox=None): | |
| H,W=img.shape[:2] | |
| landmark=landmark.copy() | |
| if bbox is not None: | |
| bbox=bbox.copy() | |
| if landmark is not None: | |
| landmark_new=np.zeros_like(landmark) | |
| landmark_new[:17]=landmark[:17][::-1] | |
| landmark_new[17:27]=landmark[17:27][::-1] | |
| landmark_new[27:31]=landmark[27:31] | |
| landmark_new[31:36]=landmark[31:36][::-1] | |
| landmark_new[36:40]=landmark[42:46][::-1] | |
| landmark_new[40:42]=landmark[46:48][::-1] | |
| landmark_new[42:46]=landmark[36:40][::-1] | |
| landmark_new[46:48]=landmark[40:42][::-1] | |
| landmark_new[48:55]=landmark[48:55][::-1] | |
| landmark_new[55:60]=landmark[55:60][::-1] | |
| landmark_new[60:65]=landmark[60:65][::-1] | |
| landmark_new[65:68]=landmark[65:68][::-1] | |
| if len(landmark)==68: | |
| pass | |
| elif len(landmark)==81: | |
| landmark_new[68:81]=landmark[68:81][::-1] | |
| else: | |
| raise NotImplementedError | |
| landmark_new[:,0]=W-landmark_new[:,0] | |
| else: | |
| landmark_new=None | |
| if bbox is not None: | |
| bbox_new=np.zeros_like(bbox) | |
| bbox_new[0,0]=bbox[1,0] | |
| bbox_new[1,0]=bbox[0,0] | |
| bbox_new[:,0]=W-bbox_new[:,0] | |
| bbox_new[:,1]=bbox[:,1].copy() | |
| if len(bbox)>2: | |
| bbox_new[2,0]=W-bbox[3,0] | |
| bbox_new[2,1]=bbox[3,1] | |
| bbox_new[3,0]=W-bbox[2,0] | |
| bbox_new[3,1]=bbox[2,1] | |
| bbox_new[4,0]=W-bbox[4,0] | |
| bbox_new[4,1]=bbox[4,1] | |
| bbox_new[5,0]=W-bbox[6,0] | |
| bbox_new[5,1]=bbox[6,1] | |
| bbox_new[6,0]=W-bbox[5,0] | |
| bbox_new[6,1]=bbox[5,1] | |
| else: | |
| bbox_new=None | |
| if mask is not None: | |
| mask=mask[:,::-1] | |
| else: | |
| mask=None | |
| img=img[:,::-1].copy() | |
| return img,mask,landmark_new,bbox_new | |
| if __name__=='__main__': | |
| seed=10 | |
| random.seed(seed) | |
| torch.manual_seed(seed) | |
| np.random.seed(seed) | |
| torch.cuda.manual_seed(seed) | |
| torch.backends.cudnn.deterministic = True | |
| torch.backends.cudnn.benchmark = False | |
| api=SBI_API(phase='train',image_size=256) | |
| img_path = 'FaceForensics++/original_sequences/youtube/c23/frames/000/000.png' | |
| img = cv2.imread(img_path) | |
| landmark_path = img_path.replace('frames', 'landmarks').replace('png', 'npy') | |
| landmark = np.load(landmark_path) | |
| sbi_img, ori_img = api(img, landmark) | |