Skip to content

augment_transform

data.transform.augmentation.augment_transform

Implement ImageTransform classes for image augmentation.

ImageType module-attribute

ImageType = ndarray

ParamsType module-attribute

ParamsType = Dict[str, Any]

MaskType module-attribute

MaskType = ndarray

BBoxesType module-attribute

BBoxesType = Union[ndarray, NumpyBoxes]

PolygonType module-attribute

PolygonType = List[ndarray]

OffsetType module-attribute

OffsetType = Tuple[float, float]

BaseTransform

BaseTransform(prob: float = 0.5)

Transform의 기본 interface를 정의합니다.

Source code in SaigeToolkit/data/transform/augmentation/base_transform.py
def __init__(self, prob: float = 0.5) -> None:
    self.prob = prob
    self._additional_targets = {}

prob instance-attribute

prob = prob

_additional_targets instance-attribute

_additional_targets = {}

data_for_params property

data_for_params: List[str]

targets property

targets: Dict[str, Callable]

__call__

__call__(*args, force_apply: bool = False, **data) -> Any
Source code in SaigeToolkit/data/transform/augmentation/base_transform.py
def __call__(self, *args, force_apply: bool = False, **data) -> Any:
    if args:
        raise KeyError("Data must be passed as named arguments, for example: aug(image=image)")

    if (random.random() < self.prob) or force_apply:
        params = {}
        if self.data_for_params:
            data_for_params = {k: data[k] for k in self.data_for_params}
            params_from_data = self.get_params_from_data(data_for_params)
            params.update(params_from_data)

        apply_param = self.get_apply_params()
        params.update(apply_param)
        data = self.apply_with_params(params, **data)

    return data

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/base_transform.py
def get_apply_params(self) -> ParamsType:
    return {}

get_params_from_data

get_params_from_data(data_for_params: ParamsType) -> ParamsType

이 함수는 input으로부터 parameter들을 뽑을 때 사용됩니다.

Parameters:

  • data_for_params (ParamsType) –

    params을 추출할 데이터를 입력으로 갖습니다.

Returns:

  • ParamsType ( ParamsType ) –

    params로 쓰일 데이터를 반환합니다.

Source code in SaigeToolkit/data/transform/augmentation/base_transform.py
def get_params_from_data(self, data_for_params: ParamsType) -> ParamsType:
    """이 함수는 input으로부터 parameter들을 뽑을 때 사용됩니다.

    Args:
        data_for_params (ParamsType): params을 추출할 데이터를 입력으로 갖습니다.

    Returns:
        ParamsType: params로 쓰일 데이터를 반환합니다.
    """
    return {}

apply_with_params

apply_with_params(params: ParamsType, **data) -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/base_transform.py
def apply_with_params(self, params: ParamsType, **data) -> ParamsType:
    def _apply_with_params(method: callable, target: str, data: Dict, params: ParamsType):
        output = []

        if isinstance(data, List) and target == "image":
            is_multipage = True
        else:
            is_multipage = False
            data = [data]

        for d in data:
            output.append(method(d, **params))

        if not is_multipage:
            output = output[0]

        return output

    for target, target_method in self.targets.items():
        if target in data:
            data[target] = _apply_with_params(target_method, target, data[target], params)
    for additional_target, target in self._additional_targets.items():
        if additional_target in data:
            target_method = self.targets[target]
            data[additional_target] = _apply_with_params(
                target_method, target, data[additional_target], params
            )
    return data

add_targets

add_targets(additional_targets: Dict[str, str]) -> None
Source code in SaigeToolkit/data/transform/augmentation/base_transform.py
def add_targets(self, additional_targets: Dict[str, str]) -> None:
    self._additional_targets = additional_targets

ImageTransform

ImageTransform(prob: float = 0.5)

Bases: BaseTransform

Image와 라벨에 적용되는 Transform 입니다.

Source code in SaigeToolkit/data/transform/augmentation/base_transform.py
def __init__(self, prob: float = 0.5) -> None:
    self.prob = prob
    self._additional_targets = {}

targets property

targets: Dict[str, Callable]

apply_to_image

