Spaces:
Running
Running
# Copyright 2019-present NAVER Corp. | |
# CC BY-NC-SA 3.0 | |
# Available only for non-commercial use | |
import pdb | |
import numpy as np | |
from PIL import Image, ImageOps, ImageEnhance | |
class DummyImg: | |
"""This class is a dummy image only defined by its size.""" | |
def __init__(self, size): | |
self.size = size | |
def resize(self, size, *args, **kwargs): | |
return DummyImg(size) | |
def expand(self, border): | |
w, h = self.size | |
if isinstance(border, int): | |
size = (w + 2 * border, h + 2 * border) | |
else: | |
l, t, r, b = border | |
size = (w + l + r, h + t + b) | |
return DummyImg(size) | |
def crop(self, border): | |
w, h = self.size | |
l, t, r, b = border | |
assert 0 <= l <= r <= w | |
assert 0 <= t <= b <= h | |
size = (r - l, b - t) | |
return DummyImg(size) | |
def rotate(self, angle): | |
raise NotImplementedError | |
def transform(self, size, *args, **kwargs): | |
return DummyImg(size) | |
def grab_img(img_and_label): | |
"""Called to extract the image from an img_and_label input | |
(a dictionary). Also compatible with old-style PIL images. | |
""" | |
if isinstance(img_and_label, dict): | |
# if input is a dictionary, then | |
# it must contains the img or its size. | |
try: | |
return img_and_label["img"] | |
except KeyError: | |
return DummyImg(img_and_label["imsize"]) | |
else: | |
# or it must be the img directly | |
return img_and_label | |
def update_img_and_labels(img_and_label, img, persp=None): | |
"""Called to update the img_and_label""" | |
if isinstance(img_and_label, dict): | |
img_and_label["img"] = img | |
img_and_label["imsize"] = img.size | |
if persp: | |
if "persp" not in img_and_label: | |
img_and_label["persp"] = (1, 0, 0, 0, 1, 0, 0, 0) | |
img_and_label["persp"] = persp_mul(persp, img_and_label["persp"]) | |
return img_and_label | |
else: | |
# or it must be the img directly | |
return img | |
def rand_log_uniform(a, b): | |
return np.exp(np.random.uniform(np.log(a), np.log(b))) | |
def translate(tx, ty): | |
return (1, 0, tx, 0, 1, ty, 0, 0) | |
def rotate(angle): | |
return (np.cos(angle), -np.sin(angle), 0, np.sin(angle), np.cos(angle), 0, 0, 0) | |
def persp_mul(mat, mat2): | |
"""homography (perspective) multiplication. | |
mat: 8-tuple (homography transform) | |
mat2: 8-tuple (homography transform) or 2-tuple (point) | |
""" | |
assert isinstance(mat, tuple) | |
assert isinstance(mat2, tuple) | |
mat = np.float32(mat + (1,)).reshape(3, 3) | |
mat2 = np.array(mat2 + (1,)).reshape(3, 3) | |
res = np.dot(mat, mat2) | |
return tuple((res / res[2, 2]).ravel()[:8]) | |
def persp_apply(mat, pts): | |
"""homography (perspective) transformation. | |
mat: 8-tuple (homography transform) | |
pts: numpy array | |
""" | |
assert isinstance(mat, tuple) | |
assert isinstance(pts, np.ndarray) | |
assert pts.shape[-1] == 2 | |
mat = np.float32(mat + (1,)).reshape(3, 3) | |
if pts.ndim == 1: | |
pt = np.dot(pts, mat[:, :2].T).ravel() + mat[:, 2] | |
pt /= pt[2] # homogeneous coordinates | |
return tuple(pt[:2]) | |
else: | |
pt = np.dot(pts, mat[:, :2].T) + mat[:, 2] | |
pt[:, :2] /= pt[:, 2:3] # homogeneous coordinates | |
return pt[:, :2] | |
def is_pil_image(img): | |
return isinstance(img, Image.Image) | |
def adjust_brightness(img, brightness_factor): | |
"""Adjust brightness of an Image. | |
Args: | |
img (PIL Image): PIL Image to be adjusted. | |
brightness_factor (float): How much to adjust the brightness. Can be | |
any non negative number. 0 gives a black image, 1 gives the | |
original image while 2 increases the brightness by a factor of 2. | |
Returns: | |
PIL Image: Brightness adjusted image. | |
Copied from https://github.com/pytorch in torchvision/transforms/functional.py | |
""" | |
if not is_pil_image(img): | |
raise TypeError("img should be PIL Image. Got {}".format(type(img))) | |
enhancer = ImageEnhance.Brightness(img) | |
img = enhancer.enhance(brightness_factor) | |
return img | |
def adjust_contrast(img, contrast_factor): | |
"""Adjust contrast of an Image. | |
Args: | |
img (PIL Image): PIL Image to be adjusted. | |
contrast_factor (float): How much to adjust the contrast. Can be any | |
non negative number. 0 gives a solid gray image, 1 gives the | |
original image while 2 increases the contrast by a factor of 2. | |
Returns: | |
PIL Image: Contrast adjusted image. | |
Copied from https://github.com/pytorch in torchvision/transforms/functional.py | |
""" | |
if not is_pil_image(img): | |
raise TypeError("img should be PIL Image. Got {}".format(type(img))) | |
enhancer = ImageEnhance.Contrast(img) | |
img = enhancer.enhance(contrast_factor) | |
return img | |
def adjust_saturation(img, saturation_factor): | |
"""Adjust color saturation of an image. | |
Args: | |
img (PIL Image): PIL Image to be adjusted. | |
saturation_factor (float): How much to adjust the saturation. 0 will | |
give a black and white image, 1 will give the original image while | |
2 will enhance the saturation by a factor of 2. | |
Returns: | |
PIL Image: Saturation adjusted image. | |
Copied from https://github.com/pytorch in torchvision/transforms/functional.py | |
""" | |
if not is_pil_image(img): | |
raise TypeError("img should be PIL Image. Got {}".format(type(img))) | |
enhancer = ImageEnhance.Color(img) | |
img = enhancer.enhance(saturation_factor) | |
return img | |
def adjust_hue(img, hue_factor): | |
"""Adjust hue of an image. | |
The image hue is adjusted by converting the image to HSV and | |
cyclically shifting the intensities in the hue channel (H). | |
The image is then converted back to original image mode. | |
`hue_factor` is the amount of shift in H channel and must be in the | |
interval `[-0.5, 0.5]`. | |
See https://en.wikipedia.org/wiki/Hue for more details on Hue. | |
Args: | |
img (PIL Image): PIL Image to be adjusted. | |
hue_factor (float): How much to shift the hue channel. Should be in | |
[-0.5, 0.5]. 0.5 and -0.5 give complete reversal of hue channel in | |
HSV space in positive and negative direction respectively. | |
0 means no shift. Therefore, both -0.5 and 0.5 will give an image | |
with complementary colors while 0 gives the original image. | |
Returns: | |
PIL Image: Hue adjusted image. | |
Copied from https://github.com/pytorch in torchvision/transforms/functional.py | |
""" | |
if not (-0.5 <= hue_factor <= 0.5): | |
raise ValueError("hue_factor is not in [-0.5, 0.5].".format(hue_factor)) | |
if not is_pil_image(img): | |
raise TypeError("img should be PIL Image. Got {}".format(type(img))) | |
input_mode = img.mode | |
if input_mode in {"L", "1", "I", "F"}: | |
return img | |
h, s, v = img.convert("HSV").split() | |
np_h = np.array(h, dtype=np.uint8) | |
# uint8 addition take cares of rotation across boundaries | |
with np.errstate(over="ignore"): | |
np_h += np.uint8(hue_factor * 255) | |
h = Image.fromarray(np_h, "L") | |
img = Image.merge("HSV", (h, s, v)).convert(input_mode) | |
return img | |