import random
import cv2
import numpy as np
from augraphy.base.augmentation import Augmentation
from augraphy.utilities.overlaybuilder import OverlayBuilder
[docs]
class LCDScreenPattern(Augmentation):
"""Creates a LCD Screen Pattern effect by overlaying different line patterns into image.
:param pattern_type: Types of pattern. Use "random" for random pattern.
Select from "Vertical", "Horizontal", "Forward_Diagonal", "Back_Diagonal" and "Cross".
:type pattern_type: string, optional
:param pattern_value_range: Tuple of ints determining the value of the pattern.
:type pattern_value_range: tuple, optional
:param pattern_skip_distance_range: Tuples of ints determining the distance between lines in each pattern.
This is not valid for pattern type of "Cross".
:type pattern_skip_distance_range: tuple, optional
:param pattern_overlay_method: The method to overlay pattern into image using OverlayBuilder.
The default value is "darken".
:type pattern_overlay_method: string, optional
:param pattern_overlay_alpha: The alpha value for the overlay method uses alpha value.
:type pattern_overlay_alpha: float, optional
:param p: The probability this Augmentation will be applied.
:type p: float, optional
"""
def __init__(
self,
pattern_type="random",
pattern_value_range=(0, 16),
pattern_skip_distance_range=(3, 5),
pattern_overlay_method="darken",
pattern_overlay_alpha=0.3,
p=1,
):
"""Constructor method"""
super().__init__(p=p)
self.pattern_type = pattern_type
self.pattern_value_range = pattern_value_range
self.pattern_skip_distance_range = pattern_skip_distance_range
self.pattern_overlay_method = pattern_overlay_method
self.pattern_overlay_alpha = pattern_overlay_alpha
def __repr__(self):
return f"LCDScreenPattern(pattern_type={self.pattern_type}, pattern_value_range={self.pattern_value_range}, pattern_skip_distance_range={self.pattern_skip_distance_range}, pattern_overlay_method={self.pattern_overlay_method}, pattern_overlay_alpha={self.pattern_overlay_alpha}, p={self.p})"
def __call__(self, image, layer=None, mask=None, keypoints=None, bounding_boxes=None, force=False):
if force or self.should_run():
image = image.copy()
# check and convert image into BGR format
has_alpha = 0
if len(image.shape) > 2:
is_gray = 0
if image.shape[2] == 4:
has_alpha = 1
image, image_alpha = image[:, :, :3], image[:, :, 3]
else:
is_gray = 1
image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
ysize, xsize = image.shape[:2]
# get types of pattern
if self.pattern_type == "random":
pattern_type = random.choice(["Vertical", "Horizontal", "Forward_Diagonal", "Back_Diagonal", "Cross"])
else:
pattern_type = self.pattern_type
# get value
value = random.randint(self.pattern_value_range[0], self.pattern_value_range[1])
# initialize image
image_pattern = np.full_like(image, fill_value=255, dtype="uint8")
pattern_skip_distance = random.randint(
self.pattern_skip_distance_range[0],
self.pattern_skip_distance_range[1],
)
if pattern_type == "Vertical":
image_pattern[:, ::pattern_skip_distance] = value
elif pattern_type == "Horizontal":
image_pattern[::pattern_skip_distance, :] = value
elif pattern_type == "Forward_Diagonal":
# minimum skip size
pattern_skip_distance = max(3, pattern_skip_distance)
y, x = np.meshgrid(np.arange(ysize), np.arange(xsize), indexing="ij")
# Create diagonal lines pattern
image_pattern = ((x + y) % pattern_skip_distance == 0).astype(np.uint8) * 255
image_pattern = 255 - image_pattern
image_pattern[image_pattern == 0] = value
# Convert from gray to BGR
if len(image.shape) > 2:
image_pattern = cv2.cvtColor(image_pattern, cv2.COLOR_GRAY2BGR)
elif pattern_type == "Back_Diagonal":
# minimum skip size
pattern_skip_distance = max(3, pattern_skip_distance)
y, x = np.meshgrid(np.arange(ysize), np.arange(xsize), indexing="ij")
# Create diagonal lines pattern
image_pattern = ((x - y) % pattern_skip_distance == 0).astype(np.uint8) * 255
image_pattern = 255 - image_pattern
image_pattern[image_pattern == 0] = value
# Convert from gray to BGR
if len(image.shape) > 2:
image_pattern = cv2.cvtColor(image_pattern, cv2.COLOR_GRAY2BGR)
else:
image_pattern[::2, ::2] = value
image_pattern[1::2, 1::2] = value
# blend pattern into image
ob = OverlayBuilder(
self.pattern_overlay_method,
image_pattern,
image,
1,
(1, 1),
"center",
0,
self.pattern_overlay_alpha,
)
image_output = ob.build_overlay()
# return image follows the input image color channel
if is_gray:
image_output = cv2.cvtColor(image_output, cv2.COLOR_BGR2GRAY)
if has_alpha:
image_output = np.dstack((image_output, image_alpha))
# check for additional output of mask, keypoints and bounding boxes
outputs_extra = []
if mask is not None or keypoints is not None or bounding_boxes is not None:
outputs_extra = [mask, keypoints, bounding_boxes]
# returns additional mask, keypoints and bounding boxes if there is additional input
if outputs_extra:
# returns in the format of [image, mask, keypoints, bounding_boxes]
return [image_output] + outputs_extra
else:
return image_output