apply_to_image(image: ImageType, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(self, image: ImageType, **params) -> ImageType:
    return image

apply_to_mask

apply_to_mask(mask: MaskType, **params) -> MaskType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_mask(self, mask: MaskType, **params) -> MaskType:
    return mask

apply_to_bboxes

apply_to_bboxes(bboxes: BBoxesType, **params) -> BBoxesType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_bboxes(self, bboxes: BBoxesType, **params) -> BBoxesType:
    return bboxes

apply_to_polygons

apply_to_polygons(polygons: PolygonType, **params) -> PolygonType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_polygons(self, polygons: PolygonType, **params) -> PolygonType:
    return polygons

ImageSizeParams

data_for_params property

data_for_params: List[str]

get_params_from_data

get_params_from_data(data_for_params: ParamsType) -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_params_from_data(self, data_for_params: ParamsType) -> ParamsType:
    img = data_for_params["image"]
    if not isinstance(img, list):
        return {"image_size": read_image_size(img)}
    else:
        return {"image_size": read_image_size(img[0])}

ToNumpy

ToNumpy(prob: float = 0.5)

Bases: ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/base_transform.py
def __init__(self, prob: float = 0.5) -> None:
    self.prob = prob
    self._additional_targets = {}

apply_to_image

apply_to_image(image: ImageType, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(self, image: ImageType, **params) -> ImageType:
    return to_numpy(image=image)

apply_to_mask

apply_to_mask(mask: MaskType, **params) -> MaskType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_mask(self, mask: MaskType, **params) -> MaskType:
    return to_numpy(image=mask)

ToPil

ToPil(prob: float = 0.5)

Bases: ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/base_transform.py
def __init__(self, prob: float = 0.5) -> None:
    self.prob = prob
    self._additional_targets = {}

apply_to_image

apply_to_image(image: ImageType, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(self, image: ImageType, **params) -> ImageType:
    return to_pil(image=image)

apply_to_mask

apply_to_mask(mask: MaskType, **params) -> MaskType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_mask(self, mask: MaskType, **params) -> MaskType:
    return to_pil(image=mask)

VerticalFlip

VerticalFlip(prob: float = 0.5)

Bases: ImageSizeParams, ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/base_transform.py
def __init__(self, prob: float = 0.5) -> None:
    self.prob = prob
    self._additional_targets = {}

apply_to_image

apply_to_image(image: ImageType, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(self, image: ImageType, **params) -> ImageType:
    return vertical_flip(image=image)

apply_to_mask

apply_to_mask(mask: MaskType, **params) -> MaskType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_mask(self, mask: MaskType, **params) -> MaskType:
    return vertical_flip(image=mask)

apply_to_bboxes

apply_to_bboxes(bboxes: BBoxesType, image_size: Tuple[int], **params) -> BBoxesType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_bboxes(self, bboxes: BBoxesType, image_size: Tuple[int], **params) -> BBoxesType:
    return box_function.vflip_box(bboxes=bboxes, image_size=image_size)

apply_to_polygons

apply_to_polygons(polygons: PolygonType, image_size: Tuple[int], **params) -> PolygonType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_polygons(self, polygons: PolygonType, image_size: Tuple[int], **params) -> PolygonType:
    return polygon_function.vertical_flip(polygons=polygons, image_size=image_size)

HorizontalFlip

HorizontalFlip(prob: float = 0.5)

Bases: ImageSizeParams, ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/base_transform.py
def __init__(self, prob: float = 0.5) -> None:
    self.prob = prob
    self._additional_targets = {}

apply_to_image

apply_to_image(image: ImageType, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(self, image: ImageType, **params) -> ImageType:
    return horizontal_flip(image=image)

apply_to_mask

apply_to_mask(mask: MaskType, **params) -> MaskType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_mask(self, mask: MaskType, **params) -> MaskType:
    return horizontal_flip(image=mask)

apply_to_bboxes

apply_to_bboxes(bboxes: BBoxesType, image_size: Tuple[int], **params) -> BBoxesType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_bboxes(self, bboxes: BBoxesType, image_size: Tuple[int], **params) -> BBoxesType:
    return box_function.hflip_box(bboxes=bboxes, image_size=image_size)

apply_to_polygons

apply_to_polygons(polygons: PolygonType, image_size: Tuple[int], **params) -> PolygonType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_polygons(self, polygons: PolygonType, image_size: Tuple[int], **params) -> PolygonType:
    return polygon_function.horizontal_flip(polygons=polygons, image_size=image_size)

Rotate

Rotate(angle_limit: Optional[List[float]] = None, interpolation: int = cv2.INTER_LINEAR, border_mode: int = cv2.BORDER_CONSTANT, value: Union[int, float, List[int], List[float]] = 0, mask_value: Union[int, float] = 0, crop_border: bool = False, **kwargs)

Bases: ImageSizeParams, ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(
    self,
    angle_limit: Optional[List[float]] = None,
    interpolation: int = cv2.INTER_LINEAR,
    border_mode: int = cv2.BORDER_CONSTANT,
    value: Union[int, float, List[int], List[float]] = 0,
    mask_value: Union[int, float] = 0,
    crop_border: bool = False,
    **kwargs,
) -> None:
    super().__init__(**kwargs)

    if angle_limit is None:
        angle_limit = [-30.0, 30.0]

    check_range(angle_limit, -360.0, 360.0)

    self.angle_limit = angle_limit
    self.interpolation = interpolation
    self.border_mode = border_mode
    self.value = value
    self.mask_value = mask_value
    self.crop_border = crop_border

angle_limit instance-attribute

angle_limit = angle_limit

interpolation instance-attribute

interpolation = interpolation

border_mode instance-attribute

border_mode = border_mode

value instance-attribute

value = value

mask_value instance-attribute

mask_value = mask_value

crop_border instance-attribute

crop_border = crop_border

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_apply_params(self) -> ParamsType:
    return {"angle": random.uniform(*self.angle_limit)}

apply_to_image

apply_to_image(image: ImageType, angle: float = 0, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(self, image: ImageType, angle: float = 0, **params) -> ImageType:
    return rotate(
        image=image,
        angle=angle,
        interpolation=self.interpolation,
        border_mode=self.border_mode,
        value=self.value,
        crop_border=self.crop_border,
    )

apply_to_mask

apply_to_mask(mask: MaskType, angle: float = 0, **params) -> MaskType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_mask(self, mask: MaskType, angle: float = 0, **params) -> MaskType:
    return rotate(
        image=mask,
        angle=angle,
        interpolation=cv2.INTER_NEAREST,
        border_mode=self.border_mode,
        value=self.mask_value,
        crop_border=self.crop_border,
    )

apply_to_bboxes

apply_to_bboxes(bboxes: BBoxesType, image_size: Tuple[int], angle: float = 0, **params) -> BBoxesType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_bboxes(
    self,
    bboxes: BBoxesType,
    image_size: Tuple[int],
    angle: float = 0,
    **params,
) -> BBoxesType:
    return box_function.rotate(bboxes=bboxes, angle=angle, image_size=image_size)

apply_to_polygons

apply_to_polygons(polygons: PolygonType, angle: float, image_size: Tuple[int], **params) -> PolygonType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_polygons(
    self,
    polygons: PolygonType,
    angle: float,
    image_size: Tuple[int],
    **params,
) -> PolygonType:
    return polygon_function.rotate(polygons=polygons, angle=angle, image_size=image_size)

RandomRotate90

RandomRotate90(**kwargs)

Bases: ImageSizeParams, ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(self, **kwargs) -> None:
    super().__init__(**kwargs)

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_apply_params(self) -> ParamsType:
    return {"factor": random.randint(0, 3)}

apply_to_image

apply_to_image(image: ImageType, factor: int = 0, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(self, image: ImageType, factor: int = 0, **params) -> ImageType:
    return random_rotate90(
        image=image,
        factor=factor,
    )

apply_to_mask

apply_to_mask(mask: MaskType, factor: int = 0, **params) -> MaskType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_mask(self, mask: MaskType, factor: int = 0, **params) -> MaskType:
    return random_rotate90(
        image=mask,
        factor=factor,
    )

apply_to_bboxes

apply_to_bboxes(bboxes: BBoxesType, image_size: Tuple[int], factor: int = 0, **params) -> BBoxesType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_bboxes(
    self,
    bboxes: BBoxesType,
    image_size: Tuple[int],
    factor: int = 0,
    **params,
) -> BBoxesType:
    return box_function.rotate90(bboxes=bboxes, factor=factor, image_size=image_size)

apply_to_polygons

apply_to_polygons(polygons: PolygonType, image_size: Tuple[int], factor: int = 0, **params) -> PolygonType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_polygons(
    self,
    polygons: PolygonType,
    image_size: Tuple[int],
    factor: int = 0,
    **params,
) -> PolygonType:
    return polygon_function.rotate90(polygons=polygons, factor=factor, image_size=image_size)

ColorJitter

ColorJitter(brightness_limit: Optional[List[float]] = None, contrast_limit: Optional[List[float]] = None, saturation_limit: Optional[List[float]] = None, hue_limit: Optional[List[float]] = None, **kwargs)

Bases: ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(
    self,
    brightness_limit: Optional[List[float]] = None,
    contrast_limit: Optional[List[float]] = None,
    saturation_limit: Optional[List[float]] = None,
    hue_limit: Optional[List[float]] = None,
    **kwargs,
) -> None:
    super().__init__(**kwargs)

    if brightness_limit is None:
        brightness_limit = [0.8, 1.2]
    if contrast_limit is None:
        contrast_limit = [0.8, 1.2]
    if saturation_limit is None:
        saturation_limit = [0.8, 1.2]
    if hue_limit is None:
        hue_limit = [-0.2, 0.2]

    check_range(brightness_limit, 0.01, 10.00)
    check_range(contrast_limit, 0.01, 10.00)
    check_range(saturation_limit, 0.01, 10.00)
    check_range(hue_limit, -0.50, 0.50)

    self.brightness_limit = brightness_limit
    self.contrast_limit = contrast_limit
    self.saturation_limit = saturation_limit
    self.hue_limit = hue_limit

brightness_limit instance-attribute

brightness_limit = brightness_limit

contrast_limit instance-attribute

contrast_limit = contrast_limit

saturation_limit instance-attribute

saturation_limit = saturation_limit

hue_limit instance-attribute

hue_limit = hue_limit

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_apply_params(self) -> ParamsType:
    order = [0, 1, 2, 3]
    random.shuffle(order)

    return {
        "brightness": random.uniform(*self.brightness_limit),
        "contrast": random.uniform(*self.contrast_limit),
        "saturation": random.uniform(*self.saturation_limit),
        "hue": random.uniform(*self.hue_limit),
        "order": order,
    }

apply_to_image

apply_to_image(image: ImageType, brightness: float = 1.0, contrast: float = 1.0, saturation: float = 1.0, hue: float = 0, order: List[int] = [0, 1, 2, 3], **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(
    self,
    image: ImageType,
    brightness: float = 1.0,
    contrast: float = 1.0,
    saturation: float = 1.0,
    hue: float = 0,
    order: List[int] = [0, 1, 2, 3],
    **params,
) -> ImageType:
    return color_jitter(
        image=image,
        brightness=brightness,
        contrast=contrast,
        saturation=saturation,
        hue=hue,
        order=order,
    )

Blur

Blur(ksize_limit: Optional[List[int]] = None, **kwargs)

Bases: ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(self, ksize_limit: Optional[List[int]] = None, **kwargs) -> None:
    super().__init__(**kwargs)

    if ksize_limit is None:
        ksize_limit = [3, 7]

    check_range(ksize_limit, 1, 100)

    self.ksize_limit = ksize_limit

ksize_limit instance-attribute

ksize_limit = ksize_limit

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_apply_params(self) -> ParamsType:
    return {"ksize": random.randint(*self.ksize_limit)}

apply_to_image

apply_to_image(image: ImageType, ksize: int = 3, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(self, image: ImageType, ksize: int = 3, **params) -> ImageType:
    return blur(image=image, ksize=ksize)

GaussianBlur

GaussianBlur(ksize_limit: Optional[List[int]] = None, sigma_limit: Optional[List[float]] = None, **kwargs)

Bases: ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(
    self,
    ksize_limit: Optional[List[int]] = None,
    sigma_limit: Optional[List[float]] = None,
    **kwargs,
) -> None:
    super().__init__(**kwargs)

    if ksize_limit is None:
        ksize_limit = [3, 7]
    if sigma_limit is None:
        sigma_limit = [0.0, 0.0]

    check_range(ksize_limit, 1, 100)
    check_range(sigma_limit, 0.00, 100.00)

    self.ksize_limit = ksize_limit
    self.sigma_limit = sigma_limit

ksize_limit instance-attribute

ksize_limit = ksize_limit

sigma_limit instance-attribute

sigma_limit = sigma_limit

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_apply_params(self) -> ParamsType:
    return {
        "ksize": random.randint(*self.ksize_limit),
        "sigma": random.uniform(*self.sigma_limit),
    }

apply_to_image

apply_to_image(image: ImageType, ksize: int = 3, sigma: float = 0.0, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(
    self, image: ImageType, ksize: int = 3, sigma: float = 0.0, **params
) -> ImageType:
    return gaussian_blur(image=image, ksize=ksize, sigma=sigma)

AdjustBrightness

AdjustBrightness(brightness_limit: Optional[List[float]] = None, **kwargs)

Bases: ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(self, brightness_limit: Optional[List[float]] = None, **kwargs) -> None:
    super().__init__(**kwargs)

    if brightness_limit is None:
        brightness_limit = [-0.2, 0.2]

    check_range(brightness_limit, -1.0, 1.0)

    self.brightness_limit = brightness_limit

brightness_limit instance-attribute

brightness_limit = brightness_limit

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_apply_params(self) -> ParamsType:
    return {"brightness": random.uniform(*self.brightness_limit)}

apply_to_image

apply_to_image(image: ImageType, brightness: float = 0.0, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(self, image: ImageType, brightness: float = 0.0, **params) -> ImageType:
    return adjust_brightness(image=image, brightness=brightness)

AdjustContrast

AdjustContrast(contrast_limit: Optional[List[float]] = None, **kwargs)

Bases: ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(self, contrast_limit: Optional[List[float]] = None, **kwargs) -> None:
    super().__init__(**kwargs)

    if contrast_limit is None:
        contrast_limit = [-0.2, 0.2]

    check_range(contrast_limit, -1.0, 1.0)

    self.contrast_limit = contrast_limit

contrast_limit instance-attribute

contrast_limit = contrast_limit

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_apply_params(self) -> ParamsType:
    return {"contrast": random.uniform(*self.contrast_limit)}

apply_to_image

apply_to_image(image: ImageType, contrast: float = 0.0, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(self, image: ImageType, contrast: float = 0.0, **params) -> ImageType:
    return adjust_contrast(image=image, contrast=contrast)

AdjustHue

AdjustHue(hue_limit: Optional[List[float]] = None, **kwargs)

Bases: ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(self, hue_limit: Optional[List[float]] = None, **kwargs) -> None:
    super().__init__(**kwargs)

    if hue_limit is None:
        hue_limit = [-0.2, 0.2]

    check_range(hue_limit, -1.0, 1.0)

    self.hue_limit = hue_limit

hue_limit instance-attribute

hue_limit = hue_limit

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_apply_params(self) -> ParamsType:
    return {"hue": random.uniform(*self.hue_limit)}

apply_to_image

apply_to_image(image: ImageType, hue: float = 0.0, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(self, image: ImageType, hue: float = 0.0, **params) -> ImageType:
    return adjust_hue(image=image, hue=hue)

AdjustSaturation

AdjustSaturation(saturation_limit: Optional[List[float]] = None, **kwargs)

Bases: ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(self, saturation_limit: Optional[List[float]] = None, **kwargs) -> None:
    super().__init__(**kwargs)

    if saturation_limit is None:
        saturation_limit = [-0.2, 0.2]

    check_range(saturation_limit, -1.0, 1.0)

    self.saturation_limit = saturation_limit

saturation_limit instance-attribute

saturation_limit = saturation_limit

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_apply_params(self) -> ParamsType:
    return {"saturation": random.uniform(*self.saturation_limit)}

apply_to_image

apply_to_image(image: ImageType, saturation: float = 0.0, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(self, image: ImageType, saturation: float = 0.0, **params) -> ImageType:
    return adjust_saturation(image=image, saturation=saturation)

AdjustGamma

AdjustGamma(gamma_limit: Optional[List[float]] = None, **kwargs)

Bases: ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(self, gamma_limit: Optional[List[float]] = None, **kwargs) -> None:
    super().__init__(**kwargs)

    if gamma_limit is None:
        gamma_limit = [-0.2, 0.2]

    check_range(gamma_limit, -1.0, 1.0)

    self.gamma_limit = gamma_limit

gamma_limit instance-attribute

gamma_limit = gamma_limit

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_apply_params(self) -> ParamsType:
    return {"gamma": random.uniform(*self.gamma_limit)}

apply_to_image

apply_to_image(image: ImageType, gamma: float = 0.0, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(self, image: ImageType, gamma: float = 0.0, **params) -> ImageType:
    return adjust_gamma(image=image, gamma=gamma)

AdjustBrightnessContrast

AdjustBrightnessContrast(brightness_limit: Optional[List[float]] = None, contrast_limit: Optional[List[float]] = None, brightness_by_max: bool = True, **kwargs)

Bases: ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(
    self,
    brightness_limit: Optional[List[float]] = None,
    contrast_limit: Optional[List[float]] = None,
    brightness_by_max: bool = True,
    **kwargs,
) -> None:
    super().__init__(**kwargs)

    if brightness_limit is None:
        brightness_limit = [-0.2, 0.2]
    if contrast_limit is None:
        contrast_limit = [-0.2, 0.2]

    check_range(brightness_limit, -1.00, 1.00)
    check_range(contrast_limit, -1.00, 1.00)

    self.brightness_limit = brightness_limit
    self.contrast_limit = contrast_limit
    self.brightness_by_max = brightness_by_max

brightness_limit instance-attribute

brightness_limit = brightness_limit

contrast_limit instance-attribute

contrast_limit = contrast_limit

brightness_by_max instance-attribute

brightness_by_max = brightness_by_max

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_apply_params(self) -> ParamsType:
    return {
        "brightness": random.uniform(*self.brightness_limit),
        "contrast": random.uniform(*self.contrast_limit),
    }

apply_to_image

apply_to_image(image: ImageType, brightness: float = 0.0, contrast: float = 0.0, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(
    self, image: ImageType, brightness: float = 0.0, contrast: float = 0.0, **params
) -> ImageType:
    return adjust_brightness_contrast(
        image=image,
        brightness=brightness,
        contrast=contrast,
        brightness_by_max=self.brightness_by_max,
    )

IsoNoise

IsoNoise(color_shift_limit: Optional[List[float]] = None, intensity_limit: Optional[List[float]] = None, **kwargs)

Bases: ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(
    self,
    color_shift_limit: Optional[List[float]] = None,
    intensity_limit: Optional[List[float]] = None,
    **kwargs,
) -> None:
    super().__init__(**kwargs)

    if color_shift_limit is None:
        color_shift_limit = [0.01, 0.05]
    if intensity_limit is None:
        intensity_limit = [0.1, 0.5]

    check_range(color_shift_limit, 0.00, 1.00)
    check_range(intensity_limit, 0.00, 2.00)

    self.color_shift_limit = color_shift_limit
    self.intensity_limit = intensity_limit

color_shift_limit instance-attribute

color_shift_limit = color_shift_limit

intensity_limit instance-attribute

intensity_limit = intensity_limit

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_apply_params(self) -> ParamsType:
    return {
        "color_shift": random.uniform(*self.color_shift_limit),
        "intensity": random.uniform(*self.intensity_limit),
        "random_state": random.randint(0, 65536),
    }

apply_to_image

apply_to_image(image: ImageType, color_shift: float = 0.05, intensity: float = 0.5, random_state: Optional[int] = None, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(
    self,
    image: ImageType,
    color_shift: float = 0.05,
    intensity: float = 0.50,
    random_state: Optional[int] = None,
    **params,
) -> ImageType:
    return iso_noise(
        image=image, color_shift=color_shift, intensity=intensity, random_state=random_state
    )

JpegCompression

JpegCompression(quality_limit: Optional[List[int]] = None, **kwargs)

Bases: ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(
    self,
    quality_limit: Optional[List[int]] = None,
    **kwargs,
) -> None:
    super().__init__(**kwargs)

    if quality_limit is None:
        quality_limit = [5, 30]

    check_range(quality_limit, 0, 100)

    self.quality_limit = quality_limit

quality_limit instance-attribute

quality_limit = quality_limit

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_apply_params(self) -> ParamsType:
    return {"quality": random.randint(*self.quality_limit)}

apply_to_image

apply_to_image(image: ImageType, quality: int = 100) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(
    self,
    image: ImageType,
    quality: int = 100,
) -> ImageType:
    return image_compression(image=image, quality=quality, image_type=".jpeg")

Sharpen

Sharpen(alpha_limit: Optional[List[int]] = None, lightness_limit: Optional[List[int]] = None, **kwargs)

Bases: ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(
    self,
    alpha_limit: Optional[List[int]] = None,
    lightness_limit: Optional[List[int]] = None,
    **kwargs,
) -> None:
    super().__init__(**kwargs)

    if alpha_limit is None:
        alpha_limit = [0.20, 0.50]

    if lightness_limit is None:
        lightness_limit = [0.80, 1.20]

    check_range(alpha_limit, 0.00, 1.00)
    check_range(lightness_limit, 0.00, 10.00)

    self.alpha_limit = alpha_limit
    self.lightness_limit = lightness_limit

alpha_limit instance-attribute

alpha_limit = alpha_limit

lightness_limit instance-attribute

lightness_limit = lightness_limit

_generate_sharpening_matrix

_generate_sharpening_matrix(alpha: float, lightness: float) -> ndarray
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def _generate_sharpening_matrix(self, alpha: float, lightness: float) -> np.ndarray:
    matrix_nochange = np.array([[0, 0, 0], [0, 1, 0], [0, 0, 0]], dtype=np.float32)
    matrix_effect = np.array(
        [[-1, -1, -1], [-1, 8 + lightness, -1], [-1, -1, -1]],
        dtype=np.float32,
    )
    matrix = (1 - alpha) * matrix_nochange + alpha * matrix_effect
    return matrix

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_apply_params(self) -> ParamsType:
    sharpening_matrix = self._generate_sharpening_matrix(
        random.uniform(*self.alpha_limit), random.uniform(*self.lightness_limit)
    )
    return {"sharpening_matrix": sharpening_matrix}

apply_to_image

apply_to_image(image: ImageType, sharpening_matrix: ndarray) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(
    self,
    image: ImageType,
    sharpening_matrix: np.ndarray,
) -> ImageType:
    return sharpen(image=image, sharpening_matrix=sharpening_matrix)

MultiplicativeNoise

MultiplicativeNoise(multiplier: Optional[List[float]] = None, per_channel: bool = True, **kwargs)

Bases: ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(
    self,
    multiplier: Optional[List[float]] = None,
    per_channel: bool = True,
    **kwargs,
) -> None:
    super().__init__(**kwargs)

    if multiplier is None:
        multiplier = [0.80, 1.20]

    check_range(multiplier, 0.00, 5.00)

    self.multiplier = multiplier
    self.per_channel = per_channel

multiplier instance-attribute

multiplier = multiplier

per_channel instance-attribute

per_channel = per_channel

_generate_multiplier

_generate_multiplier(image: ImageType, multiplier: ndarray, random_seed: int) -> ndarray
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def _generate_multiplier(
    self, image: ImageType, multiplier: np.ndarray, random_seed: int
) -> np.ndarray:
    if multiplier[0] == multiplier[1]:
        return np.array([multiplier[0]])

    height, width = image.shape[:2]
    num_channels = 3

    result_multiplier = np.random.RandomState(seed=random_seed).uniform(
        multiplier[0], multiplier[1], [height, width, num_channels]
    )
    return result_multiplier

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_apply_params(self) -> ParamsType:
    def _shrink_range(low: int, high: int) -> List[int]:
        lower_bound = random.uniform(low, high)
        upper_bound = random.uniform(lower_bound, high)
        return [lower_bound, upper_bound]

    return {
        "multiplier": np.array(_shrink_range(*self.multiplier)),
        "random_seed": random.randint(0, 65536),
    }

apply_to_image

apply_to_image(image: ImageType, multiplier: ndarray, random_seed: int) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(self, image: ImageType, multiplier: np.ndarray, random_seed: int) -> ImageType:
    _multiplier = self._generate_multiplier(image, multiplier, random_seed)
    return multiplicative_noise(image=image, multiplier=_multiplier)

RatioJitter

RatioJitter(proportion_limit: Optional[Union[List[float], int, float]] = None, resampling: str = 'bilinear', border_mode: int = cv2.BORDER_CONSTANT, value: Union[int, float, List[int], List[float]] = 0, mask_value: Union[int, float] = 0, **kwargs)

Bases: ImageSizeParams, ImageTransform

crop, pad, and resize to original image size

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(
    self,
    proportion_limit: Optional[Union[List[float], int, float]] = None,
    resampling: str = "bilinear",
    border_mode: int = cv2.BORDER_CONSTANT,
    value: Union[int, float, List[int], List[float]] = 0,
    mask_value: Union[int, float] = 0,
    **kwargs,
) -> None:
    super().__init__(**kwargs)

    if proportion_limit is None:
        proportion_limit = [-0.10, 0.10]

    if isinstance(proportion_limit, int):
        # NOTE: int 입력은 백분율로 적용.
        proportion_limit = [-abs(proportion_limit) / 100, abs(proportion_limit) / 100]

    if isinstance(proportion_limit, float):
        # NOTE: float 입력은 0~1 스케일로 적용.
        proportion_limit = [-abs(proportion_limit), abs(proportion_limit)]

    check_range(proportion_limit, -0.50, 0.50)

    self.proportion_limit = proportion_limit
    self.resampling = resampling
    self.border_mode = border_mode
    self.value = value
    self.mask_value = mask_value

proportion_limit instance-attribute

proportion_limit = proportion_limit

resampling instance-attribute

resampling = resampling

border_mode instance-attribute

border_mode = border_mode

value instance-attribute

value = value

mask_value instance-attribute

mask_value = mask_value

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_apply_params(self) -> ParamsType:
    return {
        "proportion_left": random.uniform(*self.proportion_limit),
        "proportion_right": random.uniform(*self.proportion_limit),
        "proportion_top": random.uniform(*self.proportion_limit),
        "proportion_bottom": random.uniform(*self.proportion_limit),
    }

apply_to_image

apply_to_image(image: ImageType, proportion_left: float, proportion_right: float, proportion_top: float, proportion_bottom: float, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(
    self,
    image: ImageType,
    proportion_left: float,
    proportion_right: float,
    proportion_top: float,
    proportion_bottom: float,
    **params,
) -> ImageType:
    return ratio_jitter(
        image=image,
        proportion_left=proportion_left,
        proportion_right=proportion_right,
        proportion_top=proportion_top,
        proportion_bottom=proportion_bottom,
        resampling=self.resampling,
        border_mode=self.border_mode,
        value=self.value,
    )

apply_to_mask

apply_to_mask(mask: MaskType, proportion_left: float, proportion_right: float, proportion_top: float, proportion_bottom: float, **params) -> MaskType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_mask(
    self,
    mask: MaskType,
    proportion_left: float,
    proportion_right: float,
    proportion_top: float,
    proportion_bottom: float,
    **params,
) -> MaskType:
    return ratio_jitter(
        image=mask,
        proportion_left=proportion_left,
        proportion_right=proportion_right,
        proportion_top=proportion_top,
        proportion_bottom=proportion_bottom,
        resampling="nearest",
        border_mode=self.border_mode,
        value=self.mask_value,
    )

apply_to_bboxes

apply_to_bboxes(bboxes: BBoxesType, image_size: Tuple[int], proportion_left: float, proportion_right: float, proportion_top: float, proportion_bottom: float, **params) -> BBoxesType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_bboxes(
    self,
    bboxes: BBoxesType,
    image_size: Tuple[int],
    proportion_left: float,
    proportion_right: float,
    proportion_top: float,
    proportion_bottom: float,
    **params,
) -> BBoxesType:
    return box_function.ratio_jitter(
        bboxes=bboxes,
        image_size=image_size,
        proportion_left=proportion_left,
        proportion_right=proportion_right,
        proportion_top=proportion_top,
        proportion_bottom=proportion_bottom,
    )

apply_to_polygons

apply_to_polygons(polygons: PolygonType, image_size: Tuple[int], proportion_left: float, proportion_right: float, proportion_top: float, proportion_bottom: float, **params) -> PolygonType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_polygons(
    self,
    polygons: PolygonType,
    image_size: Tuple[int],
    proportion_left: float,
    proportion_right: float,
    proportion_top: float,
    proportion_bottom: float,
    **params,
) -> PolygonType:
    return polygon_function.ratio_jitter(
        polygons=polygons,
        image_size=image_size,
        proportion_left=proportion_left,
        proportion_right=proportion_right,
        proportion_top=proportion_top,
        proportion_bottom=proportion_bottom,
    )

Zoom

Zoom(ratio_limit: Optional[List[float]] = None, resampling: str = 'bilinear', border_mode: int = cv2.BORDER_CONSTANT, value: Union[int, float, List[int], List[float]] = 0, mask_value: Union[int, float] = 0, **kwargs)

Bases: ImageSizeParams, ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(
    self,
    ratio_limit: Optional[List[float]] = None,
    resampling: str = "bilinear",
    border_mode: int = cv2.BORDER_CONSTANT,
    value: Union[int, float, List[int], List[float]] = 0,
    mask_value: Union[int, float] = 0,
    **kwargs,
) -> None:
    super().__init__(**kwargs)

    if ratio_limit is None:
        ratio_limit = [0.50, 2.00]

    check_range(ratio_limit, 0.01, 100.00)

    self.ratio_limit = ratio_limit
    self.resampling = resampling
    self.border_mode = border_mode
    self.value = value
    self.mask_value = mask_value

ratio_limit instance-attribute

ratio_limit = ratio_limit

resampling instance-attribute

resampling = resampling

border_mode instance-attribute

border_mode = border_mode

value instance-attribute

value = value

mask_value instance-attribute

mask_value = mask_value

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_apply_params(self) -> ParamsType:
    log_ratio = (math.log(self.ratio_limit[0]), math.log(self.ratio_limit[1]))
    return {
        "ratio": math.exp(random.uniform(*log_ratio)),
        "h_start": random.random(),
        "w_start": random.random(),
    }

apply_to_image

apply_to_image(image: ImageType, ratio: float, h_start: float, w_start: float, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(
    self,
    image: ImageType,
    ratio: float,
    h_start: float,
    w_start: float,
    **params,
) -> ImageType:
    return zoom(
        image=image,
        ratio=ratio,
        h_start=h_start,
        w_start=w_start,
        resampling=self.resampling,
        border_mode=self.border_mode,
        value=self.value,
    )

apply_to_mask

apply_to_mask(mask: MaskType, ratio: float, h_start: float, w_start: float, **params) -> MaskType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_mask(
    self,
    mask: MaskType,
    ratio: float,
    h_start: float,
    w_start: float,
    **params,
) -> MaskType:
    return zoom(
        image=mask,
        ratio=ratio,
        h_start=h_start,
        w_start=w_start,
        resampling="nearest",
        border_mode=self.border_mode,
        value=self.mask_value,
    )

apply_to_bboxes

apply_to_bboxes(bboxes: BBoxesType, image_size: Tuple[int], ratio: float, h_start: float, w_start: float, **params) -> BBoxesType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_bboxes(
    self,
    bboxes: BBoxesType,
    image_size: Tuple[int],
    ratio: float,
    h_start: float,
    w_start: float,
    **params,
) -> BBoxesType:
    return box_function.zoom(
        bboxes=bboxes,
        image_size=image_size,
        ratio=ratio,
        h_start=h_start,
        w_start=w_start,
    )

apply_to_polygons

apply_to_polygons(polygons: PolygonType, image_size: Tuple[int], ratio: float, h_start: float, w_start: float, **params) -> PolygonType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_polygons(
    self,
    polygons: PolygonType,
    image_size: Tuple[int],
    ratio: float,
    h_start: float,
    w_start: float,
    **params,
) -> PolygonType:
    return polygon_function.zoom(
        polygons=polygons,
        image_size=image_size,
        ratio=ratio,
        h_start=h_start,
        w_start=w_start,
    )

RandomResizedCrop

RandomResizedCrop(scale_limit: Optional[List[float]] = None, aspect_ratio_limit: Optional[List[float]] = None, resampling: str = 'bilinear', **kwargs)

Bases: ImageSizeParams, ImageTransform

Crop a random part of the input and rescale it to original size

Parameters:

  • scale_limit (Optional[List[float]], default: None ) –

    range of size of the origin size cropped. Defaults to [0.45, 1.00].

  • aspect_ratio_limit (Optional[List[float]], default: None ) –

    range of aspect ratio of the origin aspect ratio cropped. Defaults to [0.50, 2.00].

  • resampling (str, default: 'bilinear' ) –

    interpolation method. Defaults to "bilinear".

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(
    self,
    scale_limit: Optional[List[float]] = None,
    aspect_ratio_limit: Optional[List[float]] = None,
    resampling: str = "bilinear",
    **kwargs,
) -> None:
    """
    Args:
        scale_limit (Optional[List[float]], optional): range of size of the origin size cropped. Defaults to [0.45, 1.00].
        aspect_ratio_limit (Optional[List[float]], optional): range of aspect ratio of the origin aspect ratio cropped. Defaults to [0.50, 2.00].
        resampling (str, optional): interpolation method. Defaults to "bilinear".
    """
    super().__init__(**kwargs)

    if scale_limit is None:
        scale_limit = [0.45, 1.00]
    if aspect_ratio_limit is None:
        aspect_ratio_limit = [0.50, 2.00]

    check_range(scale_limit, 0.01, 1.00)
    check_range(aspect_ratio_limit, 0.10, 10.00)

    self.scale_limit = scale_limit
    self.aspect_ratio_limit = aspect_ratio_limit
    self.resampling = resampling

scale_limit instance-attribute

scale_limit = scale_limit

aspect_ratio_limit instance-attribute

aspect_ratio_limit = aspect_ratio_limit

resampling instance-attribute

resampling = resampling

targets property

targets: Dict[str, Callable]

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_apply_params(self) -> ParamsType:
    log_aspect_ratio = (math.log(self.aspect_ratio_limit[0]), math.log(self.aspect_ratio_limit[1]))
    w_scale, h_scale = 1.0, 1.0
    num_attempts = 10
    for _ in range(num_attempts):
        scale = random.uniform(*self.scale_limit)
        aspect_ratio = math.exp(random.uniform(*log_aspect_ratio))
        _w_scale = scale * math.sqrt(aspect_ratio)
        _h_scale = scale / math.sqrt(aspect_ratio)
        if _w_scale <= 1.0 and _h_scale <= 1.0:
            w_scale, h_scale = _w_scale, _h_scale
            break

    return {
        "w_scale": w_scale,
        "h_scale": h_scale,
        "h_start": random.random(),
        "w_start": random.random(),
    }

apply_to_image

apply_to_image(image: ImageType, h_scale: float, w_scale: float, h_start: float, w_start: float, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(
    self,
    image: ImageType,
    h_scale: float,
    w_scale: float,
    h_start: float,
    w_start: float,
    **params,
) -> ImageType:
    return random_resized_crop(
        image=image,
        h_scale=h_scale,
        w_scale=w_scale,
        h_start=h_start,
        w_start=w_start,
        resampling=self.resampling,
    )

apply_to_mask

apply_to_mask(mask: MaskType, h_scale: float, w_scale: float, h_start: float, w_start: float, **params) -> MaskType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_mask(
    self,
    mask: MaskType,
    h_scale: float,
    w_scale: float,
    h_start: float,
    w_start: float,
    **params,
) -> MaskType:
    return random_resized_crop(
        image=mask,
        h_scale=h_scale,
        w_scale=w_scale,
        h_start=h_start,
        w_start=w_start,
        resampling="nearest",
    )

apply_to_bboxes

apply_to_bboxes(bboxes: BBoxesType, **params) -> BBoxesType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_bboxes(self, bboxes: BBoxesType, **params) -> BBoxesType:
    raise NotImplementedError

apply_to_polygons

apply_to_polygons(polygons: PolygonType, **params) -> PolygonType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_polygons(self, polygons: PolygonType, **params) -> PolygonType:
    raise NotImplementedError

RandomResizedCropAndPad

RandomResizedCropAndPad(scale_limit: Optional[List[float]] = None, aspect_ratio_limit: Optional[List[float]] = None, height: Optional[int] = None, width: Optional[int] = None, resampling: str = 'bilinear', border_mode: int = cv2.BORDER_CONSTANT, value: Union[int, float, List[int], List[float]] = 0, mask_value: Union[int, float] = 0, **kwargs)

Bases: ImageSizeParams, ImageTransform

pad, crop and resize to original image size

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(
    self,
    scale_limit: Optional[List[float]] = None,
    aspect_ratio_limit: Optional[List[float]] = None,
    height: Optional[int] = None,
    width: Optional[int] = None,
    resampling: str = "bilinear",
    border_mode: int = cv2.BORDER_CONSTANT,
    value: Union[int, float, List[int], List[float]] = 0,
    mask_value: Union[int, float] = 0,
    **kwargs,
) -> None:
    super().__init__(**kwargs)

    if scale_limit is None:
        scale_limit = [0.45, 1.00]
    if aspect_ratio_limit is None:
        aspect_ratio_limit = [0.50, 2.00]

    check_range(scale_limit, 0.01, 1.00)
    check_range(aspect_ratio_limit, 0.10, 10.00)

    self.height = height
    self.width = width
    self.scale_limit = scale_limit
    self.aspect_ratio_limit = aspect_ratio_limit
    self.resampling = resampling
    self.border_mode = border_mode
    self.value = value
    self.mask_value = mask_value

height instance-attribute

height = height

width instance-attribute

width = width

scale_limit instance-attribute

scale_limit = scale_limit

aspect_ratio_limit instance-attribute

aspect_ratio_limit = aspect_ratio_limit

resampling instance-attribute

resampling = resampling

border_mode instance-attribute

border_mode = border_mode

value instance-attribute

value = value

mask_value instance-attribute

mask_value = mask_value

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_apply_params(self) -> ParamsType:
    log_aspect_ratio = (math.log(self.aspect_ratio_limit[0]), math.log(self.aspect_ratio_limit[1]))
    return {
        "scale": random.uniform(*self.scale_limit),
        "aspect_ratio": math.exp(random.uniform(*log_aspect_ratio)),
        "h_start": random.random(),
        "w_start": random.random(),
    }

apply_to_image

apply_to_image(image: ImageType, scale: float, aspect_ratio: float, h_start: float, w_start: float, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(
    self,
    image: ImageType,
    scale: float,
    aspect_ratio: float,
    h_start: float,
    w_start: float,
    **params,
) -> ImageType:
    return random_resized_crop_and_pad(
        image=image,
        scale=scale,
        aspect_ratio=aspect_ratio,
        h_start=h_start,
        w_start=w_start,
        height=self.height,
        width=self.width,
        resampling=self.resampling,
        border_mode=self.border_mode,
        value=self.value,
    )

apply_to_mask

apply_to_mask(mask: MaskType, scale: float, aspect_ratio: float, h_start: float, w_start: float, **params) -> MaskType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_mask(
    self,
    mask: MaskType,
    scale: float,
    aspect_ratio: float,
    h_start: float,
    w_start: float,
    **params,
) -> MaskType:
    return random_resized_crop_and_pad(
        image=mask,
        scale=scale,
        aspect_ratio=aspect_ratio,
        h_start=h_start,
        w_start=w_start,
        height=self.height,
        width=self.width,
        resampling="nearest",
        border_mode=self.border_mode,
        value=self.mask_value,
    )

apply_to_bboxes

apply_to_bboxes(bboxes: BBoxesType, image_size: Tuple[int], scale: float, aspect_ratio: float, h_start: float, w_start: float, **params) -> BBoxesType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_bboxes(
    self,
    bboxes: BBoxesType,
    image_size: Tuple[int],
    scale: float,
    aspect_ratio: float,
    h_start: float,
    w_start: float,
    **params,
) -> BBoxesType:
    return box_function.random_resized_crop_and_pad(
        bboxes=bboxes,
        image_size=image_size,
        scale=scale,
        aspect_ratio=aspect_ratio,
        h_start=h_start,
        w_start=w_start,
        height=self.height,
        width=self.width,
    )

apply_to_polygons

apply_to_polygons(polygons: PolygonType, image_size: Tuple[int], scale: float, aspect_ratio: float, h_start: float, w_start: float, **params) -> PolygonType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_polygons(
    self,
    polygons: PolygonType,
    image_size: Tuple[int],
    scale: float,
    aspect_ratio: float,
    h_start: float,
    w_start: float,
    **params,
) -> PolygonType:
    return polygon_function.random_resized_crop_and_pad(
        polygons=polygons,
        image_size=image_size,
        scale=scale,
        aspect_ratio=aspect_ratio,
        h_start=h_start,
        w_start=w_start,
    )

LightReflect

LightReflect(radius_limit: Optional[List[float]] = None, **kwargs)

Bases: ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(self, radius_limit: Optional[List[float]] = None, **kwargs) -> None:
    super().__init__(**kwargs)

    if radius_limit is None:
        radius_limit = [0.10, 0.50]

    check_range(radius_limit, 0.00, 1.00)

    self.radius_limit = radius_limit

radius_limit instance-attribute

radius_limit = radius_limit

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_apply_params(self) -> ParamsType:
    return {
        "xc": random.random(),
        "yc": random.random(),
        "x_radius": random.uniform(*self.radius_limit),
        "y_radius": random.uniform(*self.radius_limit),
        "angle": random.uniform(0.00, 360.00),
    }

apply_to_image

apply_to_image(image: ImageType, xc: float, yc: float, x_radius: float, y_radius: float, angle: float, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(
    self,
    image: ImageType,
    xc: float,
    yc: float,
    x_radius: float,
    y_radius: float,
    angle: float,
    **params,
) -> ImageType:
    return light_reflect(
        image=image, xc=xc, yc=yc, x_radius=x_radius, y_radius=y_radius, angle=angle
    )

PerspectiveTransform

PerspectiveTransform(intensity_limit: Optional[List[float]] = None, **kwargs)

Bases: ImageSizeParams, ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(
    self,
    intensity_limit: Optional[List[float]] = None,
    **kwargs,
) -> None:
    super().__init__(**kwargs)

    if intensity_limit is None:
        intensity_limit = [0, 30]

    check_range(intensity_limit, 0, 49)

    self.intensity_limit = intensity_limit

intensity_limit instance-attribute

intensity_limit = intensity_limit

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_apply_params(self) -> ParamsType:
    intensity = random.uniform(*self.intensity_limit)
    return {
        "offset_top_left": tuple((random.uniform(0, intensity), random.uniform(0, intensity))),
        "offset_top_right": tuple((random.uniform(0, intensity), random.uniform(0, intensity))),
        "offset_bottom_right": tuple((random.uniform(0, intensity), random.uniform(0, intensity))),
        "offset_bottom_left": tuple((random.uniform(0, intensity), random.uniform(0, intensity))),
    }

apply_to_image

apply_to_image(image: ImageType, offset_top_left: OffsetType, offset_top_right: OffsetType, offset_bottom_right: OffsetType, offset_bottom_left: OffsetType, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(
    self,
    image: ImageType,
    offset_top_left: OffsetType,
    offset_top_right: OffsetType,
    offset_bottom_right: OffsetType,
    offset_bottom_left: OffsetType,
    **params,
) -> ImageType:
    return perspective_transform(
        image=image,
        offset_top_left=offset_top_left,
        offset_top_right=offset_top_right,
        offset_bottom_right=offset_bottom_right,
        offset_bottom_left=offset_bottom_left,
        interpolate_method="linear",
    )

apply_to_mask

apply_to_mask(mask: MaskType, offset_top_left: OffsetType, offset_top_right: OffsetType, offset_bottom_right: OffsetType, offset_bottom_left: OffsetType, **params) -> MaskType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_mask(
    self,
    mask: MaskType,
    offset_top_left: OffsetType,
    offset_top_right: OffsetType,
    offset_bottom_right: OffsetType,
    offset_bottom_left: OffsetType,
    **params,
) -> MaskType:
    return perspective_transform(
        image=mask,
        offset_top_left=offset_top_left,
        offset_top_right=offset_top_right,
        offset_bottom_right=offset_bottom_right,
        offset_bottom_left=offset_bottom_left,
        interpolate_method="nearest",
    )

apply_to_bboxes

apply_to_bboxes(bboxes: BBoxesType, image_size: Tuple[int], offset_top_left: OffsetType, offset_top_right: OffsetType, offset_bottom_right: OffsetType, offset_bottom_left: OffsetType, **params) -> BBoxesType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_bboxes(
    self,
    bboxes: BBoxesType,
    image_size: Tuple[int],
    offset_top_left: OffsetType,
    offset_top_right: OffsetType,
    offset_bottom_right: OffsetType,
    offset_bottom_left: OffsetType,
    **params,
) -> BBoxesType:
    return box_function.perspective_transform(
        bboxes=bboxes,
        image_size=image_size,
        offset_top_left=offset_top_left,
        offset_top_right=offset_top_right,
        offset_bottom_right=offset_bottom_right,
        offset_bottom_left=offset_bottom_left,
    )

apply_to_polygons

apply_to_polygons(polygons: PolygonType, image_size: Tuple[int], offset_top_left: OffsetType, offset_top_right: OffsetType, offset_bottom_right: OffsetType, offset_bottom_left: OffsetType, **params) -> PolygonType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_polygons(
    self,
    polygons: PolygonType,
    image_size: Tuple[int],
    offset_top_left: OffsetType,
    offset_top_right: OffsetType,
    offset_bottom_right: OffsetType,
    offset_bottom_left: OffsetType,
    **params,
) -> PolygonType:
    return polygon_function.perspective_transform(
        polygons=polygons,
        image_size=image_size,
        offset_top_left=offset_top_left,
        offset_top_right=offset_top_right,
        offset_bottom_right=offset_bottom_right,
        offset_bottom_left=offset_bottom_left,
    )

RandomErasing

RandomErasing(scale: Tuple[float, float] = (0.02, 0.33), ratio: Tuple[float, float] = (0.2, 3.3), value: Union[int, Tuple[int, int, int], str] = 0, randomly_select_values: bool = False, **kwargs)

Bases: ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(
    self,
    scale: Tuple[float, float] = (0.02, 0.33),
    ratio: Tuple[float, float] = (0.2, 3.3),
    value: Union[int, Tuple[int, int, int], str] = 0,
    randomly_select_values: bool = False,
    **kwargs,
) -> None:
    super().__init__(**kwargs)
    self.scale = scale
    self.ratio = ratio
    self._value = value
    self.randomly_select_values = randomly_select_values

scale instance-attribute

scale = scale

ratio instance-attribute

ratio = ratio

_value instance-attribute

_value = value

randomly_select_values instance-attribute

randomly_select_values = randomly_select_values

_get_random_erase_params

_get_random_erase_params()

This is modified version of get_params of random erasing see: https://pytorch.org/vision/main/_modules/torchvision/transforms/transforms.html#RandomErasing.forward

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def _get_random_erase_params(self):
    """
    This is modified version of get_params of random erasing
    see: https://pytorch.org/vision/main/_modules/torchvision/transforms/transforms.html#RandomErasing.forward
    """
    area = 1

    log_ratio = torch.log(torch.tensor(self.ratio))
    for _ in range(10):
        erase_area = area * torch.empty(1).uniform_(self.scale[0], self.scale[1]).item()
        aspect_ratio = torch.exp(torch.empty(1).uniform_(log_ratio[0], log_ratio[1])).item()

        h_in_ratio = math.sqrt(erase_area * aspect_ratio)
        w_in_ratio = math.sqrt(erase_area / aspect_ratio)

        if not (h_in_ratio < 1 and w_in_ratio < 1):
            continue

        x_in_ratio = random.uniform(0, 1 - w_in_ratio)
        y_in_ratio = random.uniform(0, 1 - h_in_ratio)

        return x_in_ratio, y_in_ratio, h_in_ratio, w_in_ratio

    # Return Original Image
    return 0, 0, 1.0, 1.0

get_apply_params

get_apply_params() -> ParamsType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def get_apply_params(self) -> ParamsType:
    value = self._value
    if self.randomly_select_values:
        value_options = {
            "erase": 0,
            "rgb": (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)),
            "random": "random",
        }
        value = value_options[random.choice(list(value_options.keys()))]

    x_in_ratio, y_in_ratio, h_in_ratio, w_in_ratio = self._get_random_erase_params()

    return dict(
        x_in_ratio=x_in_ratio,
        y_in_ratio=y_in_ratio,
        h_in_ratio=h_in_ratio,
        w_in_ratio=w_in_ratio,
        value=value,
    )

apply_to_image

apply_to_image(image: ImageType, x_in_ratio: float, y_in_ratio: float, h_in_ratio: float, w_in_ratio: float, value: Union[int, Tuple[int, int, int], str], **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(
    self,
    image: ImageType,
    x_in_ratio: float,
    y_in_ratio: float,
    h_in_ratio: float,
    w_in_ratio: float,
    value: Union[int, Tuple[int, int, int], str],
    **params,
) -> ImageType:
    is_gray = image.ndim == 2
    if is_gray:
        img_height, img_width = image.shape
    else:
        img_height, img_width, _ = image.shape

    x = int(min(x_in_ratio * img_width, img_width))
    y = int(min(y_in_ratio * img_height, img_height))
    h = int(min(h_in_ratio * img_height, img_height))
    w = int(min(w_in_ratio * img_width, img_width))

    # cast value to script acceptable type
    if isinstance(value, (int, float)):
        value = np.array([float(value)]).astype("uint8")[None, None, :]
    elif isinstance(value, str):
        value = (np.random.normal(size=(h, w, 3)) * 255).astype("uint8")
    elif isinstance(value, (list, tuple)):
        value = np.array([float(v) for v in value]).astype("uint8")[None, None, :]

    return erase(image=image, x=x, y=y, w=w, h=h, v=value)

Grayscale

Grayscale(**kwargs)

Bases: ImageTransform

Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def __init__(self, **kwargs) -> None:
    super().__init__(**kwargs)

apply_to_image

apply_to_image(image: ImageType, **params) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_transform.py
def apply_to_image(self, image: ImageType, **params) -> ImageType:
    return grayscale(image=image)

to_numpy

to_numpy(image: Union[Image, Tensor, ndarray], copy: bool = False) -> ndarray
Source code in SaigeToolkit/data/transform/image_function.py
def to_numpy(image: Union[Image.Image, torch.Tensor, np.ndarray], copy: bool = False) -> np.ndarray:
    if isinstance(image, Image.Image):
        image = np.array(image)  # Image.Image -> np.ndarray
    elif isinstance(image, torch.Tensor):
        assert image.ndim in [3, 4]  # BCHW / CHW

        if image.ndim == 4:  # if BCHW
            assert image.shape[0] == 1  # Batch size must be 1
            image = image.squeeze(0)  # BCHW -> CHW

        image = image.permute(1, 2, 0)  # CHW -> HWC

        if image.shape[2] == 1:  # if gray image
            image = image.squeeze(2)  # HWC -> HW

        image = image.detach().cpu().numpy()  # torch.Tensor, HW(C) -> np.ndarray, HW(C)
    elif isinstance(image, np.ndarray):
        if copy:
            image = image.copy()
    else:
        raise NotImplementedError

    # gray: HW / rgb & rgba: HWC
    return image

to_pil

to_pil(image: Union[Image, Tensor, ndarray], copy: bool = False) -> Image
Source code in SaigeToolkit/data/transform/image_function.py
def to_pil(image: Union[Image.Image, torch.Tensor, np.ndarray], copy: bool = False) -> Image.Image:
    if isinstance(image, Image.Image):
        if copy:
            image = image.copy()
    elif isinstance(image, torch.Tensor):
        image = to_numpy(image)  # torch.Tensor -> np.ndarray
        image = Image.fromarray(image)  # np.ndarray -> Image.Image
    elif isinstance(image, np.ndarray):
        assert image.ndim in [2, 3]  # HW / HWC

        if image.ndim == 3 and image.shape[2] == 1:  # grayscale shape HW1
            image = np.squeeze(image, axis=2)  # HW1 -> HW

        image = Image.fromarray(image)  # np.ndarray -> Image.Image
    else:
        raise NotImplementedError

    return image

read_image_size

read_image_size(image: Union[Image, Tensor, ndarray]) -> ImageSizeType

image size: (W, H)

Source code in SaigeToolkit/data/transform/image_function.py
def read_image_size(image: Union[Image.Image, torch.Tensor, np.ndarray]) -> ImageSizeType:
    """image size: (W, H)"""
    if isinstance(image, Image.Image):
        return image.size
    elif isinstance(image, torch.Tensor) and image.ndim in (2, 3, 4):  # HW, CHW, BCHW
        return (image.shape[-1], image.shape[-2])
    elif isinstance(image, np.ndarray) and image.ndim in (2, 3):  # HW, HWC
        return (image.shape[1], image.shape[0])
    else:
        raise NotImplementedError

vertical_flip

vertical_flip(image: Union[ImageType, MaskType]) -> Union[ImageType, MaskType]
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
def vertical_flip(image: Union[ImageType, MaskType]) -> Union[ImageType, MaskType]:
    return AF.vflip(image)

horizontal_flip

horizontal_flip(image: Union[ImageType, MaskType]) -> Union[ImageType, MaskType]
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
def horizontal_flip(image: Union[ImageType, MaskType]) -> Union[ImageType, MaskType]:
    if image.ndim == 3 and image.shape[2] > 1 and image.dtype == np.uint8:
        # Opencv is faster than numpy only in case of
        # non-gray scale 8bits images
        return AF.hflip_cv2(image)

    return AF.hflip(image)

rotate

rotate(image: Union[ImageType, MaskType], angle: float = 0, interpolation: int = cv2.INTER_LINEAR, border_mode: int = cv2.BORDER_REFLECT_101, value: Union[int, float, List[int], List[float]] = 0, crop_border: bool = False) -> Union[ImageType, MaskType]
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
def rotate(
    image: Union[ImageType, MaskType],
    angle: float = 0,
    interpolation: int = cv2.INTER_LINEAR,
    border_mode: int = cv2.BORDER_REFLECT_101,
    value: Union[int, float, List[int], List[float]] = 0,
    crop_border: bool = False,
) -> Union[ImageType, MaskType]:
    def _rotated_rect_with_max_area(h, w, angle):
        """
        Given a rectangle of size wxh that has been rotated by 'angle' (in
        degrees), computes the width and height of the largest possible
        axis-aligned rectangle (maximal area) within the rotated rectangle.

        Code from: https://stackoverflow.com/questions/16702966/rotate-image-and-crop-out-black-borders
        """

        angle = math.radians(angle)
        width_is_longer = w >= h
        side_long, side_short = (w, h) if width_is_longer else (h, w)

        # since the solutions for angle, -angle and 180-angle are all the same,
        # it is sufficient to look at the first quadrant and the absolute values of sin,cos:
        sin_a, cos_a = abs(math.sin(angle)), abs(math.cos(angle))
        if side_short <= 2.0 * sin_a * cos_a * side_long or abs(sin_a - cos_a) < 1e-10:
            # half constrained case: two crop corners touch the longer side,
            # the other two corners are on the mid-line parallel to the longer line
            x = 0.5 * side_short
            wr, hr = (x / sin_a, x / cos_a) if width_is_longer else (x / cos_a, x / sin_a)
        else:
            # fully constrained case: crop touches all 4 sides
            cos_2a = cos_a * cos_a - sin_a * sin_a
            wr, hr = (w * cos_a - h * sin_a) / cos_2a, (h * cos_a - w * sin_a) / cos_2a

        return dict(
            x_min=max(0, int(w / 2 - wr / 2)),
            x_max=min(w, int(w / 2 + wr / 2)),
            y_min=max(0, int(h / 2 - hr / 2)),
            y_max=min(h, int(h / 2 + hr / 2)),
        )

    check_value(angle, -360.0, 360.0)

    img_out = AFGeometric.rotate(image, angle, interpolation, border_mode, value)
    if crop_border:
        h, w = image.shape[:2]
        crop_bbox_dict = _rotated_rect_with_max_area(h, w, angle)
        x_min = crop_bbox_dict["x_min"]
        y_min = crop_bbox_dict["y_min"]
        x_max = crop_bbox_dict["x_max"]
        y_max = crop_bbox_dict["y_max"]
        img_out = AFCrops.crop(img_out, x_min, y_min, x_max, y_max)
    return img_out

random_rotate90

random_rotate90(image: Union[ImageType, MaskType], factor: int = 0) -> Union[ImageType, MaskType]
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
def random_rotate90(
    image: Union[ImageType, MaskType],
    factor: int = 0,
) -> Union[ImageType, MaskType]:
    check_value(factor, 0, 3)
    return AF.rot90(img=image, factor=factor)

color_jitter

color_jitter(image: ImageType, brightness: float = 1.0, contrast: float = 1.0, saturation: float = 1.0, hue: float = 0, order: List[int] = [0, 1, 2, 3]) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
@support_rgba
def color_jitter(
    image: ImageType,
    brightness: float = 1.0,
    contrast: float = 1.0,
    saturation: float = 1.0,
    hue: float = 0,
    order: List[int] = [0, 1, 2, 3],
) -> ImageType:
    if not AF.is_rgb_image(image) and not AF.is_grayscale_image(image):
        raise TypeError("ColorJitter transformation expects 1-channel or 3-channel images.")

    check_value(brightness, 0.01, 10.00)
    check_value(contrast, 0.01, 10.00)
    check_value(saturation, 0.01, 10.00)
    check_value(hue, -0.50, 0.50)

    transforms = [
        AF.adjust_brightness_torchvision,
        AF.adjust_contrast_torchvision,
        AF.adjust_saturation_torchvision,
        AF.adjust_hue_torchvision,
    ]
    params = [brightness, contrast, saturation, hue]

    for i in order:
        image = transforms[i](image, params[i])
    return image

blur

blur(image: ImageType, ksize: int = 3) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
def blur(image: ImageType, ksize: int = 3) -> ImageType:
    check_value(ksize, 1, 100)

    return AF.blur(image, ksize)

gaussian_blur

gaussian_blur(image: ImageType, ksize: int = 3, sigma: float = 0.0) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
def gaussian_blur(image: ImageType, ksize: int = 3, sigma: float = 0.0) -> ImageType:
    check_value(ksize, 1, 100)
    check_value(sigma, 0.00, 100.00)

    if ksize % 2 != 1:
        ksize = ksize + 1

    return AF.gaussian_blur(image, ksize, sigma)

adjust_brightness

adjust_brightness(image: ImageType, brightness: float = 0.0, brightness_by_max: bool = True) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
def adjust_brightness(
    image: ImageType, brightness: float = 0.0, brightness_by_max: bool = True
) -> ImageType:
    check_value(brightness, -1.00, 1.00)

    alpha = 1.0
    beta = 0.0 + brightness

    return AF.brightness_contrast_adjust(image, alpha, beta, brightness_by_max)

adjust_contrast

adjust_contrast(image: ImageType, contrast: float = 0.0) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
def adjust_contrast(image: ImageType, contrast: float = 0.0) -> ImageType:
    check_value(contrast, -1.00, 1.00)

    alpha = 1.0 + contrast
    beta = 0.0

    return AF.brightness_contrast_adjust(image, alpha, beta)

adjust_hue

adjust_hue(image: ImageType, hue: float = 0.0) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
@support_gray
@support_rgba
def adjust_hue(image: ImageType, hue: float = 0.0) -> ImageType:
    check_value(hue, -1.00, 1.00)

    hue_shift = int(hue * 180)
    sat_shift = 0
    val_shift = 0

    return AF.shift_hsv(image, hue_shift, sat_shift, val_shift)

adjust_saturation

adjust_saturation(image: ImageType, saturation: float = 0.0) -> ImageType

adjust_saturation

Parameters:

  • image (ImageType) –

    입력 이미지

  • saturation (float, default: 0.0 ) –

    변형 강도, [-1.0, 1.0] 범위, Defaults to 0.0.

Returns:

  • ImageType ( ImageType ) –

    결과 이미지

Note

Ablumentation의 AF.shift_hsv()와 다른 알고리즘을 사용합니다. AF.shift_hsv()의 경우 색이 없는 픽셀을 붉은 색으로 변형합니다. 이 함수의 경우 색이 없는 픽셀은 변형하지 않습니다.

Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
@support_gray
@support_rgba
def adjust_saturation(image: ImageType, saturation: float = 0.0) -> ImageType:
    """adjust_saturation

    Args:
        image (ImageType): 입력 이미지
        saturation (float, optional): 변형 강도, [-1.0, 1.0] 범위, Defaults to 0.0.

    Returns:
        ImageType: 결과 이미지

    Note:
        Ablumentation의 AF.shift_hsv()와 다른 알고리즘을 사용합니다.
        AF.shift_hsv()의 경우 색이 없는 픽셀을 붉은 색으로 변형합니다.
        이 함수의 경우 색이 없는 픽셀은 변형하지 않습니다.

    """
    check_value(saturation, -1.00, 1.00)
    saturation = (saturation + 1) ** 2
    gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
    result = image * saturation + gray[..., None] * (1 - saturation)

    dtype = image.dtype
    if dtype == np.uint8:
        result = np.clip(result, 0, 255)
    elif dtype == np.uint16:
        result = np.clip(result, 0, 65535)
    result = result.astype(dtype)

    return result

adjust_gamma

adjust_gamma(image: ImageType, gamma: float = 0.0) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
def adjust_gamma(image: ImageType, gamma: float = 0.0) -> ImageType:
    check_value(gamma, -1.0, 1.0)

    gamma = gamma + 1

    return AF.gamma_transform(image, gamma=gamma)

adjust_brightness_contrast

adjust_brightness_contrast(image: ImageType, brightness: float = 0.0, contrast: float = 0.0, brightness_by_max: bool = True) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
def adjust_brightness_contrast(
    image: ImageType, brightness: float = 0.0, contrast: float = 0.0, brightness_by_max: bool = True
) -> ImageType:
    check_value(brightness, -1.00, 1.00)
    check_value(contrast, -1.00, 1.00)

    alpha = 1.0 + contrast
    beta = 0.0 + brightness

    return AF.brightness_contrast_adjust(image, alpha, beta, brightness_by_max)

iso_noise

iso_noise(image: ImageType, color_shift: float = 0.05, intensity: float = 0.5, random_state: Optional[int] = None) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
@support_gray
@support_rgba
def iso_noise(
    image: ImageType,
    color_shift: float = 0.05,
    intensity: float = 0.50,
    random_state: Optional[int] = None,
) -> ImageType:
    check_value(color_shift, 0.00, 1.00)
    check_value(intensity, 0.00, 2.00)

    return AF.iso_noise(image, color_shift, intensity, np.random.RandomState(random_state))

image_compression

image_compression(image: ImageType, quality: int = 100, image_type: str = '.jpeg') -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
@support_gray
@support_rgba
def image_compression(
    image: ImageType,
    quality: int = 100,
    image_type: str = ".jpeg",
) -> ImageType:
    return AF.image_compression(image, quality, image_type)

sharpen

sharpen(image: ImageType, sharpening_matrix: ndarray) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
@support_gray
@support_rgba
def sharpen(
    image: ImageType,
    sharpening_matrix: np.ndarray,
) -> ImageType:
    return AF.convolve(image, sharpening_matrix)

multiplicative_noise

multiplicative_noise(image: ImageType, multiplier: ndarray) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
@support_gray
@support_rgba
def multiplicative_noise(
    image: ImageType,
    multiplier: np.ndarray,
) -> ImageType:
    return AF.multiply(image, multiplier)

ratio_jitter

ratio_jitter(image: ImageType, proportion_left: float = 0.0, proportion_right: float = 0.0, proportion_top: float = 0.0, proportion_bottom: float = 0.0, resampling: str = 'bilinear', border_mode: int = cv2.BORDER_CONSTANT, value: Union[int, float, List[int], List[float]] = 0) -> Union[ImageType, MaskType]
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
def ratio_jitter(
    image: ImageType,
    proportion_left: float = 0.0,
    proportion_right: float = 0.0,
    proportion_top: float = 0.0,
    proportion_bottom: float = 0.0,
    resampling: str = "bilinear",
    border_mode: int = cv2.BORDER_CONSTANT,
    value: Union[int, float, List[int], List[float]] = 0,
) -> Union[ImageType, MaskType]:
    check_value(proportion_left, -0.50, 0.50)
    check_value(proportion_right, -0.50, 0.50)
    check_value(proportion_top, -0.50, 0.50)
    check_value(proportion_bottom, -0.50, 0.50)

    h_original, w_original = image.shape[:2]

    left = int(w_original * proportion_left)
    right = int(w_original * proportion_right)
    top = int(h_original * proportion_top)
    bottom = int(h_original * proportion_bottom)

    # crop
    crop_left = left if left > 0 else 0
    crop_right = right if right > 0 else 0
    crop_top = top if top > 0 else 0
    crop_bottom = bottom if bottom > 0 else 0

    crop_w = max(w_original - crop_left - crop_right, 1)
    crop_h = max(h_original - crop_top - crop_bottom, 1)

    image = image[crop_top : crop_top + crop_h, crop_left : crop_left + crop_w]

    # padding
    pad_left = 0 if left > 0 else -left
    pad_right = 0 if right > 0 else -right
    pad_top = 0 if top > 0 else -top
    pad_bottom = 0 if bottom > 0 else -bottom

    image = cv2.copyMakeBorder(
        image,
        top=pad_top,
        bottom=pad_bottom,
        left=pad_left,
        right=pad_right,
        borderType=border_mode,
        value=value,
    )

    # resize
    target_size = (w_original, h_original)
    image = resize_image(image, target_size, resampling)

    return image

zoom

zoom(image: ImageType, ratio: float = 1.0, h_start: float = 0.0, w_start: float = 0.0, resampling: str = 'bilinear', border_mode: int = cv2.BORDER_CONSTANT, value: Union[int, float, List[int], List[float]] = 0) -> Union[ImageType, MaskType]
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
def zoom(
    image: ImageType,
    ratio: float = 1.0,
    h_start: float = 0.0,
    w_start: float = 0.0,
    resampling: str = "bilinear",
    border_mode: int = cv2.BORDER_CONSTANT,
    value: Union[int, float, List[int], List[float]] = 0,
) -> Union[ImageType, MaskType]:
    check_value(ratio, 0.01, 100.00)
    check_value(h_start, 0.00, 1.00)
    check_value(w_start, 0.00, 1.00)

    if ratio < 1.0:
        output_image = _zoom_out(
            image=image,
            ratio=ratio,
            h_start=h_start,
            w_start=w_start,
            resampling=resampling,
            border_mode=border_mode,
            value=value,
        )
    elif ratio == 1.0:
        output_image = image
    elif ratio > 1.0:
        output_image = _zoom_in(
            image=image,
            ratio=ratio,
            h_start=h_start,
            w_start=w_start,
            resampling=resampling,
        )
    else:
        raise NotImplementedError

    return output_image

random_resized_crop

random_resized_crop(image: ImageType, h_scale: float = 1.0, w_scale: float = 1.0, h_start: float = 0.0, w_start: float = 0.0, resampling: str = 'bilinear') -> Union[ImageType, MaskType]

Crop the given image to given scale and then resize it to original size.

Parameters:

  • image (ImageType) –

    original image

  • h_scale (float, default: 1.0 ) –

    crop height scale. Defaults to 1.0.

  • w_scale (float, default: 1.0 ) –

    crop width scale. Defaults to 1.0.

  • h_start (float, default: 0.0 ) –

    crop height start ratio. Defaults to 0.0.

  • w_start (float, default: 0.0 ) –

    crop width start ratio. Defaults to 0.0.

  • resampling (str, default: 'bilinear' ) –

    interpolation method. Defaults to "bilinear".

Returns:

Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
def random_resized_crop(
    image: ImageType,
    h_scale: float = 1.0,
    w_scale: float = 1.0,
    h_start: float = 0.0,
    w_start: float = 0.0,
    resampling: str = "bilinear",
) -> Union[ImageType, MaskType]:
    """Crop the given image to given scale and then resize it to original size.

    Args:
        image (ImageType): original image
        h_scale (float, optional): crop height scale. Defaults to 1.0.
        w_scale (float, optional): crop width scale. Defaults to 1.0.
        h_start (float, optional): crop height start ratio. Defaults to 0.0.
        w_start (float, optional): crop width start ratio. Defaults to 0.0.
        resampling (str, optional): interpolation method. Defaults to "bilinear".

    Returns:
        Union[ImageType, MaskType]: augmented data
    """
    check_value(h_scale, 0.01, 1.00)
    check_value(w_scale, 0.01, 1.00)
    check_value(h_start, 0.00, 1.00)
    check_value(w_start, 0.00, 1.00)

    h_original, w_original = image.shape[:2]
    target_height = int(round(h_original * h_scale))
    target_width = int(round(w_original * w_scale))

    # crop
    image = AFCrops.random_crop(
        img=image,
        crop_height=target_height,
        crop_width=target_width,
        h_start=min(h_start, 1.0 - 1e-5),
        w_start=min(w_start, 1.0 - 1e-5),
    )

    # resize
    target_size = (w_original, h_original)
    image = resize_image(image, target_size, resampling)

    return image

random_resized_crop_and_pad

random_resized_crop_and_pad(image: ImageType, scale: float = 1.0, aspect_ratio: float = 1.0, h_start: float = 0.0, w_start: float = 0.0, height: Optional[int] = None, width: Optional[int] = None, resampling: str = 'bilinear', border_mode: int = cv2.BORDER_CONSTANT, value: Union[int, float, List[int], List[float]] = 0) -> Union[ImageType, MaskType]
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
def random_resized_crop_and_pad(
    image: ImageType,
    scale: float = 1.0,
    aspect_ratio: float = 1.0,
    h_start: float = 0.0,
    w_start: float = 0.0,
    height: Optional[int] = None,
    width: Optional[int] = None,
    resampling: str = "bilinear",
    border_mode: int = cv2.BORDER_CONSTANT,
    value: Union[int, float, List[int], List[float]] = 0,
) -> Union[ImageType, MaskType]:
    check_value(scale, 0.01, 1.00)
    check_value(aspect_ratio, 0.10, 10.00)
    check_value(h_start, 0.00, 1.00)
    check_value(w_start, 0.00, 1.00)

    h_original, w_original = image.shape[:2]
    area = h_original * w_original
    target_area = scale * area

    crop_height = int(round(math.sqrt(target_area / aspect_ratio)))
    crop_width = int(round(math.sqrt(target_area * aspect_ratio)))

    # pad
    pad_top = max(crop_height - h_original, 0)
    pad_bottom = max(crop_height - h_original, 0)
    pad_left = max(crop_width - w_original, 0)
    pad_right = max(crop_width - w_original, 0)

    image = cv2.copyMakeBorder(
        image,
        top=pad_top,
        bottom=pad_bottom,
        left=pad_left,
        right=pad_right,
        borderType=border_mode,
        value=value,
    )

    # crop
    image = AFCrops.random_crop(
        img=image,
        crop_height=crop_height,
        crop_width=crop_width,
        h_start=min(h_start, 1.0 - 1e-5),
        w_start=min(w_start, 1.0 - 1e-5),
    )

    # resize
    target_size = (width or w_original, height or h_original)
    image = resize_image(image, target_size, resampling)

    return image

light_reflect

light_reflect(image: ImageType, xc: float, yc: float, x_radius: float, y_radius: float, angle: float) -> ImageType
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
@support_gray
def light_reflect(
    image: ImageType, xc: float, yc: float, x_radius: float, y_radius: float, angle: float
) -> ImageType:
    check_value(xc, 0.00, 1.00)
    check_value(yc, 0.00, 1.00)
    check_value(x_radius, 0.00, 1.00)
    check_value(y_radius, 0.00, 1.00)
    check_value(angle, 0.00, 360.00)

    if x_radius == 0 or y_radius == 0:
        return image

    image = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)

    h_original, w_original = image.shape[:2]

    xc = ratio_to_value(xc, 0, w_original)
    yc = ratio_to_value(yc, 0, h_original)
    x_radius = ratio_to_value(x_radius, 0, w_original)
    y_radius = ratio_to_value(y_radius, 0, h_original)
    angle = math.radians(angle)

    c, r = np.meshgrid(np.arange(w_original), np.arange(h_original))
    x_rot = (c - xc) * math.cos(angle) + (r - yc) * math.sin(angle)
    y_rot = -(c - xc) * math.sin(angle) + (r - yc) * math.cos(angle)
    d = x_rot * x_rot / x_radius / x_radius + y_rot * y_rot / y_radius / y_radius
    k = 2 - np.power(d, 0.5)
    k[d >= 1] = 1

    image[:, :, 2] = np.clip(image[:, :, 2] * k, 0, 255).astype(np.uint8)

    image = cv2.cvtColor(image, cv2.COLOR_HSV2RGB)

    return image

perspective_transform

perspective_transform(image: ImageType, offset_top_left: OffsetType, offset_top_right: OffsetType, offset_bottom_right: OffsetType, offset_bottom_left: OffsetType, interpolate_method: str = 'nearest')
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
def perspective_transform(
    image: ImageType,
    offset_top_left: OffsetType,
    offset_top_right: OffsetType,
    offset_bottom_right: OffsetType,
    offset_bottom_left: OffsetType,
    interpolate_method: str = "nearest",
):
    height, width = image.shape[:2]

    for point_offset in [
        offset_top_left,
        offset_top_right,
        offset_bottom_right,
        offset_bottom_left,
    ]:
        offset_x, offset_y = point_offset

        check_value(offset_x, 0, 49)
        check_value(offset_y, 0, 49)

    transform_matrix = calculate_transform_matrix(
        width=width,
        height=height,
        offset_top_left=offset_top_left,
        offset_top_right=offset_top_right,
        offset_bottom_right=offset_bottom_right,
        offset_bottom_left=offset_bottom_left,
    )
    image = cv2.warpPerspective(
        image, transform_matrix, (width, height), flags=INTERPOLATE_METHOD_CV2[interpolate_method]
    )

    return image

erase

erase(image: ImageType, x: int, y: int, w: int, h: int, v: ndarray)
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
@support_gray
@support_rgba
def erase(
    image: ImageType,
    x: int,
    y: int,
    w: int,
    h: int,
    v: np.ndarray,
):
    image[y : y + h, x : x + w, ...] = v
    return image.astype("uint8")

grayscale

grayscale(image: ImageType) -> ndarray
Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
@support_gray
@support_rgba
def grayscale(
    image: ImageType,
) -> np.ndarray:
    image = AF.to_gray(image)
    return image.astype("uint8")

check_range

check_range(data: Union[Sequence[int], Sequence[float]], min_value: Union[int, float], max_value: Union[int, float])
Source code in SaigeToolkit/data/transform/function_util.py
def check_range(
    data: Union[Sequence[int], Sequence[float]],
    min_value: Union[int, float],
    max_value: Union[int, float],
):
    if not (isinstance(data, Sequence) and len(data) == 2):
        raise AugmentationParameterTypeError

    check_value(data[0], min_value, max_value)
    check_value(data[1], min_value, max_value)

    if not (min_value <= data[0] <= data[1] <= max_value):
        raise AugmentationParameterRangeError

box_function

PolygonType module-attribute

PolygonType = List[ndarray]

BBoxesType module-attribute

BBoxesType = Union[ndarray, NumpyBoxes]

OffsetType module-attribute

OffsetType = Tuple[float, float]

NumpyBoxes

Bases: ndarray

coordinate instance-attribute
coordinate: str
__new__
__new__(input_array, coordinate: str, dtype=None) -> NumpyBoxes
Source code in SaigeToolkit/data/dataclass/box.py
def __new__(cls, input_array, coordinate: str, dtype=None) -> NumpyBoxes:
    obj = np.array(input_array).view(cls)

    cls._check_boxes(obj)

    if dtype is not None:
        obj = obj.astype(dtype)
    obj.coordinate = coordinate
    return obj
__array_finalize__
__array_finalize__(obj)
Source code in SaigeToolkit/data/dataclass/box.py
def __array_finalize__(self, obj):
    if obj is None:
        return
    self.coordinate = getattr(obj, "coordinate", None)
__array_function__
__array_function__(func, types, args, kwargs)
Source code in SaigeToolkit/data/dataclass/box.py
def __array_function__(self, func, types, args, kwargs):
    def unwrap(e):
        return np.asarray(e) if isinstance(e, NumpyBoxes) else e

    def wrap(e, coordinate):
        return NumpyBoxes(e, coordinate) if isinstance(e, np.ndarray) else e

    def get_coordinate(args, kwargs):
        flat_args, _ = tree_flatten(args)
        flat_kwargs, _ = tree_flatten(kwargs)
        coordinates = [e.coordinate for e in flat_args + flat_kwargs if isinstance(e, NumpyBoxes)]

        assert len(set(coordinates)) == 1
        coordinate = coordinates[0]

        return coordinate

    kwargs = kwargs or {}
    ret = func(*tree_map(unwrap, args), **tree_map(unwrap, kwargs))
    coordinate = get_coordinate(args, kwargs)
    wrap_with_coordinate = functools.partial(wrap, coordinate=coordinate)
    ret = tree_map(wrap_with_coordinate, ret)

    return ret
convert_coordinate
convert_coordinate(coordinate: str) -> NumpyBoxes
Source code in SaigeToolkit/data/dataclass/box.py
def convert_coordinate(self, coordinate: str) -> NumpyBoxes:
    new_boxes: NumpyBoxes = convert_coordinate(self, self.coordinate, coordinate)
    new_boxes.coordinate = coordinate
    return new_boxes
to_numpy
to_numpy() -> ndarray
Source code in SaigeToolkit/data/dataclass/box.py
def to_numpy(self) -> np.ndarray:
    return np.array(self)
to_tensor
to_tensor() -> Tensor
Source code in SaigeToolkit/data/dataclass/box.py
def to_tensor(self) -> torch.Tensor:
    return torch.from_numpy(self.to_numpy())
_check_boxes staticmethod
_check_boxes(boxes: ndarray)
Source code in SaigeToolkit/data/dataclass/box.py
@staticmethod
def _check_boxes(boxes: np.ndarray):
    # 숫자가 아닌 값이 들어오는 경우
    if not np.issubdtype(boxes.dtype, np.number):
        raise BoxValueError

    # box position이 음수가 들어오는 경우
    if np.any(boxes < 0):
        raise BoxValueError

rotate_polygons

rotate_polygons(polygons: PolygonType, angle: float, image_size: Tuple[int], target_size: Optional[Tuple[int]] = None) -> PolygonType
Source code in SaigeToolkit/data/transform/polygon_function.py
def rotate(
    polygons: PolygonType,
    angle: float,
    image_size: Tuple[int],
    target_size: Optional[Tuple[int]] = None,
) -> PolygonType:
    if len(polygons) == 0:
        return polygons

    dtype = polygons[0].dtype
    w, h = image_size

    anchor_origin = np.array([w // 2, h // 2]).astype(dtype)

    if target_size is None:
        anchor_target = anchor_origin
    else:
        anchor_target = np.array([target_size[0] // 2, target_size[1] // 2]).astype(dtype)

    theta = np.deg2rad(angle)
    rotation_matrix = [[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]

    rotated_polygons = []
    for polygon in polygons:
        # Translate polygon so that the rotation point is at the origin
        rotated_polygon = polygon - anchor_origin

        # Rotate the polygon
        rotated_polygon = np.dot(rotated_polygon, rotation_matrix)

        # Translate the polygon back
        rotated_polygon += anchor_target

        rotated_polygons.append(rotated_polygon)

    return rotated_polygons

calculate_transform_matrix

calculate_transform_matrix(width: int, height: int, offset_top_left: OffsetType, offset_top_right: OffsetType, offset_bottom_right: OffsetType, offset_bottom_left: OffsetType) -> ndarray

Calculates the perspective transformation matrix using the given width, height, and corner points of a rectangle.

Parameters:

  • width (int) –

    Width of the original image.

  • height (int) –

    Height of the original image.

  • offset_top_left (OffsetType) –

    The offset ratio of the top-left corner point. Represented by the coordinates (x, y) and has a range of [0, 49]. Calculate xand y according to the procedure below.

    x` = width * offset_top_left[0]
    y` = height * offset_top_left[1]
    
  • offset_bottom_right (OffsetType) –

    The offset ratio of the bottom-right corner point. Calculate xand y according to the procedure below.

    x` = width - width * offset_bottom_right[0]
    y` = hegiht - height * offset_bottom_right[1]
    
  • offset_top_right (OffsetType) –

    The offset ratio of the top-left corner point.

  • offset_bottom_left (OffsetType) –

    The offset ratio of the bottom-left corner point.

Returns:

  • ndarray

    np.ndarray: The 4x3 perspective transform matrix.

Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
def calculate_transform_matrix(
    width: int,
    height: int,
    offset_top_left: OffsetType,
    offset_top_right: OffsetType,
    offset_bottom_right: OffsetType,
    offset_bottom_left: OffsetType,
) -> np.ndarray:
    """
    Calculates the perspective transformation matrix
    using the given width, height, and corner points of a rectangle.

    Parameters:
        width (int): Width of the original image.
        height (int): Height of the original image.
        offset_top_left (OffsetType):
            The offset ratio of the top-left corner point.
            Represented by the coordinates (x, y) and has a range of [0, 49].
            Calculate x` and y` according to the procedure below.

            ```
            x` = width * offset_top_left[0]
            y` = height * offset_top_left[1]
            ```

        offset_bottom_right (OffsetType):
            The offset ratio of the bottom-right corner point.
            Calculate x` and y` according to the procedure below.

            ```
            x` = width - width * offset_bottom_right[0]
            y` = hegiht - height * offset_bottom_right[1]
            ```

        offset_top_right (OffsetType): The offset ratio of the top-left corner point.
        offset_bottom_left (OffsetType): The offset ratio of the bottom-left corner point.

    Returns:
        np.ndarray: The 4x3 perspective transform matrix.

    """
    points_from = np.float32([[0, 0], [width, 0], [width, height], [0, height]])

    point_top_left: OffsetType = (
        (offset_top_left[0] / 100) * width,
        (offset_top_left[1] / 100) * height,
    )
    point_top_right: OffsetType = (
        width - (offset_top_right[0] / 100) * width,
        (offset_top_right[1] / 100) * height,
    )
    point_bottom_right: OffsetType = (
        width - (offset_bottom_right[0] / 100) * width,
        height - (offset_bottom_right[1] / 100) * height,
    )
    point_bottom_left: OffsetType = (
        (offset_bottom_left[0] / 100) * width,
        height - (offset_bottom_left[1] / 100) * height,
    )
    points_to = np.float32(
        [
            point_top_left,
            point_top_right,
            point_bottom_right,
            point_bottom_left,
        ]
    )
    transform_matrix = cv2.getPerspectiveTransform(points_from, points_to)

    return transform_matrix

check_value

check_value(data: Union[int, float], min_value: Union[int, float], max_value: Union[int, float])
Source code in SaigeToolkit/data/transform/function_util.py
def check_value(data: Union[int, float], min_value: Union[int, float], max_value: Union[int, float]):
    if not (isinstance(data, (int, float))):
        raise AugmentationParameterTypeError

    if not (min_value <= data <= max_value):
        raise AugmentationParameterRangeError

preserve_coordinates

preserve_coordinates(func)

Box augmentation이 (left, top, right, bottom) coordinate system을 기반으로 구현 되어있기 때문에, input bboxes의 coordinate system을 확인하고 augmentation에 맞는 coordinate system으로 변환하고, augmentation이 끝나면 다시 기존 coordinate system으로 변경하여 출력합니다.

  • np.ndarray의 경우 coordinate system을 체크할 수 없기 때문에 (left, top, right, bottom) coordinate system이라고 가정합니다.

  • NumpyBBoxes의 경우 NumpyBBoxes 내부 변수 coordinate과 내부 함수 convert_coordinate를 활용하여 구현됩니다.

Source code in SaigeToolkit/data/transform/box_function.py
def preserve_coordinates(func):
    """
    Box augmentation이 (left, top, right, bottom) coordinate system을 기반으로 구현 되어있기 때문에,
    input bboxes의 coordinate system을 확인하고 augmentation에 맞는 coordinate system으로 변환하고,
    augmentation이 끝나면 다시 기존 coordinate system으로 변경하여 출력합니다.

    - np.ndarray의 경우
    coordinate system을 체크할 수 없기 때문에 (left, top, right, bottom) coordinate system이라고 가정합니다.

    - NumpyBBoxes의 경우
    NumpyBBoxes 내부 변수 coordinate과 내부 함수 convert_coordinate를 활용하여 구현됩니다.

    """
    _FUNCTIONAL_BBOX_COORDINATE = "xyxy"

    def wrapped_function_for_ndarray(bboxes: np.ndarray, *args, **kwargs) -> np.ndarray:
        new_bboxes = func(bboxes, *args, **kwargs)

        return new_bboxes

    def wrapped_function_for_numpyboxes(bboxes: NumpyBoxes, *args, **kwargs) -> NumpyBoxes:
        # original coordinate -> (left, top, right, bottom)
        original_coordinate = bboxes.coordinate  # record original coordinate
        bboxes = bboxes.convert_coordinate(_FUNCTIONAL_BBOX_COORDINATE)  # -> (left, top, right, bottom)

        # box augmentation
        new_bboxes = func(bboxes, *args, **kwargs)
        if not isinstance(new_bboxes, bboxes.__class__):
            new_bboxes = bboxes.__class__(new_bboxes, _FUNCTIONAL_BBOX_COORDINATE)

        # (left, top, right, bottom) -> original coordinate
        new_bboxes = new_bboxes.convert_coordinate(original_coordinate)

        return new_bboxes

    @wraps(func)
    def wrapped_function(bboxes: BBoxesType, *args, **kwargs) -> BBoxesType:
        # isinstance가 상속된 type도 true를 return 하기 때문에 여기서는 type(instance) == class로 체크
        if isinstance(bboxes, NumpyBoxes):
            new_bboxes = wrapped_function_for_numpyboxes(bboxes, *args, **kwargs)
        elif isinstance(bboxes, np.ndarray):
            new_bboxes = wrapped_function_for_ndarray(bboxes, *args, **kwargs)
        else:
            raise NotImplementedError

        return new_bboxes

    return wrapped_function

resize_box

resize_box(bboxes: BBoxesType, image_size: Tuple[int], tw: int, th: int) -> BBoxesType

bbox resize from (w, h) to (tw, th)

Source code in SaigeToolkit/data/transform/box_function.py
@preserve_coordinates
def resize_box(bboxes: BBoxesType, image_size: Tuple[int], tw: int, th: int) -> BBoxesType:
    """bbox resize from (w, h) to (tw, th)"""
    dtype = bboxes.dtype
    w, h = image_size
    if w == tw and h == th:
        return bboxes
    else:
        w_scale = tw / w
        h_scale = th / h
        return (bboxes * (w_scale, h_scale, w_scale, h_scale)).astype(dtype)

crop_box

crop_box(bboxes: BBoxesType, cropping_box: Union[ndarray, List[int]]) -> BBoxesType

bbox crop. An image is cropped at (new_left, new_top, new_right, new_bottom)

Source code in SaigeToolkit/data/transform/box_function.py
@preserve_coordinates
def crop_box(bboxes: BBoxesType, cropping_box: Union[np.ndarray, List[int]]) -> BBoxesType:
    """bbox crop. An image is cropped at (new_left, new_top, new_right, new_bottom)"""
    dtype = bboxes.dtype
    new_left, new_top, new_right, new_bottom = map(round, cropping_box)
    new_h = new_bottom - new_top
    new_bboxes = bboxes - (new_left, new_top, new_left, new_top)
    new_bboxes[:, [0, 1]] = np.maximum(new_bboxes[:, [0, 1]], 0)
    new_bboxes[:, [2, 3]] = np.minimum(new_bboxes[:, [2, 3]], (new_right - new_left, new_h))
    return new_bboxes.astype(dtype)

hflip_box

hflip_box(bboxes: BBoxesType, image_size: Tuple[int]) -> BBoxesType
Source code in SaigeToolkit/data/transform/box_function.py
@preserve_coordinates
def hflip_box(bboxes: BBoxesType, image_size: Tuple[int]) -> BBoxesType:
    w, h = image_size
    bboxes = bboxes.copy()
    bboxes[:, [0, 2]] = w - bboxes[:, [2, 0]]
    return bboxes

vflip_box

vflip_box(bboxes: BBoxesType, image_size: Tuple[int]) -> BBoxesType
Source code in SaigeToolkit/data/transform/box_function.py
@preserve_coordinates
def vflip_box(bboxes: BBoxesType, image_size: Tuple[int]) -> BBoxesType:
    w, h = image_size
    bboxes = bboxes.copy()
    bboxes[:, [1, 3]] = h - bboxes[:, [3, 1]]
    return bboxes

rotate

rotate(bboxes: BBoxesType, angle: Union[float, int], image_size: Tuple[int], target_size: Optional[Tuple[int]] = None, clipping: bool = True) -> BBoxesType
Source code in SaigeToolkit/data/transform/box_function.py
@preserve_coordinates
def rotate(
    bboxes: BBoxesType,
    angle: Union[float, int],
    image_size: Tuple[int],
    target_size: Optional[Tuple[int]] = None,
    clipping: bool = True,
) -> BBoxesType:
    dtype = bboxes.dtype
    w, h = image_size

    def _bboxes_to_polygons(bboxes: BBoxesType) -> PolygonType:
        polygons = []
        for bbox in bboxes:
            x1, y1, x2, y2 = bbox
            polygon = np.array([[x1, y1], [x1, y2], [x2, y2], [x2, y1]]).astype(dtype)
            polygons.append(polygon)
        return polygons

    def _polygons_to_bboxes(polygons: PolygonType) -> BBoxesType:
        bboxes = []
        for polygon in polygons:
            # Extract the bounding box from the rotated polygon
            x1, y1 = np.min(polygon, axis=0)
            x2, y2 = np.max(polygon, axis=0)
            bboxes.append([x1, y1, x2, y2])

        bboxes = np.array(bboxes).reshape(-1, 4)
        return bboxes

    if bboxes.size == 0:
        return bboxes

    polygons = _bboxes_to_polygons(bboxes)
    rotated_polygons = rotate_polygons(
        polygons=polygons, angle=angle, image_size=image_size, target_size=target_size
    )
    rotated_bboxes = _polygons_to_bboxes(rotated_polygons)

    if clipping:
        rotated_bboxes[:, [0, 2]] = np.clip(rotated_bboxes[:, [0, 2]], 0, w - 1)
        rotated_bboxes[:, [1, 3]] = np.clip(rotated_bboxes[:, [1, 3]], 0, h - 1)
    return rotated_bboxes.astype(dtype)

rotate90

rotate90(bboxes: BBoxesType, factor: int, image_size: Tuple[int], clipping: bool = True) -> BBoxesType
Source code in SaigeToolkit/data/transform/box_function.py
@preserve_coordinates
def rotate90(
    bboxes: BBoxesType,
    factor: int,
    image_size: Tuple[int],
    clipping: bool = True,
) -> BBoxesType:
    angle = factor * 90.0
    if factor % 2 == 0:
        target_size = image_size
    else:
        target_size = (image_size[1], image_size[0])
    return rotate(
        bboxes=bboxes, angle=angle, image_size=image_size, target_size=target_size, clipping=clipping
    )

translate_box

translate_box(bboxes: BBoxesType, offset: Tuple[int], image_size: Tuple[int]) -> BBoxesType
Source code in SaigeToolkit/data/transform/box_function.py
@preserve_coordinates
def translate_box(bboxes: BBoxesType, offset: Tuple[int], image_size: Tuple[int]) -> BBoxesType:
    w, h = image_size
    x_offset, y_offset = offset
    new_bboxes = bboxes.copy()
    new_bboxes[:, 0] = np.maximum(np.minimum(bboxes[:, 0] - x_offset, w), 0)
    new_bboxes[:, 1] = np.maximum(np.minimum(bboxes[:, 1] - y_offset, h), 0)
    new_bboxes[:, 2] = np.minimum(np.maximum(bboxes[:, 2] - x_offset, 0), w)
    new_bboxes[:, 3] = np.minimum(np.maximum(bboxes[:, 3] - y_offset, 0), h)
    return new_bboxes

ratio_jitter

ratio_jitter(bboxes: BBoxesType, image_size: Tuple[int], proportion_left: float = 0.0, proportion_right: float = 0.0, proportion_top: float = 0.0, proportion_bottom: float = 0.0) -> BBoxesType
Source code in SaigeToolkit/data/transform/box_function.py
@preserve_coordinates
def ratio_jitter(
    bboxes: BBoxesType,
    image_size: Tuple[int],
    proportion_left: float = 0.0,
    proportion_right: float = 0.0,
    proportion_top: float = 0.0,
    proportion_bottom: float = 0.0,
) -> BBoxesType:
    w, h = image_size

    left = int(w * proportion_left)
    right = int(w * proportion_right)
    top = int(h * proportion_top)
    bottom = int(h * proportion_bottom)

    # Crop
    crop_left = left if left > 0 else 0
    crop_right = right if right > 0 else 0
    crop_top = top if top > 0 else 0
    crop_bottom = bottom if bottom > 0 else 0

    crop_w = max(w - crop_left - crop_right, 1)
    crop_h = max(h - crop_top - crop_bottom, 1)

    bboxes = crop_box(bboxes, [crop_left, crop_top, crop_left + crop_w, crop_top + crop_h])

    # Padding
    pad_left = 0 if left > 0 else -left
    pad_right = 0 if right > 0 else -right
    pad_top = 0 if top > 0 else -top
    pad_bottom = 0 if bottom > 0 else -bottom

    bboxes = resize_box(bboxes, (crop_w + pad_left + pad_right, crop_h + pad_top + pad_bottom), w, h)

    # Translate
    w_scale = (crop_w + pad_left + pad_right) / w
    h_scale = (crop_h + pad_top + pad_bottom) / h
    bboxes = translate_box(bboxes, [-pad_left / w_scale, -pad_top / h_scale], image_size)

    return bboxes

zoom

zoom(bboxes: BBoxesType, image_size: Tuple[int], ratio: float = 1.0, h_start: float = 0.0, w_start: float = 0.0) -> BBoxesType
Source code in SaigeToolkit/data/transform/box_function.py
@preserve_coordinates
def zoom(
    bboxes: BBoxesType,
    image_size: Tuple[int],
    ratio: float = 1.0,
    h_start: float = 0.0,
    w_start: float = 0.0,
) -> BBoxesType:
    w, h = image_size
    if ratio == 1.0:
        return bboxes
    target_size = (int(w * ratio), int(h * ratio))
    bboxes = resize_box(bboxes, image_size, target_size[0], target_size[1])
    if ratio > 1.0:
        h_start = min(h_start, 1.0 - 1e-5)
        w_start = min(w_start, 1.0 - 1e-5)
        x1 = int((target_size[0] - w + 1) * w_start)
        y1 = int((target_size[1] - h + 1) * h_start)
        bboxes = crop_box(bboxes, [x1, y1, x1 + w, y1 + h])
    elif ratio < 1.0:
        x1 = int((w - target_size[0] + 1) * w_start)
        y1 = int((h - target_size[1] + 1) * h_start)
        bboxes = translate_box(bboxes, [-x1, -y1], image_size)

    return bboxes

random_resized_crop_and_pad

random_resized_crop_and_pad(bboxes: BBoxesType, image_size: Tuple[int], scale: float = 1.0, aspect_ratio: float = 1.0, h_start: float = 0.0, w_start: float = 0.0, height: Optional[int] = None, width: Optional[int] = None) -> BBoxesType
Source code in SaigeToolkit/data/transform/box_function.py
@preserve_coordinates
def random_resized_crop_and_pad(
    bboxes: BBoxesType,
    image_size: Tuple[int],
    scale: float = 1.0,
    aspect_ratio: float = 1.0,
    h_start: float = 0.0,
    w_start: float = 0.0,
    height: Optional[int] = None,
    width: Optional[int] = None,
) -> BBoxesType:
    w_original, h_original = image_size
    area = h_original * w_original
    target_area = scale * area

    crop_height = int(round(math.sqrt(target_area / aspect_ratio)))
    crop_width = int(round(math.sqrt(target_area * aspect_ratio)))

    w_start = min(w_start, 1.0 - 1e-5)
    h_start = min(h_start, 1.0 - 1e-5)

    # Padding
    pad_top = max(crop_height - h_original, 0)
    pad_bottom = max(crop_height - h_original, 0)
    pad_left = max(crop_width - w_original, 0)
    pad_right = max(crop_width - w_original, 0)

    padded_image_size = [w_original + pad_left + pad_right, h_original + pad_top + pad_bottom]
    bboxes = translate_box(bboxes, [-pad_left, -pad_top], padded_image_size)

    # Crop
    x1 = int((padded_image_size[0] - crop_width + 1) * w_start)
    y1 = int((padded_image_size[1] - crop_height + 1) * h_start)
    bboxes = crop_box(bboxes, [x1, y1, x1 + crop_width, y1 + crop_height])

    # Resize
    bboxes = resize_box(
        bboxes,
        [crop_width, crop_height],
        width or w_original,
        height or h_original,
    )

    return bboxes

perspective_transform

perspective_transform(bboxes: BBoxesType, image_size: Tuple[int], offset_top_left: OffsetType, offset_top_right: OffsetType, offset_bottom_right: OffsetType, offset_bottom_left: OffsetType) -> BBoxesType
Source code in SaigeToolkit/data/transform/box_function.py
@preserve_coordinates
def perspective_transform(
    bboxes: BBoxesType,
    image_size: Tuple[int],
    offset_top_left: OffsetType,
    offset_top_right: OffsetType,
    offset_bottom_right: OffsetType,
    offset_bottom_left: OffsetType,
) -> BBoxesType:
    width, height = image_size

    for point_offset in [
        offset_top_left,
        offset_top_right,
        offset_bottom_right,
        offset_bottom_left,
    ]:
        offset_x, offset_y = point_offset

        check_value(offset_x, 0, 49)
        check_value(offset_y, 0, 49)

    transform_matrix = calculate_transform_matrix(
        width=width,
        height=height,
        offset_top_left=offset_top_left,
        offset_top_right=offset_top_right,
        offset_bottom_right=offset_bottom_right,
        offset_bottom_left=offset_bottom_left,
    )

    new_bboxes = bboxes.copy()
    for idx_box, bbox in enumerate(bboxes):
        # [(x1, y1), (x2, y1), (x2, y2), (x1, y2)]
        points = [(bbox[0], bbox[1]), (bbox[2], bbox[1]), (bbox[2], bbox[3]), (bbox[0], bbox[3])]

        dtype_max_value = np.iinfo(np.int32).max
        min_x, min_y = dtype_max_value, dtype_max_value
        max_x, max_y = 0, 0

        for point in points:
            x, y, scaling_factor = np.dot(transform_matrix, np.append(point, 1))
            x = int(x / scaling_factor)
            y = int(y / scaling_factor)

            if x < min_x:
                min_x = x

            elif x > max_x:
                max_x = x

            if y < min_y:
                min_y = y

            elif y > max_y:
                max_y = y

        new_bboxes[idx_box] = [min_x, min_y, max_x, max_y]

    return new_bboxes

polygon_function

PolygonType module-attribute

PolygonType = List[ndarray]

OffsetType module-attribute

OffsetType = Tuple[float, float]

calculate_transform_matrix

calculate_transform_matrix(width: int, height: int, offset_top_left: OffsetType, offset_top_right: OffsetType, offset_bottom_right: OffsetType, offset_bottom_left: OffsetType) -> ndarray

Calculates the perspective transformation matrix using the given width, height, and corner points of a rectangle.

Parameters:

  • width (int) –

    Width of the original image.

  • height (int) –

    Height of the original image.

  • offset_top_left (OffsetType) –

    The offset ratio of the top-left corner point. Represented by the coordinates (x, y) and has a range of [0, 49]. Calculate xand y according to the procedure below.

    x` = width * offset_top_left[0]
    y` = height * offset_top_left[1]
    
  • offset_bottom_right (OffsetType) –

    The offset ratio of the bottom-right corner point. Calculate xand y according to the procedure below.

    x` = width - width * offset_bottom_right[0]
    y` = hegiht - height * offset_bottom_right[1]
    
  • offset_top_right (OffsetType) –

    The offset ratio of the top-left corner point.

  • offset_bottom_left (OffsetType) –

    The offset ratio of the bottom-left corner point.

Returns:

  • ndarray

    np.ndarray: The 4x3 perspective transform matrix.

Source code in SaigeToolkit/data/transform/augmentation/augment_function.py
def calculate_transform_matrix(
    width: int,
    height: int,
    offset_top_left: OffsetType,
    offset_top_right: OffsetType,
    offset_bottom_right: OffsetType,
    offset_bottom_left: OffsetType,
) -> np.ndarray:
    """
    Calculates the perspective transformation matrix
    using the given width, height, and corner points of a rectangle.

    Parameters:
        width (int): Width of the original image.
        height (int): Height of the original image.
        offset_top_left (OffsetType):
            The offset ratio of the top-left corner point.
            Represented by the coordinates (x, y) and has a range of [0, 49].
            Calculate x` and y` according to the procedure below.

            ```
            x` = width * offset_top_left[0]
            y` = height * offset_top_left[1]
            ```

        offset_bottom_right (OffsetType):
            The offset ratio of the bottom-right corner point.
            Calculate x` and y` according to the procedure below.

            ```
            x` = width - width * offset_bottom_right[0]
            y` = hegiht - height * offset_bottom_right[1]
            ```

        offset_top_right (OffsetType): The offset ratio of the top-left corner point.
        offset_bottom_left (OffsetType): The offset ratio of the bottom-left corner point.

    Returns:
        np.ndarray: The 4x3 perspective transform matrix.

    """
    points_from = np.float32([[0, 0], [width, 0], [width, height], [0, height]])

    point_top_left: OffsetType = (
        (offset_top_left[0] / 100) * width,
        (offset_top_left[1] / 100) * height,
    )
    point_top_right: OffsetType = (
        width - (offset_top_right[0] / 100) * width,
        (offset_top_right[1] / 100) * height,
    )
    point_bottom_right: OffsetType = (
        width - (offset_bottom_right[0] / 100) * width,
        height - (offset_bottom_right[1] / 100) * height,
    )
    point_bottom_left: OffsetType = (
        (offset_bottom_left[0] / 100) * width,
        height - (offset_bottom_left[1] / 100) * height,
    )
    points_to = np.float32(
        [
            point_top_left,
            point_top_right,
            point_bottom_right,
            point_bottom_left,
        ]
    )
    transform_matrix = cv2.getPerspectiveTransform(points_from, points_to)

    return transform_matrix

check_value

check_value(data: Union[int, float], min_value: Union[int, float], max_value: Union[int, float])
Source code in SaigeToolkit/data/transform/function_util.py
def check_value(data: Union[int, float], min_value: Union[int, float], max_value: Union[int, float]):
    if not (isinstance(data, (int, float))):
        raise AugmentationParameterTypeError

    if not (min_value <= data <= max_value):
        raise AugmentationParameterRangeError

vertical_flip

vertical_flip(polygons: PolygonType, image_size: Tuple[int]) -> PolygonType
Source code in SaigeToolkit/data/transform/polygon_function.py
def vertical_flip(polygons: PolygonType, image_size: Tuple[int]) -> PolygonType:
    _, h = image_size
    polygons = deepcopy(polygons)
    for polygon in polygons:
        polygon[:, 1] = h - polygon[:, 1]
    return polygons

horizontal_flip

horizontal_flip(polygons: PolygonType, image_size: Tuple[int]) -> PolygonType
Source code in SaigeToolkit/data/transform/polygon_function.py
def horizontal_flip(polygons: PolygonType, image_size: Tuple[int]) -> PolygonType:
    w, _ = image_size
    polygons = deepcopy(polygons)
    for polygon in polygons:
        polygon[:, 0] = w - polygon[:, 0]
    return polygons

rotate

rotate(polygons: PolygonType, angle: float, image_size: Tuple[int], target_size: Optional[Tuple[int]] = None) -> PolygonType
Source code in SaigeToolkit/data/transform/polygon_function.py
def rotate(
    polygons: PolygonType,
    angle: float,
    image_size: Tuple[int],
    target_size: Optional[Tuple[int]] = None,
) -> PolygonType:
    if len(polygons) == 0:
        return polygons

    dtype = polygons[0].dtype
    w, h = image_size

    anchor_origin = np.array([w // 2, h // 2]).astype(dtype)

    if target_size is None:
        anchor_target = anchor_origin
    else:
        anchor_target = np.array([target_size[0] // 2, target_size[1] // 2]).astype(dtype)

    theta = np.deg2rad(angle)
    rotation_matrix = [[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]

    rotated_polygons = []
    for polygon in polygons:
        # Translate polygon so that the rotation point is at the origin
        rotated_polygon = polygon - anchor_origin

        # Rotate the polygon
        rotated_polygon = np.dot(rotated_polygon, rotation_matrix)

        # Translate the polygon back
        rotated_polygon += anchor_target

        rotated_polygons.append(rotated_polygon)

    return rotated_polygons

rotate90

rotate90(polygons: PolygonType, factor: int, image_size: Tuple[int]) -> PolygonType
Source code in SaigeToolkit/data/transform/polygon_function.py
def rotate90(
    polygons: PolygonType,
    factor: int,
    image_size: Tuple[int],
) -> PolygonType:
    angle = factor * 90.0
    if factor % 2 == 0:
        target_size = image_size
    else:
        target_size = (image_size[1], image_size[0])
    return rotate(polygons=polygons, angle=angle, image_size=image_size, target_size=target_size)

ratio_jitter

ratio_jitter(polygons: PolygonType, image_size: Tuple[int], proportion_left: float, proportion_right: float, proportion_top: float, proportion_bottom: float) -> PolygonType
Source code in SaigeToolkit/data/transform/polygon_function.py
def ratio_jitter(
    polygons: PolygonType,
    image_size: Tuple[int],
    proportion_left: float,
    proportion_right: float,
    proportion_top: float,
    proportion_bottom: float,
) -> PolygonType:
    w, h = image_size

    left = int(w * proportion_left)
    right = int(w * proportion_right)
    top = int(h * proportion_top)
    bottom = int(h * proportion_bottom)

    # Crop
    crop_left = left if left > 0 else 0
    crop_right = right if right > 0 else 0
    crop_top = top if top > 0 else 0
    crop_bottom = bottom if bottom > 0 else 0

    crop_w = max(w - crop_left - crop_right, 1)
    crop_h = max(h - crop_top - crop_bottom, 1)
    polygons = translate_polygon(polygons, [crop_left, crop_top])

    # Padding
    pad_left = 0 if left > 0 else -left
    pad_right = 0 if right > 0 else -right
    pad_top = 0 if top > 0 else -top
    pad_bottom = 0 if bottom > 0 else -bottom

    polygons = resize_polygon(
        polygons, (crop_w + pad_left + pad_right, crop_h + pad_top + pad_bottom), w, h
    )

    # Translate
    w_scale = (crop_w + pad_left + pad_right) / w
    h_scale = (crop_h + pad_top + pad_bottom) / h
    polygons = translate_polygon(polygons, [-int(pad_left / w_scale), -int(pad_top / h_scale)])

    return polygons

zoom

zoom(polygons: PolygonType, image_size: Tuple[int], ratio: float, h_start: float, w_start: float) -> PolygonType
Source code in SaigeToolkit/data/transform/polygon_function.py
def zoom(
    polygons: PolygonType,
    image_size: Tuple[int],
    ratio: float,
    h_start: float,
    w_start: float,
) -> PolygonType:
    w, h = image_size

    if ratio == 1.0:
        return polygons

    target_size = (int(w * ratio), int(h * ratio))
    polygons = resize_polygon(polygons, image_size, target_size[0], target_size[1])

    x1 = 0
    y1 = 0

    if ratio > 1.0:
        h_start = min(h_start, 1.0 - 1e-5)
        w_start = min(w_start, 1.0 - 1e-5)
        x1 = int((target_size[0] - w + 1) * w_start)
        y1 = int((target_size[1] - h + 1) * h_start)

    elif ratio < 1.0:
        x1 = -int((w - target_size[0] + 1) * w_start)
        y1 = -int((h - target_size[1] + 1) * h_start)

    polygons = translate_polygon(polygons, [x1, y1])

    return polygons

random_resized_crop_and_pad

random_resized_crop_and_pad(polygons: PolygonType, image_size: Tuple[int], scale: float, aspect_ratio: float, h_start: float, w_start: float, h_target: Optional[int] = None, w_target: Optional[int] = None, **params) -> PolygonType
Source code in SaigeToolkit/data/transform/polygon_function.py
def random_resized_crop_and_pad(
    polygons: PolygonType,
    image_size: Tuple[int],
    scale: float,
    aspect_ratio: float,
    h_start: float,
    w_start: float,
    h_target: Optional[int] = None,
    w_target: Optional[int] = None,
    **params
) -> PolygonType:
    w_original, h_original = image_size
    area = h_original * w_original
    target_area = scale * area

    crop_height = int(round(math.sqrt(target_area / aspect_ratio)))
    crop_width = int(round(math.sqrt(target_area * aspect_ratio)))

    # Padding
    pad_top = max(crop_height - h_original, 0)
    pad_bottom = max(crop_height - h_original, 0)
    pad_left = max(crop_width - w_original, 0)
    pad_right = max(crop_width - w_original, 0)

    padded_image_size = [w_original + pad_left + pad_right, h_original + pad_top + pad_bottom]
    polygons = translate_polygon(
        polygons,
        [-(pad_left), -(pad_top)],
    )

    # Crop
    x1 = int((padded_image_size[0] - crop_width + 1) * w_start)
    y1 = int((padded_image_size[1] - crop_height + 1) * h_start)
    polygons = translate_polygon(polygons, [x1, y1])

    # Resize
    polygons = resize_polygon(
        polygons,
        [crop_width, crop_height],
        w_target or w_original,
        h_target or h_original,
    )
    return polygons

perspective_transform

perspective_transform(polygons: PolygonType, image_size: Tuple[int], offset_top_left: OffsetType, offset_top_right: OffsetType, offset_bottom_right: OffsetType, offset_bottom_left: OffsetType) -> PolygonType
Source code in SaigeToolkit/data/transform/polygon_function.py
def perspective_transform(
    polygons: PolygonType,
    image_size: Tuple[int],
    offset_top_left: OffsetType,
    offset_top_right: OffsetType,
    offset_bottom_right: OffsetType,
    offset_bottom_left: OffsetType,
) -> PolygonType:
    width, height = image_size

    for point_offset in [
        offset_top_left,
        offset_top_right,
        offset_bottom_right,
        offset_bottom_left,
    ]:
        offset_x, offset_y = point_offset

        check_value(offset_x, 0, 49)
        check_value(offset_y, 0, 49)

    transform_matrix = calculate_transform_matrix(
        width=width,
        height=height,
        offset_top_left=offset_top_left,
        offset_top_right=offset_top_right,
        offset_bottom_right=offset_bottom_right,
        offset_bottom_left=offset_bottom_left,
    )
    new_polygons = deepcopy(polygons)
    for idx_poly, polygon in enumerate(polygons):
        for idx_pt, point in enumerate(polygon):
            x, y, scaling_factor = np.dot(transform_matrix, np.append(point, 1))

            new_polygons[idx_poly][idx_pt][0] = int(x / scaling_factor)
            new_polygons[idx_poly][idx_pt][1] = int(y / scaling_factor)

    return new_polygons

resize_polygon

resize_polygon(polygons: PolygonType, image_size: Tuple[int], tw: int, th: int) -> PolygonType

Resize polygon from (w, h) to (tw, th)

Source code in SaigeToolkit/data/transform/polygon_function.py
def resize_polygon(polygons: PolygonType, image_size: Tuple[int], tw: int, th: int) -> PolygonType:
    """Resize polygon from (w, h) to (tw, th)"""
    if len(polygons) == 0:
        return polygons

    w, h = image_size
    if w == tw and h == th:
        return polygons

    dtype = polygons[0].dtype

    w_scale = tw / w
    h_scale = th / h

    new_polygons = deepcopy(polygons)

    for polygon in new_polygons:
        polygon[:, 0] = polygon[:, 0] * w_scale
        polygon[:, 1] = polygon[:, 1] * h_scale
        polygon = polygon.astype(dtype)

    return new_polygons

translate_polygon

translate_polygon(polygons: PolygonType, offset: Tuple[int]) -> PolygonType

Translate polyfon from [(x1, y1), ... ] to [(x1 - x_offset), (y1 - y_offset), ...]

Source code in SaigeToolkit/data/transform/polygon_function.py
def translate_polygon(
    polygons: PolygonType,
    offset: Tuple[int],
) -> PolygonType:
    """Translate polyfon from [(x1, y1), ... ] to [(x1 - x_offset), (y1 - y_offset), ...]"""
    if len(polygons) == 0:
        return polygons

    if offset[0] == 0 and offset[1] == 0:
        return polygons

    dtype = polygons[0].dtype

    x_offset, y_offset = np.array(offset).astype(dtype)

    new_polygons = deepcopy(polygons)

    for polygon in new_polygons:
        polygon[:, 0] -= x_offset
        polygon[:, 1] -= y_offset

    return new_polygons