# _____ ______ _____
# / ____/ /\ | ____ | __ \
# | | / \ | |__ | |__) | Caer - Modern Computer Vision
# | | / /\ \ | __| | _ / Languages: Python, C, C++, Cuda
# | |___ / ____ \ | |____ | | \ \ http://github.com/jasmcaus/caer
# \_____\/_/ \_ \______ |_| \_\
# Licensed under the MIT License <http://opensource.org/licenses/MIT>
# SPDX-License-Identifier: MIT
# Copyright (c) 2020-2021 The Caer Authors <http://github.com/jasmcaus>
#pylint:disable=unused-argument,unused-variable,eval-used
import numpy as np
import cv2 as cv
import random
import math
from ..coreten import Tensor, is_tensor
from ..annotations import Tuple, Optional, Union
from .functional import (
is_numeric,
is_numeric_list_or_tuple,
is_tuple,
_rgb,
_snow_process,
_generate_random_lines,
_rain_process,
_generate_random_blur_coordinates,
_add_blur,
_gravel_process,
_add_sun_flare_line,
_add_sun_process,
_apply_motion_blur,
_autumn_process,
_shadow_process
)
__all__ = [
"sim_snow",
"sim_rain",
"sim_fog",
"sim_gravel",
"sim_sun_flare",
"sim_motion_blur",
"sim_autumn",
"sim_shadow"
]
[docs]def sim_snow(tens: Tensor, snow_coeff : Union[float, int] = -1) -> Tensor:
r"""
Simulate snowy conditions on an image.
Args:
tens (Tensor) : Any regular ``caer.Tensor``.
snow_coeff (int): Coefficient value.
Returns:
Tensor of shape ``(height, width, channels)``.
Examples::
>> tens = caer.data.sunrise
>> filtered = caer.filters.sim_snow(tens, snow_coeff=-1)
>> filtered
(427, 640, 3)
"""
if snow_coeff != -1:
if snow_coeff < 0.0 or snow_coeff > 1.0:
raise ValueError("Snow coeff must only be between 0 and 1")
else:
snow_coeff = random.uniform(0, 1)
snow_coeff *= 255/2
snow_coeff += 255/3
return _snow_process(tens, snow_coeff)
# Rain_type = "drizzle", "heavy", "torrential"
[docs]def sim_rain(
tens: Tensor,
slant: int = -1,
drop_length: int = 20,
drop_width: int = 1,
drop_color: Tuple = (200,200,200),
rain_type: Optional[str] = "None"
) -> Tensor: ## (200,200,200) is a shade of gray
r"""
Simulate rainy conditions on an image.
Args:
tens (Tensor) : Any regular ``caer.Tensor``.
slant (int): Slant value.
drop_length (int): Length of the raindrop.
drop_width (int): Width of the raindrop.
drop_color (tuple): Color of the raindrop.
rain_type (str): Type of rain. Can be either "drizzle", "heavy" or "torrential".
Returns:
Tensor of shape ``(height, width, channels)``.
Examples::
>> tens = caer.data.sunrise
>> filtered = caer.filters.sim_rain(tens)
>> filtered
(427, 640, 3)
"""
slant_extreme = slant
if not(is_numeric(slant_extreme) and (slant_extreme >=-20 and slant_extreme <= 20) or slant_extreme==-1):
raise ValueError("Numeric value must be between -20 and 20")
if not(is_numeric(drop_width) and drop_width>=1 and drop_width<=5):
raise ValueError("Width must be between 1 and 5")
if not(is_numeric(drop_length) and drop_length>=0 and drop_length<=100):
raise ValueError("Length must be between 0 and 100")
imshape = tens.shape
if slant_extreme == -1:
slant= np.random.randint(-10,10) # generate random slant if no slant value is given
rain_drops, drop_length= _generate_random_lines(imshape, slant, drop_length, rain_type)
return _rain_process(tens, slant_extreme, drop_length, drop_color, drop_width, rain_drops)
[docs]def sim_fog(tens: Tensor, fog_coeff:int=-1) -> Tensor:
r"""
Simulate foggy conditions on an image.
Args:
tens (Tensor) : Any regular ``caer.Tensor``.
fog_coeff (int): Coefficient value.
Returns:
Tensor of shape ``(height, width, channels)``.
Examples::
>> tens = caer.data.sunrise
>> filtered = caer.filters.sim_fog(tens, fog_coeff=-1)
>> filtered
(427, 640, 3)
"""
if fog_coeff != -1:
if fog_coeff < 0.0 or fog_coeff > 1.0:
raise ValueError("Fog coefficient must be between 0 and 1")
imshape = tens.shape
if fog_coeff == -1:
fog_coeff_t = random.uniform(0.3,1)
else:
fog_coeff_t = fog_coeff
hw = int(imshape[1]//3*fog_coeff_t)
haze_list = _generate_random_blur_coordinates(imshape,hw)
for haze_points in haze_list:
tens = _add_blur(tens, haze_points[0], haze_points[1], hw, fog_coeff_t)
tens = cv.blur(tens, (hw//10, hw//10))
return _rgb(tens)
[docs]def sim_gravel(tens: Tensor, rectangular_roi:Tuple=(-1,-1,-1,-1), num_patches:int=8) -> Tensor:
r"""
Simulate gravelly conditions on an image.
Args:
tens (Tensor) : Any regular ``caer.Tensor``.
rectangular_roi (tuple): Rectanglar co-ordinates of the intended region of interest. Default: (-1,-1,-1,-1).
num_patches (int): Number of patches to operate on.
Returns:
Tensor of shape ``(height, width, channels)``.
Examples::
>> tens = caer.data.sunrise
>> filtered = caer.filters.sim_gravel(tens)
>> filtered
(427, 640, 3)
"""
if is_tuple(rectangular_roi) and is_numeric_list_or_tuple(rectangular_roi) and len(rectangular_roi)==4:
x1 = rectangular_roi[0]
y1 = rectangular_roi[1]
x2 = rectangular_roi[2]
y2 = rectangular_roi[3]
else:
raise ValueError("Rectangular ROI dimensions are invalid.")
if rectangular_roi == (-1,-1,-1,-1):
if is_tensor(tens):
x1 = 0
y1 = int(tens.shape[0]*3/4)
x2 = tens.shape[1]
y2 = tens.shape[0]
else:
x1 = 0
y1 = int(tens[0].shape[0]*3/4)
x2 = tens[0].shape[1]
y2 = tens[0].shape[0]
elif x1 == -1 or y1 == -1 or x2 == -1 or y2 == -1 or x2 <= x1 or y2 <= y1:
raise ValueError("Rectangular ROI dimensions are invalid.")
return _gravel_process(tens, x1, x2, y1, y2, num_patches)
[docs]def sim_sun_flare(tens: Tensor, flare_center:int=-1, angle:int=-1, num_flare_circles:int=8, src_radius:int=400, src_color:Tuple=(255,255,255)) -> Tensor:
r"""
Add a source of light (flare) on an specific region of an image.
Args:
tens (Tensor) : Any regular ``caer.Tensor``.
flare_center (int): Center of the flare. Default: -1.
angle (int): Angle of the flare. Default: -1
num_flare_circles (int): Number of flare circles to operate on.
src_radius (int): Intended size of the flare
src_color (tuple): Intended source color of the flare
Returns:
Tensor of shape ``(height, width, channels)``.
Examples::
>> tens = caer.data.sunrise
>> filtered = caer.filters.sim_sun_flare(tens)
>> filtered
(427, 640, 3)
"""
if angle != -1:
angle = angle % (2*math.pi) # type: ignore
if not(num_flare_circles >= 0 and num_flare_circles <= 20):
raise ValueError("Numeric value must be between 0 and 20")
imshape = tens.shape
if angle == -1:
angle_t = random.uniform(0, 2*math.pi)
if angle_t == math.pi/2:
angle_t = 0
else:
angle_t = angle
if flare_center == -1:
flare_center_t = (random.randint(0, imshape[1]), random.randint(0, imshape[0]//2)) # type: ignore
else:
flare_center_t = flare_center # type: ignore
x, y = _add_sun_flare_line(flare_center_t, angle_t, imshape)
return _add_sun_process(tens, num_flare_circles, flare_center_t, src_radius, x, y, src_color)
[docs]def sim_motion_blur(tens: Tensor, speed_coeff:int=-1) -> Tensor:
r"""
Simulate motion-blur conditions on an image.
Args:
tens (Tensor) : Any regular ``caer.Tensor``.
speed_coeff (int, float): Speed coefficient. Value must be between 0 and 1.
Returns:
Tensor of shape ``(height, width, channels)``.
Examples::
>> tens = caer.data.sunrise
>> filtered = caer.filters.sim_motion_blur(tens, speed_coeff=-1)
>> filtered
(427, 640, 3)
"""
if speed_coeff != -1:
if speed_coeff < 0.0 or speed_coeff > 1.0:
raise ValueError("Speed coefficient must be between 0 and 1")
if speed_coeff == -1:
count_t = int(15 * random.uniform(0, 1))
else:
count_t = int(15 * speed_coeff)
return _apply_motion_blur(tens, count_t)
[docs]def sim_autumn(tens: Tensor) -> Tensor:
r"""
Simulate autumn conditions on an image.
Args:
tens (Tensor) : Any regular ``caer.Tensor``.
Returns:
Tensor of shape ``(height, width, channels)``.
Examples::
>> tens = caer.data.sunrise
>> filtered = caer.filters.sim_autumn(tens)
>> filtered
(427, 640, 3)
"""
return _autumn_process(tens)
## ROI:(top-left x1,y1, bottom-right x2,y2), shadow_dimension=no. of sides of polygon generated
[docs]def sim_shadow(
tens: Tensor,
num_shadows : int = 1,
rectangular_roi : Tuple = (-1,-1,-1,-1),
shadow_dimension : int = 5
) -> Tensor:
r"""
Simulate shadowy conditions on an image.
Args:
tens (Tensor) : Any regular ``caer.Tensor``.
num_shadows (int): Number of shadows to work with. Value must be between 1 and 10.
rectangular_roi (tuple): Rectanglar co-ordinates of the intended region of interest. Default: (-1,-1,-1,-1).
shadow_dimensions (int): Number of shadow dimensions. Value must be > 3.
Returns:
Tensor of shape ``(height, width, channels)``.
Examples::
>> tens = caer.data.sunrise
>> filtered = caer.filters.sim_shadow(tens)
>> filtered
(427, 640, 3)
"""
if not(is_numeric(num_shadows) and num_shadows >= 1 and num_shadows <= 10):
raise ValueError("Only 1-10 shadows can be introduced in an image")
if not(is_numeric(shadow_dimension) and shadow_dimension >= 3 and shadow_dimension <= 10):
raise ValueError("Polygons with dimensions < 3 don't exist and take time to plot")
if is_tuple(rectangular_roi) and is_numeric_list_or_tuple(rectangular_roi) and len(rectangular_roi)==4:
x1 = rectangular_roi[0]
y1 = rectangular_roi[1]
x2 = rectangular_roi[2]
y2 = rectangular_roi[3]
else:
raise ValueError("Rectangular ROI dimensions are not valid")
if rectangular_roi==(-1,-1,-1,-1):
x1 = 0
if(is_tensor(tens)):
y1 = tens.shape[0] // 2
x2 = tens.shape[1]
y2 = tens.shape[0]
else:
y1 = tens[0].shape[0] // 2
x2 = tens[0].shape[1]
y2 = tens[0].shape[0]
elif x1 == -1 or y1 == -1 or x2 == -1 or y2 == -1 or x2 <= x1 or y2 <= y1:
raise ValueError("Rectangular ROI dimensions are not valid")
return _shadow_process(tens,num_shadows, x1, y1, x2, y2, shadow_dimension)