123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493 |
- # Copyright (c) OpenMMLab. All rights reserved.
- import math
- from typing import Optional
- import mmcv
- import numpy as np
- from mmcv.transforms import BaseTransform
- from mmcv.transforms.utils import cache_randomness
- from mmdet.registry import TRANSFORMS
- from .augment_wrappers import _MAX_LEVEL, level_to_mag
- @TRANSFORMS.register_module()
- class ColorTransform(BaseTransform):
- """Base class for color transformations. All color transformations need to
- inherit from this base class. ``ColorTransform`` unifies the class
- attributes and class functions of color transformations (Color, Brightness,
- Contrast, Sharpness, Solarize, SolarizeAdd, Equalize, AutoContrast, Invert,
- and Posterize), and only distort color channels, without impacting the
- locations of the instances.
- Required Keys:
- - img
- Modified Keys:
- - img
- Args:
- prob (float): The probability for performing the geometric
- transformation and should be in range [0, 1]. Defaults to 1.0.
- level (int, optional): The level should be in range [0, _MAX_LEVEL].
- If level is None, it will generate from [0, _MAX_LEVEL] randomly.
- Defaults to None.
- min_mag (float): The minimum magnitude for color transformation.
- Defaults to 0.1.
- max_mag (float): The maximum magnitude for color transformation.
- Defaults to 1.9.
- """
- def __init__(self,
- prob: float = 1.0,
- level: Optional[int] = None,
- min_mag: float = 0.1,
- max_mag: float = 1.9) -> None:
- assert 0 <= prob <= 1.0, f'The probability of the transformation ' \
- f'should be in range [0,1], got {prob}.'
- assert level is None or isinstance(level, int), \
- f'The level should be None or type int, got {type(level)}.'
- assert level is None or 0 <= level <= _MAX_LEVEL, \
- f'The level should be in range [0,{_MAX_LEVEL}], got {level}.'
- assert isinstance(min_mag, float), \
- f'min_mag should be type float, got {type(min_mag)}.'
- assert isinstance(max_mag, float), \
- f'max_mag should be type float, got {type(max_mag)}.'
- assert min_mag <= max_mag, \
- f'min_mag should smaller than max_mag, ' \
- f'got min_mag={min_mag} and max_mag={max_mag}'
- self.prob = prob
- self.level = level
- self.min_mag = min_mag
- self.max_mag = max_mag
- def _transform_img(self, results: dict, mag: float) -> None:
- """Transform the image."""
- pass
- @cache_randomness
- def _random_disable(self):
- """Randomly disable the transform."""
- return np.random.rand() > self.prob
- @cache_randomness
- def _get_mag(self):
- """Get the magnitude of the transform."""
- return level_to_mag(self.level, self.min_mag, self.max_mag)
- def transform(self, results: dict) -> dict:
- """Transform function for images.
- Args:
- results (dict): Result dict from loading pipeline.
- Returns:
- dict: Transformed results.
- """
- if self._random_disable():
- return results
- mag = self._get_mag()
- self._transform_img(results, mag)
- return results
- def __repr__(self) -> str:
- repr_str = self.__class__.__name__
- repr_str += f'(prob={self.prob}, '
- repr_str += f'level={self.level}, '
- repr_str += f'min_mag={self.min_mag}, '
- repr_str += f'max_mag={self.max_mag})'
- return repr_str
- @TRANSFORMS.register_module()
- class Color(ColorTransform):
- """Adjust the color balance of the image, in a manner similar to the
- controls on a colour TV set. A magnitude=0 gives a black & white image,
- whereas magnitude=1 gives the original image. The bboxes, masks and
- segmentations are not modified.
- Required Keys:
- - img
- Modified Keys:
- - img
- Args:
- prob (float): The probability for performing Color transformation.
- Defaults to 1.0.
- level (int, optional): Should be in range [0,_MAX_LEVEL].
- If level is None, it will generate from [0, _MAX_LEVEL] randomly.
- Defaults to None.
- min_mag (float): The minimum magnitude for Color transformation.
- Defaults to 0.1.
- max_mag (float): The maximum magnitude for Color transformation.
- Defaults to 1.9.
- """
- def __init__(self,
- prob: float = 1.0,
- level: Optional[int] = None,
- min_mag: float = 0.1,
- max_mag: float = 1.9) -> None:
- assert 0. <= min_mag <= 2.0, \
- f'min_mag for Color should be in range [0,2], got {min_mag}.'
- assert 0. <= max_mag <= 2.0, \
- f'max_mag for Color should be in range [0,2], got {max_mag}.'
- super().__init__(
- prob=prob, level=level, min_mag=min_mag, max_mag=max_mag)
- def _transform_img(self, results: dict, mag: float) -> None:
- """Apply Color transformation to image."""
- # NOTE defaultly the image should be BGR format
- img = results['img']
- results['img'] = mmcv.adjust_color(img, mag).astype(img.dtype)
- @TRANSFORMS.register_module()
- class Brightness(ColorTransform):
- """Adjust the brightness of the image. A magnitude=0 gives a black image,
- whereas magnitude=1 gives the original image. The bboxes, masks and
- segmentations are not modified.
- Required Keys:
- - img
- Modified Keys:
- - img
- Args:
- prob (float): The probability for performing Brightness transformation.
- Defaults to 1.0.
- level (int, optional): Should be in range [0,_MAX_LEVEL].
- If level is None, it will generate from [0, _MAX_LEVEL] randomly.
- Defaults to None.
- min_mag (float): The minimum magnitude for Brightness transformation.
- Defaults to 0.1.
- max_mag (float): The maximum magnitude for Brightness transformation.
- Defaults to 1.9.
- """
- def __init__(self,
- prob: float = 1.0,
- level: Optional[int] = None,
- min_mag: float = 0.1,
- max_mag: float = 1.9) -> None:
- assert 0. <= min_mag <= 2.0, \
- f'min_mag for Brightness should be in range [0,2], got {min_mag}.'
- assert 0. <= max_mag <= 2.0, \
- f'max_mag for Brightness should be in range [0,2], got {max_mag}.'
- super().__init__(
- prob=prob, level=level, min_mag=min_mag, max_mag=max_mag)
- def _transform_img(self, results: dict, mag: float) -> None:
- """Adjust the brightness of image."""
- img = results['img']
- results['img'] = mmcv.adjust_brightness(img, mag).astype(img.dtype)
- @TRANSFORMS.register_module()
- class Contrast(ColorTransform):
- """Control the contrast of the image. A magnitude=0 gives a gray image,
- whereas magnitude=1 gives the original imageThe bboxes, masks and
- segmentations are not modified.
- Required Keys:
- - img
- Modified Keys:
- - img
- Args:
- prob (float): The probability for performing Contrast transformation.
- Defaults to 1.0.
- level (int, optional): Should be in range [0,_MAX_LEVEL].
- If level is None, it will generate from [0, _MAX_LEVEL] randomly.
- Defaults to None.
- min_mag (float): The minimum magnitude for Contrast transformation.
- Defaults to 0.1.
- max_mag (float): The maximum magnitude for Contrast transformation.
- Defaults to 1.9.
- """
- def __init__(self,
- prob: float = 1.0,
- level: Optional[int] = None,
- min_mag: float = 0.1,
- max_mag: float = 1.9) -> None:
- assert 0. <= min_mag <= 2.0, \
- f'min_mag for Contrast should be in range [0,2], got {min_mag}.'
- assert 0. <= max_mag <= 2.0, \
- f'max_mag for Contrast should be in range [0,2], got {max_mag}.'
- super().__init__(
- prob=prob, level=level, min_mag=min_mag, max_mag=max_mag)
- def _transform_img(self, results: dict, mag: float) -> None:
- """Adjust the image contrast."""
- img = results['img']
- results['img'] = mmcv.adjust_contrast(img, mag).astype(img.dtype)
- @TRANSFORMS.register_module()
- class Sharpness(ColorTransform):
- """Adjust images sharpness. A positive magnitude would enhance the
- sharpness and a negative magnitude would make the image blurry. A
- magnitude=0 gives the origin img.
- Required Keys:
- - img
- Modified Keys:
- - img
- Args:
- prob (float): The probability for performing Sharpness transformation.
- Defaults to 1.0.
- level (int, optional): Should be in range [0,_MAX_LEVEL].
- If level is None, it will generate from [0, _MAX_LEVEL] randomly.
- Defaults to None.
- min_mag (float): The minimum magnitude for Sharpness transformation.
- Defaults to 0.1.
- max_mag (float): The maximum magnitude for Sharpness transformation.
- Defaults to 1.9.
- """
- def __init__(self,
- prob: float = 1.0,
- level: Optional[int] = None,
- min_mag: float = 0.1,
- max_mag: float = 1.9) -> None:
- assert 0. <= min_mag <= 2.0, \
- f'min_mag for Sharpness should be in range [0,2], got {min_mag}.'
- assert 0. <= max_mag <= 2.0, \
- f'max_mag for Sharpness should be in range [0,2], got {max_mag}.'
- super().__init__(
- prob=prob, level=level, min_mag=min_mag, max_mag=max_mag)
- def _transform_img(self, results: dict, mag: float) -> None:
- """Adjust the image sharpness."""
- img = results['img']
- results['img'] = mmcv.adjust_sharpness(img, mag).astype(img.dtype)
- @TRANSFORMS.register_module()
- class Solarize(ColorTransform):
- """Solarize images (Invert all pixels above a threshold value of
- magnitude.).
- Required Keys:
- - img
- Modified Keys:
- - img
- Args:
- prob (float): The probability for performing Solarize transformation.
- Defaults to 1.0.
- level (int, optional): Should be in range [0,_MAX_LEVEL].
- If level is None, it will generate from [0, _MAX_LEVEL] randomly.
- Defaults to None.
- min_mag (float): The minimum magnitude for Solarize transformation.
- Defaults to 0.0.
- max_mag (float): The maximum magnitude for Solarize transformation.
- Defaults to 256.0.
- """
- def __init__(self,
- prob: float = 1.0,
- level: Optional[int] = None,
- min_mag: float = 0.0,
- max_mag: float = 256.0) -> None:
- assert 0. <= min_mag <= 256.0, f'min_mag for Solarize should be ' \
- f'in range [0, 256], got {min_mag}.'
- assert 0. <= max_mag <= 256.0, f'max_mag for Solarize should be ' \
- f'in range [0, 256], got {max_mag}.'
- super().__init__(
- prob=prob, level=level, min_mag=min_mag, max_mag=max_mag)
- def _transform_img(self, results: dict, mag: float) -> None:
- """Invert all pixel values above magnitude."""
- img = results['img']
- results['img'] = mmcv.solarize(img, mag).astype(img.dtype)
- @TRANSFORMS.register_module()
- class SolarizeAdd(ColorTransform):
- """SolarizeAdd images. For each pixel in the image that is less than 128,
- add an additional amount to it decided by the magnitude.
- Required Keys:
- - img
- Modified Keys:
- - img
- Args:
- prob (float): The probability for performing SolarizeAdd
- transformation. Defaults to 1.0.
- level (int, optional): Should be in range [0,_MAX_LEVEL].
- If level is None, it will generate from [0, _MAX_LEVEL] randomly.
- Defaults to None.
- min_mag (float): The minimum magnitude for SolarizeAdd transformation.
- Defaults to 0.0.
- max_mag (float): The maximum magnitude for SolarizeAdd transformation.
- Defaults to 110.0.
- """
- def __init__(self,
- prob: float = 1.0,
- level: Optional[int] = None,
- min_mag: float = 0.0,
- max_mag: float = 110.0) -> None:
- assert 0. <= min_mag <= 110.0, f'min_mag for SolarizeAdd should be ' \
- f'in range [0, 110], got {min_mag}.'
- assert 0. <= max_mag <= 110.0, f'max_mag for SolarizeAdd should be ' \
- f'in range [0, 110], got {max_mag}.'
- super().__init__(
- prob=prob, level=level, min_mag=min_mag, max_mag=max_mag)
- def _transform_img(self, results: dict, mag: float) -> None:
- """SolarizeAdd the image."""
- img = results['img']
- img_solarized = np.where(img < 128, np.minimum(img + mag, 255), img)
- results['img'] = img_solarized.astype(img.dtype)
- @TRANSFORMS.register_module()
- class Posterize(ColorTransform):
- """Posterize images (reduce the number of bits for each color channel).
- Required Keys:
- - img
- Modified Keys:
- - img
- Args:
- prob (float): The probability for performing Posterize
- transformation. Defaults to 1.0.
- level (int, optional): Should be in range [0,_MAX_LEVEL].
- If level is None, it will generate from [0, _MAX_LEVEL] randomly.
- Defaults to None.
- min_mag (float): The minimum magnitude for Posterize transformation.
- Defaults to 0.0.
- max_mag (float): The maximum magnitude for Posterize transformation.
- Defaults to 4.0.
- """
- def __init__(self,
- prob: float = 1.0,
- level: Optional[int] = None,
- min_mag: float = 0.0,
- max_mag: float = 4.0) -> None:
- assert 0. <= min_mag <= 8.0, f'min_mag for Posterize should be ' \
- f'in range [0, 8], got {min_mag}.'
- assert 0. <= max_mag <= 8.0, f'max_mag for Posterize should be ' \
- f'in range [0, 8], got {max_mag}.'
- super().__init__(
- prob=prob, level=level, min_mag=min_mag, max_mag=max_mag)
- def _transform_img(self, results: dict, mag: float) -> None:
- """Posterize the image."""
- img = results['img']
- results['img'] = mmcv.posterize(img, math.ceil(mag)).astype(img.dtype)
- @TRANSFORMS.register_module()
- class Equalize(ColorTransform):
- """Equalize the image histogram. The bboxes, masks and segmentations are
- not modified.
- Required Keys:
- - img
- Modified Keys:
- - img
- Args:
- prob (float): The probability for performing Equalize transformation.
- Defaults to 1.0.
- level (int, optional): No use for Equalize transformation.
- Defaults to None.
- min_mag (float): No use for Equalize transformation. Defaults to 0.1.
- max_mag (float): No use for Equalize transformation. Defaults to 1.9.
- """
- def _transform_img(self, results: dict, mag: float) -> None:
- """Equalizes the histogram of one image."""
- img = results['img']
- results['img'] = mmcv.imequalize(img).astype(img.dtype)
- @TRANSFORMS.register_module()
- class AutoContrast(ColorTransform):
- """Auto adjust image contrast.
- Required Keys:
- - img
- Modified Keys:
- - img
- Args:
- prob (float): The probability for performing AutoContrast should
- be in range [0, 1]. Defaults to 1.0.
- level (int, optional): No use for AutoContrast transformation.
- Defaults to None.
- min_mag (float): No use for AutoContrast transformation.
- Defaults to 0.1.
- max_mag (float): No use for AutoContrast transformation.
- Defaults to 1.9.
- """
- def _transform_img(self, results: dict, mag: float) -> None:
- """Auto adjust image contrast."""
- img = results['img']
- results['img'] = mmcv.auto_contrast(img).astype(img.dtype)
- @TRANSFORMS.register_module()
- class Invert(ColorTransform):
- """Invert images.
- Required Keys:
- - img
- Modified Keys:
- - img
- Args:
- prob (float): The probability for performing invert therefore should
- be in range [0, 1]. Defaults to 1.0.
- level (int, optional): No use for Invert transformation.
- Defaults to None.
- min_mag (float): No use for Invert transformation. Defaults to 0.1.
- max_mag (float): No use for Invert transformation. Defaults to 1.9.
- """
- def _transform_img(self, results: dict, mag: float) -> None:
- """Invert the image."""
- img = results['img']
- results['img'] = mmcv.iminvert(img).astype(img.dtype)
|