# Copyright 2022 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Image Blur
"""
import numpy as np
import cv2
from mindarmour.natural_robustness.transform.image.natural_perturb import _NaturalPerturb
from mindarmour.utils._check_param import check_param_multi_types, check_int_positive, check_param_type
from mindarmour.utils.logger import LogUtil
LOGGER = LogUtil.get_instance()
TAG = 'Image Blur'
[文档]class GaussianBlur(_NaturalPerturb):
"""
Blurs the image using Gaussian blur filter.
Args:
ksize (int): Size of gaussian kernel, this value must be non-negnative. Default: ``2``.
auto_param (bool): Auto selected parameters. Selected parameters will preserve semantics of image.
Default: ``False``.
Examples:
>>> import cv2
>>> img = cv2.imread('1.png')
>>> img = np.array(img)
>>> ksize = 5
>>> trans = GaussianBlur(ksize)
>>> dst = trans(img)
"""
def __init__(self, ksize=2, auto_param=False):
super(GaussianBlur, self).__init__()
ksize = check_int_positive('ksize', ksize)
if auto_param:
ksize = 2 * np.random.randint(0, 5) + 1
else:
ksize = 2 * ksize + 1
self.ksize = (ksize, ksize)
def __call__(self, image):
"""
Transform the image.
Args:
image (numpy.ndarray): Original image to be transformed.
Returns:
numpy.ndarray, transformed image.
"""
ori_dtype = image.dtype
_, chw, normalized, gray3dim, image = self._check(image)
new_img = cv2.GaussianBlur(image, self.ksize, 0)
new_img = self._original_format(new_img, chw, normalized, gray3dim)
return new_img.astype(ori_dtype)
[文档]class MotionBlur(_NaturalPerturb):
"""
Motion blur for a given image.
Args:
degree (int): Degree of blur. This value must be positive. Suggested value range in [1, 15].
Default: ``5``.
angle (union[float, int]): Direction of motion blur. Angle=0 means up and down motion blur. Angle is
counterclockwise. Default: ``45``.
auto_param (bool): Auto selected parameters. Selected parameters will preserve semantics of image.
Default: ``False``.
Examples:
>>> import cv2
>>> img = cv2.imread('1.png')
>>> img = np.array(img)
>>> angle = 0
>>> degree = 5
>>> trans = MotionBlur(degree=degree, angle=angle)
>>> new_img = trans(img)
"""
def __init__(self, degree=5, angle=45, auto_param=False):
super(MotionBlur, self).__init__()
self.degree = check_int_positive('degree', degree)
self.degree = check_param_multi_types('degree', degree, [float, int])
auto_param = check_param_type('auto_param', auto_param, bool)
if auto_param:
self.degree = np.random.randint(1, 5)
self.angle = np.random.uniform(0, 360)
else:
self.angle = angle - 45
def __call__(self, image):
"""
Motion blur for a given image.
Args:
image (numpy.ndarray): Original image.
Returns:
numpy.ndarray, image after motion blur.
"""
ori_dtype = image.dtype
_, chw, normalized, gray3dim, image = self._check(image)
matrix = cv2.getRotationMatrix2D((self.degree / 2, self.degree / 2), self.angle, 1)
motion_blur_kernel = np.diag(np.ones(self.degree))
motion_blur_kernel = cv2.warpAffine(motion_blur_kernel, matrix, (self.degree, self.degree))
motion_blur_kernel = motion_blur_kernel / self.degree
blurred = cv2.filter2D(image, -1, motion_blur_kernel)
# convert to uint8
cv2.normalize(blurred, blurred, 0, 255, cv2.NORM_MINMAX)
blurred = self._original_format(blurred, chw, normalized, gray3dim)
return blurred.astype(ori_dtype)
[文档]class GradientBlur(_NaturalPerturb):
"""
Gradient blur.
Args:
point (union[tuple, list]): 2D coordinate of the Blur center point.
kernel_num (int): Number of blur kernels. Suggested value range in [1, 8]. Default: ``3``.
center (bool): Blurred or clear at the center of a specified point.
auto_param (bool): Auto selected parameters. Selected parameters will preserve semantics of image.
Default: ``False``.
Examples:
>>> import cv2
>>> img = cv2.imread('xx.png')
>>> img = np.array(img)
>>> number = 5
>>> h, w = img.shape[:2]
>>> point = (int(h / 5), int(w / 5))
>>> center = True
>>> trans = GradientBlur(point, number, center)
>>> new_img = trans(img)
"""
def __init__(self, point, kernel_num=3, center=True, auto_param=False):
super(GradientBlur).__init__()
point = check_param_multi_types('point', point, [list, tuple])
self.auto_param = check_param_type('auto_param', auto_param, bool)
self.point = tuple(point)
self.kernel_num = check_int_positive('kernel_num', kernel_num)
self.center = check_param_type('center', center, bool)
def _auto_param(self, h, w):
self.point = (int(np.random.uniform(0, h)), int(np.random.uniform(0, w)))
self.kernel_num = np.random.randint(1, 6)
self.center = np.random.choice([True, False])
def __call__(self, image):
"""
Args:
image (numpy.ndarray): Original image.
Returns:
numpy.ndarray, gradient blurred image.
"""
ori_dtype = image.dtype
_, chw, normalized, gray3dim, image = self._check(image)
w, h = image.shape[:2]
if self.auto_param:
self._auto_param(h, w)
mask = np.zeros(image.shape, dtype=np.uint8)
masks = []
radius = max(w - self.point[0], self.point[0], h - self.point[1], self.point[1])
radius = int(radius / self.kernel_num)
for i in range(self.kernel_num):
circle = cv2.circle(mask.copy(), self.point, radius * (1 + i), (1, 1, 1), -1)
masks.append(circle)
blurs = []
for i in range(3, 3 + 2 * self.kernel_num, 2):
ksize = (i, i)
blur = cv2.GaussianBlur(image, ksize, 0)
blurs.append(blur)
dst = image.copy()
if self.center:
for i in range(self.kernel_num):
dst = masks[i] * dst + (1 - masks[i]) * blurs[i]
else:
for i in range(self.kernel_num - 1, -1, -1):
dst = masks[i] * blurs[self.kernel_num - 1 - i] + (1 - masks[i]) * dst
dst = self._original_format(dst, chw, normalized, gray3dim)
return dst.astype(ori_dtype)