Skip to content

Commit

Permalink
Merge pull request #420 from kwcckw/dev
Browse files Browse the repository at this point in the history
Added DepthSimulatedBlur.
  • Loading branch information
kwcckw authored Dec 21, 2023
2 parents 319135e + a7851d5 commit 1bc4d12
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 0 deletions.
2 changes: 2 additions & 0 deletions augraphy/augmentations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from augraphy.augmentations.colorpaper import ColorPaper
from augraphy.augmentations.colorshift import ColorShift
from augraphy.augmentations.delaunay import DelaunayTessellation
from augraphy.augmentations.depthsimulatedblur import DepthSimulatedBlur
from augraphy.augmentations.dirtydrum import DirtyDrum
from augraphy.augmentations.dirtyrollers import DirtyRollers
from augraphy.augmentations.dirtyscreen import DirtyScreen
Expand Down Expand Up @@ -58,6 +59,7 @@
"ColorPaper",
"ColorShift",
"DelaunayTessellation",
"DepthSimulatedBlur",
"DirtyDrum",
"DirtyRollers",
"DirtyScreen",
Expand Down
125 changes: 125 additions & 0 deletions augraphy/augmentations/depthsimulatedblur.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import random

import cv2
import numpy as np

from augraphy.base.augmentation import Augmentation


class DepthSimulatedBlur(Augmentation):
"""Creates a depth-simulated blur effect from a camera by blurring a small elliptical region of image.
:param blur_centerr: Center (x,y) of blur effect. Use "random" for random location.
:type blur_center: tuple or string, optional
:param blur_major_axes_length_range: Pair of ints determining the value of major axis in the blurring ellipse.
:type blur_major_axes_length_range: tuple, optional
:param blur_minor_axes_length_range: Pair of ints determining the value of minor axis in the blurring ellipse.
:type blur_minor_axes_length_range: tuple, optional
:param p: The probability this Augmentation will be applied.
:type p: float, optional
"""

def __init__(
self,
blur_center="random",
blur_major_axes_length_range=(120, 200),
blur_minor_axes_length_range=(120, 200),
p=1,
):
super().__init__(p=p)
self.blur_center = blur_center
self.blur_major_axes_length_range = blur_major_axes_length_range
self.blur_minor_axes_length_range = blur_minor_axes_length_range

# Constructs a string representation of this Augmentation.
def __repr__(self):
return f"DepthSimulatedBlur(blur_center={self.blur_center}, blur_major_axes_length_range={self.blur_major_axes_length_range}, blur_minor_axes_length_range={self.blur_minor_axes_length_range}, p={self.p})"

# Applies the Augmentation to input data.
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]

# initial gaussian kernel value, will be incremented per iteration
kernel_value = 3
gaussian_kernel = [kernel_value, kernel_value]

axes_major = random.randint(self.blur_major_axes_length_range[0], self.blur_major_axes_length_range[1])
axes_minor = random.randint(self.blur_minor_axes_length_range[0], self.blur_minor_axes_length_range[1])

if self.blur_center == "random":
center_x = random.randint(0, xsize)
center_y = random.randint(0, ysize)
else:
center_x = self.blur_center[0]
center_y = self.blur_center[0]

step = 10
decremental_value = 10
angle = random.randint(0, 360) # Angle of rotation (in degrees)
center_coordinates = (center_x, center_y)
color = (255, 255, 255) # BGR color (here, blue)
thickness = -1 # Line thickness

image_output = image.copy()

# it still run slow now, need further optimization
for i in range(step):

image_ellipse = np.zeros_like(image, dtype="uint8")

axes_length = (axes_major, axes_minor) # Major and minor axes lengths

# Draw the oval on the image
cv2.ellipse(image_ellipse, center_coordinates, axes_length, angle, 0, 360, color, thickness)

# blur image
image_blur = cv2.GaussianBlur(image, gaussian_kernel, 0)

# blend blur region into image
image_output = cv2.seamlessClone(
image_output,
image_blur,
255 - image_ellipse,
(int(xsize / 2), int(ysize / 2)),
cv2.NORMAL_CLONE,
)

# increase gaussian kernel size
gaussian_kernel[0] += 4
gaussian_kernel[1] += 4

# increase major and minor length
axes_major = max(axes_major - decremental_value, 1)
axes_minor = max(axes_minor - decremental_value, 1)

# 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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
64 changes: 64 additions & 0 deletions doc/source/augmentations/depthsimulatedblur.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
******************
DepthSimulatedBlur
******************

.. autoclass:: augraphy.augmentations.depthsimulatedblur.DepthSimulatedBlur
:members:
:undoc-members:
:show-inheritance:

--------
Overview
--------
The DepthSimulatedBlur augmentation creates a depth-simulated blur effect from a camera by blurring a small elliptical region of image

Initially, a clean image with single line of text is created.

Code example:

::

# import libraries
import cv2
import numpy as np
from augraphy import *


# create a clean image with single line of text
image = np.full((500, 1500,3), 250, dtype="uint8")
cv2.putText(
image,
"Lorem ipsum dolor sit amet, consectetur adipiscing elit",
(80, 250),
cv2.FONT_HERSHEY_SIMPLEX,
1.5,
0,
3,
)

cv2.imshow("Input image", image)

Clean image:

.. figure:: augmentations/input.png

---------
Example 1
---------
In this example, a DepthSimulatedBlur augmentation instance is initialized and blur center is set to random location (blur_center = "random"). The blurring ellipse's major and minor axes are to random value in between 120 and 200 (120,200).

Code example:

::

depthsimulatedblur = DepthSimulatedBlur(blur_center = "random",
blur_major_axes_length_range = (120, 200),
blur_minor_axes_length_range = (120, 200),
)

img_depthsimulatedblur = depthsimulatedblur(image)
cv2.imshow("depthsimulatedblur", img_depthsimulatedblur)

Augmented image:

.. figure:: augmentations/depthsimulatedblur/depth_simulated_blur.png
1 change: 1 addition & 0 deletions doc/source/list_of_augmentations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Pixel Level Augmentations
augmentations/colorpaper.rst
augmentations/colorshift.rst
augmentations/delaunay.rst
augmentations/depthsimulatedblur.rst
augmentations/dirtydrum.rst
augmentations/dirtyrollers.rst
augmentations/dirtyscreen.rst
Expand Down

0 comments on commit 1bc4d12

Please sign in to comment.