Source code for jactorch.transforms.coor.functional

#! /usr/bin/env python3
# -*- coding: utf-8 -*-
# File   : functional.py
# Author : Jiayuan Mao
# Email  : maojiayuan@gmail.com
# Date   : 03/03/2018
#
# This file is part of Jacinle.
# Distributed under terms of the MIT license.

import math

from PIL import Image
import numpy as np

import torchvision.transforms.functional as TF
import jactorch.transforms.image.functional as jac_tf
from jacinle.utils.argument import get_2dshape


[docs] def normalize_coor(img, coor): coor = coor.copy() coor[:, 0] /= img.width coor[:, 1] /= img.height return img, coor
[docs] def denormalize_coor(img, coor): coor = coor.copy() coor[:, 0] *= img.width coor[:, 1] *= img.height return img, coor
[docs] def crop(img, coor, i, j, h, w): coor = coor.copy() coor[:, 0] = (coor[:, 0] - j / img.width) * (img.width / w) coor[:, 1] = (coor[:, 1] - i / img.height) * (img.height / h) return TF.crop(img, i, j, h, w), coor
[docs] def center_crop(img, coor, output_size): output_size = get_2dshape(output_size) w, h = img.size th, tw = output_size i = int(round((h - th) / 2.)) j = int(round((w - tw) / 2.)) return crop(img, coor, i, j, th, tw)
[docs] def pad(img, coor, padding, mode='constant', fill=0): if isinstance(padding, int): padding = (padding, padding, padding, padding) elif len(padding) == 2: padding = (padding[0], padding[1], padding[0], padding[1]) else: assert len(padding) == 4 img_new = jac_tf.pad(img, padding, mode=mode, fill=fill) coor = coor.copy() coor[:, 0] = (coor[:, 0] + padding[0] / img.width) * (img.width / img_new.width) coor[:, 1] = (coor[:, 1] + padding[1] / img.height) * (img.height/ img_new.height) return img_new, coor
[docs] def hflip(img, coor): coor = coor.copy() coor[:, 0] = 1 - coor[:, 0] return TF.hflip(img), coor
[docs] def vflip(img, coor): coor = coor.copy() coor[:, 1] = 1 - coor[:, 1] return TF.vflip(img), coor
[docs] def resize(img, coor, size, interpolation=Image.BILINEAR): # Assuming coordinates are 0/1-normalized. return TF.resize(img, size, interpolation=interpolation), coor
[docs] def resized_crop(img, coor, i, j, h, w, size, interpolation=Image.BILINEAR): img, coor = crop(img, coor, i, j, h, w) img, coor = resize(img, coor, size, interpolation) return img, coor
[docs] def refresh_valid(img, coor, force=False): if coor.shape[1] == 2: if force: coor = np.concatenate([coor, np.ones_like(coor[:, 0])], axis=1) else: return img, coor assert coor.shape[1] == 3, 'Support only (x, y, valid) or (x, y) typed coordinates.' out = [] for x, y, v in coor: valid = (v == 1) and (x >= 0) and (x < img.width) and (y >= 0) and (y < img.height) if valid: out.append((x, y, v)) else: out.append((0., 0., 0.)) return img, np.array(out, dtype='float32')
[docs] def rotate(img, coor, angle, resample, crop_, expand, center=None, translate=None): assert translate is None img_new = TF.rotate(img, angle, resample=resample, expand=expand, center=center) matrix, extra_crop = get_rotation_matrix(img, angle, crop_, expand, center, translate) _, coor = denormalize_coor(img, coor) for i in range(coor.shape[0]): coor[i, :2] = apply_affine_transform(*coor[i, :2], matrix) _, coor = normalize_coor(img_new, coor) if extra_crop is not None: img_new, coor = crop(img_new, coor, *extra_crop) return img_new, coor
[docs] def pad_multiple_of(img, coor, multiple, mode='constant', fill=0): h, w = img.height, img.width hh = h - h % multiple + multiple * int(h % multiple != 0) ww = w - w % multiple + multiple * int(w % multiple != 0) if h != hh or w != ww: return pad(img, coor, (0, 0, ww - w, hh - h), mode=mode, fill=fill) return img, coor
[docs] def get_rotation_matrix(image, angle, crop, expand, center, translate): w, h = image.size if translate is None: translate = (0, 0) if center is None: center = (w / 2.0, h / 2.0) angle = math.radians(angle % 360) matrix = [ round(math.cos(angle), 15), round(math.sin(angle), 15), 0.0, round(-math.sin(angle), 15), round(math.cos(angle), 15), 0.0 ] matrix[2], matrix[5] = apply_affine_transform(-center[0], -center[1], matrix) matrix[2] += center[0] + translate[0] matrix[5] += center[1] + translate[1] # print('debug', angle, translate, center, matrix, apply_affine_transform(0.5, 0.5, matrix)) if crop or expand: xx = [] yy = [] for x, y in ((0, 0), (w, 0), (w, h), (0, h)): x, y = apply_affine_transform(x, y, matrix) xx.append(x) yy.append(y) xx.sort() yy.sort() extra_crop = None if crop: assert not expand, 'Cannot use both expand and crop.' nw = int(math.ceil(xx[2]) - math.floor(xx[1])) nh = int(math.ceil(yy[2]) - math.floor(yy[1])) # CAUSION! extra_crop is of format (dy, dx, h, w) extra_crop = ((h - nh) // 2, (w - nw) // 2, nh, nw) if expand: nw = int(math.ceil(xx[3]) - math.floor(xx[0])) nh = int(math.ceil(yy[3]) - math.floor(yy[0])) matrix[2] += (nw - w) / 2. matrix[5] += (nh - h) / 2. return matrix, extra_crop
[docs] def apply_affine_transform(x, y, matrix): (a, b, c, d, e, f) = matrix return a*x + b*y + c, d*x + e*y + f