CoolFace
Apppublic

ICML2022/OFA

sourceHugging Faceapache-2.0updated 4y agoView on Hugging Face
18likes
transforms.py509 linesDownload Raw Back to utils
1import random2 3import torch4import torchvision.transforms as T5import torchvision.transforms.functional as F6import numpy as np7from PIL import Image8 9 10def crop(image, target, region, delete=True):11    cropped_image = F.crop(image, *region)12 13    target = target.copy()14    i, j, h, w = region15 16    # should we do something wrt the original size?17    target["size"] = torch.tensor([h, w])18 19    fields = ["labels", "area"]20 21    if "boxes" in target:22        boxes = target["boxes"]23        max_size = torch.as_tensor([w, h], dtype=torch.float32)24        cropped_boxes = boxes - torch.as_tensor([j, i, j, i])25        cropped_boxes = torch.min(cropped_boxes.reshape(-1, 2, 2), max_size)26        cropped_boxes = cropped_boxes.clamp(min=0)27        area = (cropped_boxes[:, 1, :] - cropped_boxes[:, 0, :]).prod(dim=1)28        target["boxes"] = cropped_boxes.reshape(-1, 4)29        target["area"] = area30        fields.append("boxes")31 32    if "polygons" in target:33        polygons = target["polygons"]34        num_polygons = polygons.shape[0]35        max_size = torch.as_tensor([w, h], dtype=torch.float32)36        start_coord = torch.cat([torch.tensor([j, i], dtype=torch.float32)37                                 for _ in range(polygons.shape[1] // 2)], dim=0)38        cropped_boxes = polygons - start_coord39        cropped_boxes = torch.min(cropped_boxes.reshape(num_polygons, -1, 2), max_size)40        cropped_boxes = cropped_boxes.clamp(min=0)41        target["polygons"] = cropped_boxes.reshape(num_polygons, -1)42        fields.append("polygons")43 44    if "masks" in target:45        # FIXME should we update the area here if there are no boxes?46        target['masks'] = target['masks'][:, i:i + h, j:j + w]47        fields.append("masks")48 49    # remove elements for which the boxes or masks that have zero area50    if delete and ("boxes" in target or "masks" in target):51        # favor boxes selection when defining which elements to keep52        # this is compatible with previous implementation53        if "boxes" in target:54            cropped_boxes = target['boxes'].reshape(-1, 2, 2)55            keep = torch.all(cropped_boxes[:, 1, :] > cropped_boxes[:, 0, :], dim=1)56        else:57            keep = target['masks'].flatten(1).any(1)58 59        for field in fields:60            target[field] = target[field][keep.tolist()]61 62    return cropped_image, target63 64 65def hflip(image, target):66    flipped_image = F.hflip(image)67 68    w, h = image.size69 70    target = target.copy()71    if "boxes" in target:72        boxes = target["boxes"]73        boxes = boxes[:, [2, 1, 0, 3]] * torch.as_tensor([-1, 1, -1, 1]) + torch.as_tensor([w, 0, w, 0])74        target["boxes"] = boxes75 76    if "polygons" in target:77        polygons = target["polygons"]78        num_polygons = polygons.shape[0]79        polygons = polygons.reshape(num_polygons, -1, 2) * torch.as_tensor([-1, 1]) + torch.as_tensor([w, 0])80        target["polygons"] = polygons81 82    if "masks" in target:83        target['masks'] = target['masks'].flip(-1)84 85    return flipped_image, target86 87 88def resize(image, target, size, max_size=None):89    # size can be min_size (scalar) or (w, h) tuple90 91    def get_size_with_aspect_ratio(image_size, size, max_size=None):92        w, h = image_size93 94        if (w <= h and w == size) or (h <= w and h == size):95            if max_size is not None:96                max_size = int(max_size)97                h = min(h, max_size)98                w = min(w, max_size)99            return (h, w)100 101        if w < h:102            ow = size103            oh = int(size * h / w)104        else:105            oh = size106            ow = int(size * w / h)107 108        if max_size is not None:109           max_size = int(max_size)110           oh = min(oh, max_size)111           ow = min(ow, max_size)112 113        return (oh, ow)114 115    def get_size(image_size, size, max_size=None):116        if isinstance(size, (list, tuple)):117            return size[::-1]118        else:119            return get_size_with_aspect_ratio(image_size, size, max_size)120 121    size = get_size(image.size, size, max_size)122    rescaled_image = F.resize(image, size, interpolation=Image.BICUBIC)123 124    if target is None:125        return rescaled_image126 127    ratios = tuple(float(s) / float(s_orig) for s, s_orig in zip(rescaled_image.size, image.size))128    ratio_width, ratio_height = ratios129 130    target = target.copy()131    if "boxes" in target:132        boxes = target["boxes"]133        scaled_boxes = boxes * torch.as_tensor([ratio_width, ratio_height, ratio_width, ratio_height])134        target["boxes"] = scaled_boxes135 136    if "polygons" in target:137        polygons = target["polygons"]138        scaled_ratio = torch.cat([torch.tensor([ratio_width, ratio_height])139                                 for _ in range(polygons.shape[1] // 2)], dim=0)140        scaled_polygons = polygons * scaled_ratio141        target["polygons"] = scaled_polygons142 143    if "area" in target:144        area = target["area"]145        scaled_area = area * (ratio_width * ratio_height)146        target["area"] = scaled_area147 148    h, w = size149    target["size"] = torch.tensor([h, w])150 151    if "masks" in target:152        assert False153        # target['masks'] = interpolate(154        #     target['masks'][:, None].float(), size, mode="nearest")[:, 0] > 0.5155 156    return rescaled_image, target157 158 159class CenterCrop(object):160    def __init__(self, size):161        self.size = size162 163    def __call__(self, img, target):164        image_width, image_height = img.size165        crop_height, crop_width = self.size166        crop_top = int(round((image_height - crop_height) / 2.))167        crop_left = int(round((image_width - crop_width) / 2.))168        return crop(img, target, (crop_top, crop_left, crop_height, crop_width))169 170 171class ObjectCenterCrop(object):172    def __init__(self, size):173        self.size = size174 175    def __call__(self, img, target):176        image_width, image_height = img.size177        crop_height, crop_width = self.size178 179        x0 = float(target['boxes'][0][0])180        y0 = float(target['boxes'][0][1])181        x1 = float(target['boxes'][0][2])182        y1 = float(target['boxes'][0][3])183 184        center_x = (x0 + x1) / 2185        center_y = (y0 + y1) / 2186        crop_left = max(center_x-crop_width/2 + min(image_width-center_x-crop_width/2, 0), 0)187        crop_top = max(center_y-crop_height/2 + min(image_height-center_y-crop_height/2, 0), 0)188 189        return crop(img, target, (crop_top, crop_left, crop_height, crop_width), delete=False)190 191 192class RandomHorizontalFlip(object):193    def __init__(self, p=0.5):194        self.p = p195 196    def __call__(self, img, target):197        if random.random() < self.p:198            return hflip(img, target)199        return img, target200 201 202class RandomResize(object):203    def __init__(self, sizes, max_size=None, equal=False):204        assert isinstance(sizes, (list, tuple))205        self.sizes = sizes206        self.max_size = max_size207        self.equal = equal208 209    def __call__(self, img, target=None):210        size = random.choice(self.sizes)211        if self.equal:212            return resize(img, target, size, size)213        else:214            return resize(img, target, size, self.max_size)215 216 217class ToTensor(object):218    def __call__(self, img, target):219        return F.to_tensor(img), target220 221 222class Normalize(object):223    def __init__(self, mean, std, max_image_size=512):224        self.mean = mean225        self.std = std226        self.max_image_size = max_image_size227 228    def __call__(self, image, target=None):229        image = F.normalize(image, mean=self.mean, std=self.std)230        if target is None:231            return image, None232        target = target.copy()233        # h, w = image.shape[-2:]234        h, w = target["size"][0], target["size"][1]235        if "boxes" in target:236            boxes = target["boxes"]237            boxes = boxes / self.max_image_size238            target["boxes"] = boxes239        if "polygons" in target:240            polygons = target["polygons"]241            scale = torch.cat([torch.tensor([w, h], dtype=torch.float32)242                               for _ in range(polygons.shape[1] // 2)], dim=0)243            polygons = polygons / scale244            target["polygons"] = polygons245        return image, target246 247 248class Compose(object):249    def __init__(self, transforms):250        self.transforms = transforms251 252    def __call__(self, image, target):253        for t in self.transforms:254            image, target = t(image, target)255        return image, target256 257    def __repr__(self):258        format_string = self.__class__.__name__ + "("259        for t in self.transforms:260            format_string += "\n"261            format_string += "    {0}".format(t)262        format_string += "\n)"263        return format_string264 265 266class LargeScaleJitter(object):267    """268        implementation of large scale jitter from copy_paste269    """270 271    def __init__(self, output_size=512, aug_scale_min=0.3, aug_scale_max=2.0):272        self.desired_size = torch.tensor([output_size])273        self.aug_scale_min = aug_scale_min274        self.aug_scale_max = aug_scale_max275 276    def rescale_target(self, scaled_size, image_size, target):277        # compute rescaled targets278        image_scale = scaled_size / image_size279        ratio_height, ratio_width = image_scale280 281        target = target.copy()282        target["size"] = scaled_size283 284        if "boxes" in target:285            boxes = target["boxes"]286            scaled_boxes = boxes * torch.as_tensor([ratio_width, ratio_height, ratio_width, ratio_height])287            target["boxes"] = scaled_boxes288 289        if "area" in target:290            area = target["area"]291            scaled_area = area * (ratio_width * ratio_height)292            target["area"] = scaled_area293 294        if "masks" in target:295            assert False296            masks = target['masks']297            # masks = interpolate(298            #     masks[:, None].float(), scaled_size, mode="nearest")[:, 0] > 0.5299            target['masks'] = masks300        return target301 302    def crop_target(self, region, target):303        i, j, h, w = region304        fields = ["labels", "area"]305 306        target = target.copy()307        target["size"] = torch.tensor([h, w])308 309        if "boxes" in target:310            boxes = target["boxes"]311            max_size = torch.as_tensor([w, h], dtype=torch.float32)312            cropped_boxes = boxes - torch.as_tensor([j, i, j, i])313            cropped_boxes = torch.min(cropped_boxes.reshape(-1, 2, 2), max_size)314            cropped_boxes = cropped_boxes.clamp(min=0)315            area = (cropped_boxes[:, 1, :] - cropped_boxes[:, 0, :]).prod(dim=1)316            target["boxes"] = cropped_boxes.reshape(-1, 4)317            target["area"] = area318            fields.append("boxes")319 320        if "masks" in target:321            # FIXME should we update the area here if there are no boxes?322            target['masks'] = target['masks'][:, i:i + h, j:j + w]323            fields.append("masks")324 325        # remove elements for which the boxes or masks that have zero area326        if "boxes" in target or "masks" in target:327            # favor boxes selection when defining which elements to keep328            # this is compatible with previous implementation329            if "boxes" in target:330                cropped_boxes = target['boxes'].reshape(-1, 2, 2)331                keep = torch.all(cropped_boxes[:, 1, :] > cropped_boxes[:, 0, :], dim=1)332            else:333                keep = target['masks'].flatten(1).any(1)334 335            for field in fields:336                target[field] = target[field][keep.tolist()]337        return target338 339    def pad_target(self, padding, target):340        target = target.copy()341        if "masks" in target:342            target['masks'] = torch.nn.functional.pad(target['masks'], (0, padding[1], 0, padding[0]))343        return target344 345    def __call__(self, image, target=None):346        image_size = image.size347        image_size = torch.tensor(image_size[::-1])348 349        random_scale = torch.rand(1) * (self.aug_scale_max - self.aug_scale_min) + self.aug_scale_min350        scaled_size = (random_scale * self.desired_size).round()351 352        scale = torch.maximum(scaled_size / image_size[0], scaled_size / image_size[1])353        scaled_size = (image_size * scale).round().int()354 355        scaled_image = F.resize(image, scaled_size.tolist(), interpolation=Image.BICUBIC)356 357        if target is not None:358            target = self.rescale_target(scaled_size, image_size, target)359 360        # randomly crop or pad images361        if random_scale >= 1:362            # Selects non-zero random offset (x, y) if scaled image is larger than desired_size.363            max_offset = scaled_size - self.desired_size364            offset = (max_offset * torch.rand(2)).floor().int()365            region = (offset[0].item(), offset[1].item(),366                      self.desired_size[0].item(), self.desired_size[0].item())367            output_image = F.crop(scaled_image, *region)368            if target is not None:369                target = self.crop_target(region, target)370        else:371            assert False372            padding = self.desired_size - scaled_size373            output_image = F.pad(scaled_image, [0, 0, padding[1].item(), padding[0].item()])374            if target is not None:375                target = self.pad_target(padding, target)376 377        return output_image, target378 379 380class OriginLargeScaleJitter(object):381    """382        implementation of large scale jitter from copy_paste383    """384 385    def __init__(self, output_size=512, aug_scale_min=0.3, aug_scale_max=2.0):386        self.desired_size = torch.tensor(output_size)387        self.aug_scale_min = aug_scale_min388        self.aug_scale_max = aug_scale_max389 390    def rescale_target(self, scaled_size, image_size, target):391        # compute rescaled targets392        image_scale = scaled_size / image_size393        ratio_height, ratio_width = image_scale394 395        target = target.copy()396        target["size"] = scaled_size397 398        if "boxes" in target:399            boxes = target["boxes"]400            scaled_boxes = boxes * torch.as_tensor([ratio_width, ratio_height, ratio_width, ratio_height])401            target["boxes"] = scaled_boxes402 403        if "area" in target:404            area = target["area"]405            scaled_area = area * (ratio_width * ratio_height)406            target["area"] = scaled_area407 408        if "masks" in target:409            assert False410            masks = target['masks']411            # masks = interpolate(412            #     masks[:, None].float(), scaled_size, mode="nearest")[:, 0] > 0.5413            target['masks'] = masks414        return target415 416    def crop_target(self, region, target):417        i, j, h, w = region418        fields = ["labels", "area"]419 420        target = target.copy()421        target["size"] = torch.tensor([h, w])422 423        if "boxes" in target:424            boxes = target["boxes"]425            max_size = torch.as_tensor([w, h], dtype=torch.float32)426            cropped_boxes = boxes - torch.as_tensor([j, i, j, i])427            cropped_boxes = torch.min(cropped_boxes.reshape(-1, 2, 2), max_size)428            cropped_boxes = cropped_boxes.clamp(min=0)429            area = (cropped_boxes[:, 1, :] - cropped_boxes[:, 0, :]).prod(dim=1)430            target["boxes"] = cropped_boxes.reshape(-1, 4)431            target["area"] = area432            fields.append("boxes")433 434        if "masks" in target:435            # FIXME should we update the area here if there are no boxes?436            target['masks'] = target['masks'][:, i:i + h, j:j + w]437            fields.append("masks")438 439        # remove elements for which the boxes or masks that have zero area440        if "boxes" in target or "masks" in target:441            # favor boxes selection when defining which elements to keep442            # this is compatible with previous implementation443            if "boxes" in target:444                cropped_boxes = target['boxes'].reshape(-1, 2, 2)445                keep = torch.all(cropped_boxes[:, 1, :] > cropped_boxes[:, 0, :], dim=1)446            else:447                keep = target['masks'].flatten(1).any(1)448 449            for field in fields:450                target[field] = target[field][keep.tolist()]451        return target452 453    def pad_target(self, padding, target):454        target = target.copy()455        if "masks" in target:456            target['masks'] = torch.nn.functional.pad(target['masks'], (0, padding[1], 0, padding[0]))457        return target458 459    def __call__(self, image, target=None):460        image_size = image.size461        image_size = torch.tensor(image_size[::-1])462 463        out_desired_size = (self.desired_size * image_size / max(image_size)).round().int()464 465        random_scale = torch.rand(1) * (self.aug_scale_max - self.aug_scale_min) + self.aug_scale_min466        scaled_size = (random_scale * self.desired_size).round()467 468        scale = torch.minimum(scaled_size / image_size[0], scaled_size / image_size[1])469        scaled_size = (image_size * scale).round().int()470 471        scaled_image = F.resize(image, scaled_size.tolist())472 473        if target is not None:474            target = self.rescale_target(scaled_size, image_size, target)475 476        # randomly crop or pad images477        if random_scale > 1:478            # Selects non-zero random offset (x, y) if scaled image is larger than desired_size.479            max_offset = scaled_size - out_desired_size480            offset = (max_offset * torch.rand(2)).floor().int()481            region = (offset[0].item(), offset[1].item(),482                      out_desired_size[0].item(), out_desired_size[1].item())483            output_image = F.crop(scaled_image, *region)484            if target is not None:485                target = self.crop_target(region, target)486        else:487            padding = out_desired_size - scaled_size488            output_image = F.pad(scaled_image, [0, 0, padding[1].item(), padding[0].item()])489            if target is not None:490                target = self.pad_target(padding, target)491 492        return output_image, target493 494 495class RandomDistortion(object):496    """497    Distort image w.r.t hue, saturation and exposure.498    """499 500    def __init__(self, brightness=0, contrast=0, saturation=0, hue=0, prob=0.5):501        self.prob = prob502        self.tfm = T.ColorJitter(brightness, contrast, saturation, hue)503 504    def __call__(self, img, target=None):505        if np.random.random() < self.prob:506            return self.tfm(img), target507        else:508            return img, target509