Spaces:
Running on Zero
Running on Zero
Download diffusion/data/transforms.py from Cryptobureau/hack2cortex-sana-video: direct link, hf CLI and curl.
- Browser
- Download file 9.64 kB
-
https://huggingface.co/spaces/Cryptobureau/hack2cortex-sana-video/resolve/main/diffusion/data/transforms.py
- Command line
-
hf download hf://spaces/Cryptobureau/hack2cortex-sana-video/diffusion/data/transforms.py
-
curl -L -o transforms.py https://huggingface.co/spaces/Cryptobureau/hack2cortex-sana-video/resolve/main/diffusion/data/transforms.py
9.64 kB
| # Copyright 2024 NVIDIA CORPORATION & AFFILIATES | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| # | |
| # SPDX-License-Identifier: Apache-2.0 | |
| # Parts of this file are adapted from https://github.com/hpcaitech/Open-Sora/blob/main/opensora/datasets/video_transforms.py#L161 | |
| import numbers | |
| import imageio.v3 as iio | |
| import numpy as np | |
| import torch | |
| import torchvision.transforms as T | |
| from PIL import Image | |
| TRANSFORMS = dict() | |
| def _is_tensor_video_clip(clip): | |
| if not torch.is_tensor(clip): | |
| raise TypeError("clip should be Tensor. Got %s" % type(clip)) | |
| if not clip.ndimension() == 4: | |
| raise ValueError("clip should be 4D. Got %dD" % clip.dim()) | |
| return True | |
| def crop(clip, i, j, h, w): | |
| """ | |
| Args: | |
| clip (torch.tensor): Video clip to be cropped. Size is (T, C, H, W) | |
| """ | |
| if len(clip.size()) != 4: | |
| raise ValueError("clip should be a 4D tensor") | |
| return clip[..., i : i + h, j : j + w] | |
| def resize(clip, target_size, interpolation_mode): | |
| if len(target_size) != 2: | |
| raise ValueError(f"target size should be tuple (height, width), instead got {target_size}") | |
| return torch.nn.functional.interpolate(clip, size=target_size, mode=interpolation_mode, align_corners=False) | |
| def resize_crop_to_fill(clip, target_size): | |
| if not _is_tensor_video_clip(clip): | |
| raise ValueError("clip should be a 4D torch.tensor") | |
| h, w = clip.size(-2), clip.size(-1) | |
| th, tw = target_size[0], target_size[1] | |
| rh, rw = th / h, tw / w | |
| if rh > rw: | |
| sh, sw = th, round(w * rh) | |
| clip = resize(clip, (sh, sw), "bilinear") | |
| i = 0 | |
| j = int(round(sw - tw) / 2.0) | |
| else: | |
| sh, sw = round(h * rw), tw | |
| clip = resize(clip, (sh, sw), "bilinear") | |
| i = int(round(sh - th) / 2.0) | |
| j = 0 | |
| assert i + th <= clip.size(-2) and j + tw <= clip.size(-1) | |
| return crop(clip, i, j, th, tw) | |
| def resize_crop_to_fill_image(pil_image, image_size): | |
| w, h = pil_image.size # PIL is (W, H) | |
| th, tw = image_size | |
| rh, rw = th / h, tw / w | |
| if rh > rw: | |
| sh, sw = th, round(w * rh) | |
| image = pil_image.resize((sw, sh), Image.BICUBIC) | |
| i = 0 | |
| j = int(round((sw - tw) / 2.0)) | |
| else: | |
| sh, sw = round(h * rw), tw | |
| image = pil_image.resize((sw, sh), Image.BICUBIC) | |
| i = int(round((sh - th) / 2.0)) | |
| j = 0 | |
| arr = np.array(image) | |
| assert i + th <= arr.shape[0] and j + tw <= arr.shape[1] | |
| return Image.fromarray(arr[i : i + th, j : j + tw]) | |
| def to_tensor(clip): | |
| """ | |
| Convert tensor data type from uint8 to float, divide value by 255.0 and | |
| permute the dimensions of clip tensor | |
| Args: | |
| clip (torch.tensor, dtype=torch.uint8): Size is (T, C, H, W) | |
| Return: | |
| clip (torch.tensor, dtype=torch.float): Size is (T, C, H, W) | |
| """ | |
| _is_tensor_video_clip(clip) | |
| if not clip.dtype == torch.uint8: | |
| raise TypeError("clip tensor should have data type uint8. Got %s" % str(clip.dtype)) | |
| # return clip.float().permute(3, 0, 1, 2) / 255.0 | |
| return clip.float() / 255.0 | |
| class ToTensorVideo: | |
| """ | |
| Convert tensor data type from uint8 to float, divide value by 255.0 and | |
| permute the dimensions of clip tensor | |
| """ | |
| def __init__(self): | |
| pass | |
| def __call__(self, clip): | |
| """ | |
| Args: | |
| clip (torch.tensor, dtype=torch.uint8): Size is (T, C, H, W) | |
| Return: | |
| clip (torch.tensor, dtype=torch.float): Size is (T, C, H, W) | |
| """ | |
| return to_tensor(clip) | |
| def __repr__(self) -> str: | |
| return self.__class__.__name__ | |
| def resize_scale(clip, target_size, interpolation_mode): | |
| if len(target_size) != 2: | |
| raise ValueError(f"target size should be tuple (height, width), instead got {target_size}") | |
| H, W = clip.size(-2), clip.size(-1) | |
| scale_ = target_size[0] / min(H, W) | |
| th, tw = int(round(H * scale_)), int(round(W * scale_)) | |
| return torch.nn.functional.interpolate(clip, size=(th, tw), mode=interpolation_mode, align_corners=False) | |
| def resized_crop(clip, i, j, h, w, size, interpolation_mode="bilinear"): | |
| """ | |
| Do spatial cropping and resizing to the video clip | |
| Args: | |
| clip (torch.tensor): Video clip to be cropped. Size is (T, C, H, W) | |
| i (int): i in (i,j) i.e coordinates of the upper left corner. | |
| j (int): j in (i,j) i.e coordinates of the upper left corner. | |
| h (int): Height of the cropped region. | |
| w (int): Width of the cropped region. | |
| size (tuple(int, int)): height and width of resized clip | |
| Returns: | |
| clip (torch.tensor): Resized and cropped clip. Size is (T, C, H, W) | |
| """ | |
| if not _is_tensor_video_clip(clip): | |
| raise ValueError("clip should be a 4D torch.tensor") | |
| clip = crop(clip, i, j, h, w) | |
| clip = resize(clip, size, interpolation_mode) | |
| return clip | |
| def center_crop(clip, crop_size): | |
| if not _is_tensor_video_clip(clip): | |
| raise ValueError("clip should be a 4D torch.tensor") | |
| h, w = clip.size(-2), clip.size(-1) | |
| th, tw = crop_size | |
| if h < th or w < tw: | |
| raise ValueError("height and width must be no smaller than crop_size") | |
| i = int(round((h - th) / 2.0)) | |
| j = int(round((w - tw) / 2.0)) | |
| return crop(clip, i, j, th, tw) | |
| def get_closest_ratio(height: float, width: float, ratios: dict): | |
| aspect_ratio = height / width | |
| closest_ratio = min(ratios.keys(), key=lambda ratio: abs(float(ratio) - aspect_ratio)) | |
| return ratios[closest_ratio], float(closest_ratio) | |
| class ResizeCrop: | |
| def __init__(self, size): | |
| if isinstance(size, numbers.Number): | |
| self.size = (int(size), int(size)) | |
| else: | |
| self.size = size | |
| def __call__(self, clip): | |
| clip = resize_crop_to_fill(clip, self.size) | |
| return clip | |
| def __repr__(self) -> str: | |
| return f"{self.__class__.__name__}(size={self.size})" | |
| class ResizeCenterCropVideo: | |
| """ | |
| First scale to the specified size in equal proportion to the short edge, | |
| then center cropping | |
| """ | |
| def __init__( | |
| self, | |
| size, | |
| interpolation_mode="bilinear", | |
| ): | |
| if isinstance(size, tuple): | |
| if len(size) != 2: | |
| raise ValueError(f"size should be tuple (height, width), instead got {size}") | |
| self.size = size | |
| else: | |
| self.size = (size, size) | |
| self.interpolation_mode = interpolation_mode | |
| def __call__(self, clip): | |
| """ | |
| Args: | |
| clip (torch.tensor): Video clip to be cropped. Size is (T, C, H, W) | |
| Returns: | |
| torch.tensor: scale resized / center cropped video clip. | |
| size is (T, C, crop_size, crop_size) | |
| """ | |
| clip_resize = resize_scale(clip=clip, target_size=self.size, interpolation_mode=self.interpolation_mode) | |
| clip_center_crop = center_crop(clip_resize, self.size) | |
| return clip_center_crop | |
| def __repr__(self) -> str: | |
| return f"{self.__class__.__name__}(size={self.size}, interpolation_mode={self.interpolation_mode}" | |
| def register_transform(transform): | |
| name = transform.__name__ | |
| if name in TRANSFORMS: | |
| raise RuntimeError(f"Transform {name} has already registered.") | |
| TRANSFORMS.update({name: transform}) | |
| def get_transform(type, resolution): | |
| transform = TRANSFORMS[type](resolution) | |
| transform = T.Compose(transform) | |
| transform.image_size = resolution | |
| return transform | |
| def default_train(n_px): | |
| transform = [ | |
| T.Lambda(lambda img: img.convert("RGB")), | |
| T.Resize(n_px), # Image.BICUBIC | |
| T.CenterCrop(n_px), | |
| # T.RandomHorizontalFlip(), | |
| T.ToTensor(), | |
| T.Normalize([0.5], [0.5]), | |
| ] | |
| return transform | |
| def default_train_video(image_size=(256, 256)): | |
| transform = [ | |
| ToTensorVideo(), # TCHW | |
| ResizeCrop(image_size), | |
| T.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5], inplace=True), | |
| ] | |
| return transform | |
| def read_image_from_path(path, image_size): | |
| image = Image.open(path).convert("RGB") | |
| transform = T.Compose( | |
| [ | |
| T.Lambda(lambda pil_image: resize_crop_to_fill_image(pil_image, image_size)), | |
| T.ToTensor(), | |
| T.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5], inplace=True), | |
| ] | |
| ) | |
| return transform(image) # C,H,W, range (-1, 1) | |
| def read_video_from_path(path, video_size, num_frames): | |
| """Decode a local video to normalized ``[T, C, H, W]`` frames.""" | |
| frames = [] | |
| for frame in iio.imiter(path, plugin="pyav"): | |
| frames.append(frame) | |
| if len(frames) == num_frames: | |
| break | |
| if len(frames) < num_frames: | |
| raise RuntimeError(f"Short decode: {path} returned {len(frames)} frames, expected at least {num_frames}") | |
| transform = T.Compose( | |
| [ | |
| ToTensorVideo(), | |
| ResizeCrop(video_size), | |
| T.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5], inplace=True), | |
| ] | |
| ) | |
| video = torch.from_numpy(np.stack(frames)).permute(0, 3, 1, 2) | |
| return transform(video) | |