Image Processing

misc codes

Split 2n vertices into multiple 4 vertices#

간단히 아래 그림을 참조하면, 10 vertices를 [4 vertices, 4 vertices, 4 vertices, 4 vertices] 로 변경합니다.

https://s3-us-west-2.amazonaws.com/aistages-prod-server-public/app/Users/00000526/files/bd9306f8-1355-4b73-bb06-982733064679..png

def parse_vertices(vertices):
    n_pts = len(vertices)
    assert n_pts % 2 == 0, 'Wrong points! It has odd vertices.'
    vertices = np.array(vertices)
    return [
        np.vstack(
            [vertices[idx:idx + 2],
             vertices[n_pts - 2 - idx:n_pts - idx]]).flatten()
        for idx in range(int(n_pts / 2) - 1)
    ]

Extract a specific region(mask) of a image along label#

def merge_image(insert_image, insert_mask, class_id, base_image=None, base_mask=None):
    """
    Args:
        insert_image: 추출하려고 하는 이미지
        insert_mask: 추출하려고 하는 이미지의 마스크
        class_id: 목적 class
        base_image: 배경이 되는 이미지
        base_mask: 배경이 되는 이미지의 마스크
    """
    tmp_img = np.ones((512,512,3), dtype=np.uint8) * 255
    if type(base_image) is type(None):
        base_image = tmp_img.copy()
    tmp_img[:,:,0] = np.where(insert_mask == class_id, insert_image[:,:,0], base_image[:,:,0])  # R or B
    tmp_img[:,:,1] = np.where(insert_mask == class_id, insert_image[:,:,1], base_image[:,:,1])  # G
    tmp_img[:,:,2] = np.where(insert_mask == class_id, insert_image[:,:,2], base_image[:,:,2])  # B or R
    if type(base_mask) is type(None):
        base_mask = np.zeros((512,512), dtype=np.uint8)
    tmp_mask = np.where(insert_mask == class_id, insert_mask, base_mask)  # mask
    return tmp_img, tmp_mask.astype(np.uint8)

Normalize Image#

Xμσ\frac{X - \mu}{\sigma}
class albumentations.augmentations.transforms.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225), max_pixel_value=255.0, always_apply=False, p=1.0)
"""
img = (img - mean * max_pixel_value) / (std * max_pixel_value)
"""

Un-normalize Image#

Issue#

# matplot/imshow.py data 전처리 코드

# If the input data has values outside the valid range (after
# normalisation), we issue a warning and then clip X to the bounds
# - otherwise casting wraps extreme values, hiding outliers and
# making reliable interpretation impossible.
high = 255 if np.issubdtype(self._A.dtype, np.integer) else 1
if self._A.min() < 0 or high < self._A.max():
    _log.warning(
        'Clipping input data to the valid range for imshow with '
        'RGB data ([0..1] for floats or [0..255] for integers).'
    )
    self._A = np.clip(self._A, 0, high)

Normalized image는 대략 -2.1부터 2.6까지 값을 가지기 때문에 0과 1 사이를 제외한 값들은 clip 된다. 그래서 이미지가 다르게 표현된다.

Solution#

PyTorch 포럼의 UnNormalize 코드를 수정.

  • float [0..1]
  • uint8 [0..255]
# https://discuss.pytorch.org/t/simple-way-to-inverse-transform-normalization/4821/3

class TensorToNumpyImage:
    def __init__(self,
        mean: tuple = (0.485, 0.456, 0.406), 
        std: tuple = (0.229, 0.224, 0.225), 
        uint8: bool = False):

        self.mean = mean
        self.std = std
        self._uint8 = uint8

    def __call__(self, tensor):
        """
        Args:
            tensor (Tensor): Tensor image of size (C, H, W) to be normalized.
        Returns:
            array (numpy.ndarray): Numpy array of size (H, W, C). ([0..1] for floats or [0..255] for integers)
        """
        _tensor = tensor.detach().cpu().clone()
        for t, m, s in zip(_tensor, self.mean, self.std):
            t.mul_(s).add_(m)
            # The normalize code -> t.sub_(m).div_(s)

        if self._uint8:
            return _tensor.mul_(255).numpy().astype(np.uint8).transpose(1, 2, 0)
        else:
            return _tensor.numpy().transpose(1, 2, 0)

tensor2image_float = TensorToNumpyImage(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225), uint8=False)
tensor2image_uint8 = TensorToNumpyImage(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225), uint8=True)

Caution: Tensor를 clone 해야 한다. 그렇지 않은 경우 원래 Tensor가 변형된다.

Simple way to inverse transform ? Normalization