Spaces:
Running on Zero
Running on Zero
Download src/transforms.py from hugging-apps/bar-jepa-chart-extraction: direct link, hf CLI and curl.
- Browser
- Download file 4.71 kB
-
https://huggingface.co/spaces/hugging-apps/bar-jepa-chart-extraction/resolve/main/src/transforms.py
- Command line
-
hf download hf://spaces/hugging-apps/bar-jepa-chart-extraction/src/transforms.py
-
curl -L -o transforms.py https://huggingface.co/spaces/hugging-apps/bar-jepa-chart-extraction/resolve/main/src/transforms.py
4.71 kB
| # Copyright (c) Meta Platforms, Inc. and affiliates. | |
| # All rights reserved. | |
| # | |
| # This source code is licensed under the license found in the | |
| # LICENSE file in the root directory of this source tree. | |
| # | |
| from logging import getLogger | |
| from math import floor | |
| from PIL import ImageFilter | |
| import torch | |
| import torchvision.transforms as transforms | |
| import torchvision.transforms.functional as F | |
| _GLOBAL_SEED = 0 | |
| logger = getLogger() | |
| def make_transforms( | |
| crop_size=224, | |
| crop_scale=(0.3, 1.0), | |
| color_jitter=1.0, | |
| random_resize_crop=True, | |
| horizontal_flip=False, | |
| color_distortion=False, | |
| gaussian_blur=False, | |
| normalization=((0.485, 0.456, 0.406), | |
| (0.229, 0.224, 0.225)), | |
| preserve_aspect_ratio=True, | |
| max_patches=14*14, | |
| patch_size=16 | |
| ): | |
| logger.info('making data transforms') | |
| def get_color_distortion(s=1.0): | |
| # s is the strength of color distortion. | |
| color_jitter = transforms.ColorJitter(0.8*s, 0.8*s, 0.8*s, 0.2*s) | |
| rnd_color_jitter = transforms.RandomApply([color_jitter], p=0.8) | |
| rnd_gray = transforms.RandomGrayscale(p=0.2) | |
| color_distort = transforms.Compose([ | |
| rnd_color_jitter, | |
| rnd_gray]) | |
| return color_distort | |
| transform_list = [] | |
| if preserve_aspect_ratio: | |
| if random_resize_crop: | |
| transform_list.append(RandomResizedCropARP(scale=crop_scale)) | |
| transform_list.append( | |
| ResizeToFixedPatches(max_patches=max_patches, patch_size=patch_size) | |
| ) | |
| else: | |
| if random_resize_crop: | |
| transform_list.append(transforms.RandomResizedCrop(crop_size, scale=crop_scale)) | |
| else: | |
| transform_list.append(transforms.Resize((crop_size, crop_size))) | |
| if horizontal_flip: | |
| transform_list.append(transforms.RandomHorizontalFlip()) | |
| if color_distortion: | |
| transform_list.append(get_color_distortion(s=color_jitter)) | |
| if gaussian_blur: | |
| transform_list.append(GaussianBlur(p=0.5)) | |
| mean, std = normalization | |
| transform_list.extend([transforms.ToTensor(), transforms.Normalize(mean, std)]) | |
| transform = transforms.Compose(transform_list) | |
| return transform | |
| class GaussianBlur(object): | |
| """ | |
| Apply Gaussian blur with a given probability. | |
| :param p: Probability of applying blur | |
| :param radius_min: Minimum blur radius | |
| :param radius_max: Maximum blur radius | |
| """ | |
| def __init__(self, p=0.5, radius_min=0.1, radius_max=2.): | |
| self.prob = p | |
| self.radius_min = radius_min | |
| self.radius_max = radius_max | |
| def __call__(self, img): | |
| if torch.bernoulli(torch.tensor(self.prob)) == 0: | |
| return img | |
| radius = self.radius_min + torch.rand(1) * (self.radius_max - self.radius_min) | |
| return img.filter(ImageFilter.GaussianBlur(radius=radius)) | |
| class ResizeToFixedPatches(object): | |
| """ | |
| Resize an image so that its patch grid fits within max_patches. | |
| :param max_patches: Maximum number of patches (H*W) | |
| :param patch_size: Patch size in pixels | |
| """ | |
| def __init__(self, max_patches=14*14, patch_size=16): | |
| self.max_patches = int(max_patches) | |
| self.patch_size = int(patch_size) | |
| def __call__(self, img): | |
| image_width, image_height = img.size | |
| scale = (self.max_patches * (self.patch_size / image_height) * (self.patch_size / image_width)) ** 0.5 | |
| scale += 1e-6 | |
| num_feasible_rows = max(min(floor(scale * image_height / self.patch_size), self.max_patches), 1) | |
| num_feasible_cols = max(min(floor(scale * image_width / self.patch_size), self.max_patches), 1) | |
| resized_height = max(int(num_feasible_rows * self.patch_size), 1) | |
| resized_width = max(int(num_feasible_cols * self.patch_size), 1) | |
| return F.resize( | |
| img, | |
| (resized_height, resized_width), | |
| interpolation=transforms.InterpolationMode.BICUBIC, | |
| antialias=True | |
| ) | |
| class RandomResizedCropARP(object): | |
| """ | |
| Random resized crop that preserves the original aspect ratio. | |
| Uses torchvision's RandomResizedCrop sampling logic with ratio fixed | |
| to the input image's aspect ratio. | |
| :param scale: Range of area scaling for the crop | |
| """ | |
| def __init__(self, scale=(0.3, 1.0)): | |
| self.scale = scale | |
| def __call__(self, img): | |
| image_width, image_height = img.size | |
| if image_width <= 0 or image_height <= 0: | |
| return img | |
| ratio = image_width / image_height | |
| i, j, h, w = transforms.RandomResizedCrop.get_params( | |
| img, | |
| scale=self.scale, | |
| ratio=(ratio, ratio) | |
| ) | |
| return F.crop(img, i, j, h, w) | |