未完成
测试图片使用lena,下载地址:https://www.ece.rice.edu/~wakin/images/lena512color.tiff
起名为util.py
,下面某些退化函数需要用到该文件。
# -*- coding: utf-8 -*-
import numpy as np
def float_to_uint8(image, scale=255.0):
"""
Convert image from float type to uint8, meanwhile the clip between [0, 255]
will be done.
Parameters
----------
image: numpy array image data of float type
scale: a scale factor for image data
Returns
-------
image_uint8: numpy array image data of uint8 type
"""
image_uint8 = np.clip(np.round(image * scale), 0, 255).astype(np.uint8)
return image_uint8
def get_noise_index(image, noise_num_ratio):
"""
Get noise index for a certain ratio of noise number
Parameters
----------
image: numpy array image data
noise_num_ratio: ratio of noise number with respect to the total number of
pixels, between [0, 1]
Returns
-------
row: row indexes
col: column indexes
"""
image_height, image_width = image.shape[0:2]
noise_num = int(np.round(image_height * image_width * noise_num_ratio))
row = np.random.randint(0, image_height, noise_num)
col = np.random.randint(0, image_width, noise_num)
return row, col
def get_noise_shape(image, speckle_size=1.0):
"""
Get noise shape according to image shape.
Parameters
----------
image: numpy image data, shape is [H, W, C], C is optional
speckle_size: speckle size of noise
Returns
-------
noise_shape: a tuple whose length is 3
The shape of noise. Let height, width be the image height and width.
If image.ndim is 2, output noise_shape will be (height, width, 1),
else (height, width, 3)
"""
if speckle_size > np.min(image.shape[:2]):
raise ValueError("speckle_size can NOT be larger than the min of "
"(image_height, image_width)")
if image.ndim == 2:
noise_shape = np.array(image.shape)
else:
noise_shape = np.array([*image.shape[:2], 3])
if speckle_size > 1.0:
noise_shape[0] = int(round(noise_shape[0] / speckle_size))
noise_shape[1] = int(round(noise_shape[1] / speckle_size))
return noise_shape
def add_noise(image, noise, noise_num_ratio=1.0):
"""
Add noise to image.
Parameters
----------
image: numpy image data, shape is [H, W, C], C is optional
noise: additive noise, same shape as 'image'
noise_num_ratio: ratio of noise number with respect to the total number of
pixels, between [0, 1]
Returns
-------
noisy_image: image with noise
"""
if not 0.0 <= noise_num_ratio <= 1.0:
raise ValueError('noise_num_ratio must between [0, 1]')
# preprocess noise
if noise.ndim == 2:
noise = np.expand_dims(noise, axis=2)
channel = noise.shape[2]
# initialize noisy_image
noisy_image = image.copy().astype(np.float32)
if noisy_image.ndim == 2:
noisy_image = np.expand_dims(noisy_image, axis=2)
# add noise to noisy_image
if noise_num_ratio >= 1.0:
noisy_image[:, :, :channel] += noise
else:
row, col = get_noise_index(image, noise_num_ratio)
noisy_image[row, col, :channel] += noise[row, col, ...]
# post processing for dtype and shape
if image.dtype == np.uint8:
noisy_image = float_to_uint8(noisy_image, scale=1.0)
else:
noisy_image = noisy_image.astype(image.dtype)
noisy_image = np.squeeze(noisy_image)
return noisy_image
噪音由拍摄过程中的随机因素引入,在算法上我们使用随机数进行模拟。
关于噪音一般需要考虑如下几个因素:
下面介绍4中图像处理中常用的噪音,分别是高斯噪音,均匀噪音,泊松噪音,椒盐噪音。其中高斯噪音和均匀噪音既可以设置成加性,也可以设置为乘性。
针对每个噪音类型,我会从两个维度(彩色图,带alpha通道的彩色图,灰度图) * (彩色噪音,灰度噪音)
给出6个测试图片。从外观表现上来看,带alpha通道的彩图与普通彩图加上噪音后没什么区别,测这样的图只是为了看看程序的健壮性如何。
自然界的过程大多是高斯的,比如元器件尺寸与标准尺寸的差异分布。再加上多个随机过程(即便非高斯过程)的叠加一般也是高斯分布,所以高斯噪音几乎是一定存在的。
下面图中彩色噪声的颗粒搞得比较大,夸张了点,实际上一般不会有这么大颗粒的噪音,这里只是为了测试。在灰度图中,即便参数设置为加彩噪,最后实际上也会退化成加灰度噪音。
下面是加高斯噪音的代码,控制高斯噪音强弱的关键参数是sigma,是高斯随机数的标准差。
# -*- coding: utf-8 -*-
import cv2
import numpy as np
from util import get_noise_shape
from util import add_noise
def generate_gaussian_noise(image,
sigma,
is_gray=False,
speckle_size=1.0,
multiplicative=False):
"""
Generate gaussian distributed noise.
Parameters
----------
image: numpy image data, shape is [H, W, C], C is optional
sigma: standard deviation of gaussian random numbers
is_gray: whether the noise is color or gray
speckle_size: speckle size of noise
multiplicative: whether to add additive noise or multiplicative noise
Returns
-------
noise: gaussian noise
"""
noise_shape = get_noise_shape(image, speckle_size)
# generate noise
if is_gray:
noise = np.random.normal(0.0, sigma, size=noise_shape[0:2])
if image.ndim == 3:
noise = np.expand_dims(noise, axis=2).repeat(3, axis=2)
else:
noise = np.random.normal(0.0, sigma, size=noise_shape)
# resize noise to keep same size as image
if speckle_size > 1.0:
interp_type = np.random.choice([cv2.INTER_CUBIC, cv2.INTER_LINEAR])
noise = cv2.resize(noise, dsize=image.shape[:2], fx=None, fy=None,
interpolation=interp_type)
noise = noise.astype(np.float32)
# make multiplicative noise if needed
if multiplicative:
if noise.ndim == 3:
channel = noise.shape[2]
noise *= np.float32(image[..., :channel])
else:
noise *= np.float32(image)
return noise
def add_gaussian_noise(image,
sigma,
is_gray=False,
speckle_size=1.0,
noise_num_ratio=1.0,
multiplicative=False):
"""
Add gaussian noise to image.
Parameters
----------
image: numpy image data, shape is [H, W, C], C is optional
sigma: standard deviation of gaussian random numbers
is_gray: whether the noise is color or gray
speckle_size: speckle size of noise
noise_num_ratio: ratio of noise number with respect to the total number of
pixels, between [0, 1]
multiplicative: whether to add additive noise or multiplicative noise
Returns
-------
noisy_image: image after adding noise
"""
if sigma < 0:
raise ValueError('sigma must >= 0.0')
noise = generate_gaussian_noise(image,
sigma=sigma,
is_gray=is_gray,
speckle_size=speckle_size,
multiplicative=multiplicative)
noisy_image = add_noise(image,
noise=noise,
noise_num_ratio=noise_num_ratio)
return noisy_image
if __name__ == '__main__':
# choose one of the following parameter set
MULTI = True
SIGMA = 0.1
# MULTI = False
# SIGMA = 25
# read original image / gray scale image / image with alpha channel
image = cv2.imread('lena512color.tiff')
image_gray = cv2.imread('lena512color.tiff', cv2.IMREAD_GRAYSCALE)
alpha = np.ones((*image.shape[:2], 1), dtype=np.uint8) * 255
image_alpha = np.concatenate((image, alpha), axis=2) # 4 channel
# generate noisy image
noisy_image = add_gaussian_noise(image, SIGMA, False, 10.0, 1.0, MULTI)
cv2.imwrite('gaussian_noise_color_image_color_noise.png', noisy_image)
noisy_image = add_gaussian_noise(image_gray, SIGMA, False, 10.0, 1.0,
MULTI)
cv2.imwrite('gaussian_noise_gray_image_color_noise.png', noisy_image)
noisy_image = add_gaussian_noise(image_alpha, SIGMA, False, 10.0, 1.0,
MULTI)
cv2.imwrite('gaussian_noise_alpha_image_color_noise.png', noisy_image)
noisy_image = add_gaussian_noise(image, SIGMA, True, 2.5, 1.0, MULTI)
cv2.imwrite('gaussian_noise_color_image_gray_noise.png', noisy_image)
noisy_image = add_gaussian_noise(image_gray, SIGMA, True, 2.5, 1.0, MULTI)
cv2.imwrite('gaussian_noise_gray_image_gray_noise.png', noisy_image)
noisy_image = add_gaussian_noise(image_alpha, SIGMA, True, 2.5, 1.0, MULTI)
cv2.imwrite('gaussian_noise_alpha_image_gray_noise.png', noisy_image)
我也不清楚图像中什么情况下会出现均匀随机噪音,且当作一种能增加点随机性的退化手段吧。这个搞法跟高斯那部分几乎一样,只是生成噪音的随机数不一样,另外控制噪音的参数也不一样,均匀噪音直接用上下限来控制强弱。
乘性均匀噪音的图就略了,肉眼也看不出太大区别。
代码如下:
# -*- coding: utf-8 -*-
import cv2
import numpy as np
from util import get_noise_shape
from util import add_noise
def generate_uniform_noise(image,
limit,
is_gray=False,
speckle_size=1.0,
multiplicative=False):
"""
Generate uniform distributed noise.
Parameters
----------
image: numpy image data, shape is [H, W, C], C is optional
limit: limit of uniform random number
is_gray: whether the noise is color or gray
speckle_size: speckle size of noise
multiplicative: whether to add additive noise or multiplicative noise
Returns
-------
noise: uniform noise
"""
noise_shape = get_noise_shape(image, speckle_size)
# generate noise
if is_gray:
noise = np.random.uniform(-limit, limit, size=noise_shape[0:2])
if image.ndim == 3:
noise = np.expand_dims(noise, axis=2).repeat(3, axis=2)
else:
noise = np.random.uniform(-limit, limit, size=noise_shape)
# resize noise to keep same size as image
if speckle_size > 1.0:
interp_type = np.random.choice([cv2.INTER_CUBIC, cv2.INTER_LINEAR])
noise = cv2.resize(noise, dsize=image.shape[:2], fx=None, fy=None,
interpolation=interp_type)
noise = noise.astype(np.float32)
# make multiplicative noise if needed
if multiplicative:
if noise.ndim == 3:
channel = noise.shape[2]
noise *= np.float32(image[..., :channel])
else:
noise *= np.float32(image)
return noise
def add_uniform_noise(image,
limit,
is_gray=False,
speckle_size=1.0,
noise_num_ratio=1.0,
multiplicative=False):
"""
Add uniform noise to image.
Parameters
----------
image: numpy image data, shape is [H, W, C], C is optional
limit: limit of uniform random number
is_gray: whether the noise is color or gray
speckle_size: speckle size of noise
noise_num_ratio: ratio of noise number with respect to the total number of
pixels, between [0, 1]
multiplicative: whether to add additive noise or multiplicative noise
Returns
-------
noisy_image: image after adding noise
"""
if limit < 0:
raise ValueError('limit must >= 0.0')
noise = generate_uniform_noise(image,
limit=limit,
is_gray=is_gray,
speckle_size=speckle_size,
multiplicative=multiplicative)
noisy_image = add_noise(image,
noise=noise,
noise_num_ratio=noise_num_ratio)
return noisy_image
if __name__ == '__main__':
# choose one of the following parameter set
MULTI = True
LIMIT = 0.1
# MULTI = False
# LIMIT = 25
# read original image / gray scale image / image with alpha channel
image = cv2.imread('lena512color.tiff')
image_gray = cv2.imread('lena512color.tiff', cv2.IMREAD_GRAYSCALE)
alpha = np.ones((*image.shape[:2], 1), dtype=np.uint8) * 255
image_alpha = np.concatenate((image, alpha), axis=2) # 4 channel
# generate noisy image
noisy_image = add_uniform_noise(image, LIMIT, False, 10.0, 1.0, MULTI)
cv2.imwrite('uniform_noise_color_image_color_noise.png', noisy_image)
noisy_image = add_uniform_noise(image_gray, LIMIT, False, 10.0, 1.0,
MULTI)
cv2.imwrite('uniform_noise_gray_image_color_noise.png', noisy_image)
noisy_image = add_uniform_noise(image_alpha, LIMIT, False, 10.0, 1.0,
MULTI)
cv2.imwrite('uniform_noise_alpha_image_color_noise.png', noisy_image)
noisy_image = add_uniform_noise(image, LIMIT, True, 2.5, 1.0, MULTI)
cv2.imwrite('uniform_noise_color_image_gray_noise.png', noisy_image)
noisy_image = add_uniform_noise(image_gray, LIMIT, True, 2.5, 1.0, MULTI)
cv2.imwrite('uniform_noise_gray_image_gray_noise.png', noisy_image)
noisy_image = add_uniform_noise(image_alpha, LIMIT, True, 2.5, 1.0, MULTI)
cv2.imwrite('uniform_noise_alpha_image_gray_noise.png', noisy_image)
泊松噪音是一种计数噪音,比如电话接线员没小时可能接起电话的次数,饭店每天可能接到的外卖订单个数等等。这个变量肯定有一个期望,但是实际的数字在期望附近上下波动,波动的结果就是针对这个期望产生的泊松随机数。
对图像而言,泊松噪音模拟了光子打到传感器的随机过程,这是一个计数过程,所以用泊松过程来模拟。泊松噪音的输入是图像本身(的像素值),输出就是加了泊松噪音的图像,而不是单纯的噪音。但是通过这种方式加泊松噪音无法调节强弱,所以本文档的做法是先使用带有泊松噪音的图像减去原图像,得到噪音,然后给噪音乘上一个系数,最后再加回到原图像,这样就可以利用系数来调节噪音强弱。
请注意,由于泊松噪音是计数噪音,所以泊松噪音的输入必需是uint8类型的图像,数值区间得是[0, 255],不能是[0, 1]范围那种。
光从表面来看的话,跟高斯和均匀噪音傻傻分不清。。。
代码如下:
# -*- coding: utf-8 -*-
import cv2
import numpy as np
from util import get_noise_shape
from util import add_noise
def generate_poisson_noise(image,
scale,
is_gray=False,
speckle_size=1.0):
"""
Generate poisson distributed noise.
Parameters
----------
image: numpy image data, shape is [H, W, C], C is optional
scale: scale multiplied to poisson noise
is_gray: whether the noise is color or gray
speckle_size: speckle size of noise
Returns
-------
noise: poisson noise
"""
# preprocess image
image_temp = image.copy()
if image_temp.ndim == 3 and image_temp.shape[2] > 3:
image_temp = image_temp[:, :, :3]
ndim = image.ndim
if is_gray and ndim == 3:
image_temp = cv2.cvtColor(image_temp, cv2.COLOR_BGR2GRAY)
noise_shape = get_noise_shape(image, speckle_size)
if np.any(image_temp.shape[:2] != noise_shape[:2]):
image_temp = cv2.resize(image_temp, dsize=noise_shape[:2],
fx=None, fy=None, interpolation=cv2.INTER_AREA)
# generate noise
noisy_image = np.float32(np.random.poisson(image_temp))
noise = noisy_image - image_temp
if is_gray and ndim == 3:
noise = np.expand_dims(noise, axis=2).repeat(3, axis=2)
noise *= scale
# resize noise to keep same size as image
if speckle_size > 1.0:
interp_type = np.random.choice([cv2.INTER_CUBIC, cv2.INTER_LINEAR])
noise = cv2.resize(noise, dsize=image.shape[:2], fx=None, fy=None,
interpolation=interp_type)
return noise
def add_poisson_noise(image,
scale,
is_gray=False,
speckle_size=1.0,
noise_num_ratio=1.0):
"""
Add poisson noise to image.
Parameters
----------
image: numpy image data, shape is [H, W, C], C is optional
scale: scale multiplied to poisson noise
is_gray: whether the noise is color or gray
speckle_size: speckle size of noise
noise_num_ratio: ratio of noise number with respect to the total number of
pixels, between [0, 1]
Returns
-------
noisy_image: image after adding noise
"""
if scale < 0:
raise ValueError('scale must >= 0.0')
noise = generate_poisson_noise(image,
scale=scale,
is_gray=is_gray,
speckle_size=speckle_size)
noisy_image = add_noise(image,
noise=noise,
noise_num_ratio=noise_num_ratio)
return noisy_image
if __name__ == '__main__':
SCALE = 1.0
# read original image / gray scale image / image with alpha channel
image = cv2.imread('lena512color.tiff')
image_gray = cv2.imread('lena512color.tiff', cv2.IMREAD_GRAYSCALE)
alpha = np.ones((*image.shape[:2], 1), dtype=np.uint8) * 255
image_alpha = np.concatenate((image, alpha), axis=2) # 4 channel
# generate noisy image
noisy_image = add_poisson_noise(image, SCALE, False, 10.0, 1.0)
cv2.imwrite('poisson_noise_color_image_color_noise.png', noisy_image)
noisy_image = add_poisson_noise(image_gray, SCALE, False, 10.0, 1.0)
cv2.imwrite('poisson_noise_gray_image_color_noise.png', noisy_image)
noisy_image = add_poisson_noise(image_alpha, SCALE, False, 10.0, 1.0)
cv2.imwrite('poisson_noise_alpha_image_color_noise.png', noisy_image)
noisy_image = add_poisson_noise(image, SCALE, True, 2.5, 1.0)
cv2.imwrite('poisson_noise_color_image_gray_noise.png', noisy_image)
noisy_image = add_poisson_noise(image_gray, SCALE, True, 2.5, 1.0)
cv2.imwrite('poisson_noise_gray_image_gray_noise.png', noisy_image)
noisy_image = add_poisson_noise(image_alpha, SCALE, True, 2.5, 1.0)
cv2.imwrite('poisson_noise_alpha_image_gray_noise.png', noisy_image)
椒盐噪音可能是图像在拍摄成像的过程中受到了非常强的干扰,从而导致图像上出现的一些过大或过小的值,如果是在灰度图上,那么就是白色或者黑色的噪点,就像是盐(白)和胡椒(黑)颗粒一样,所以称为椒盐噪音。
(终于来了一个有辨识度的噪音,椒盐噪音很容易认出来)
在下面代码中,我将椒盐的值设置为参数的形式,也就是说用户可以进行调节,不一定非得让盐=255,椒=0。
# -*- coding: utf-8 -*-
import cv2
import numpy as np
from util import get_noise_shape
def generate_salt_pepper_noise_mask(image,
is_gray=False,
noise_num_ratio=0.1,
speckle_size=1.0,
salt_ratio=0.5):
"""
Generate a mask for salt pepper noise.
Parameters
----------
image: image data read by opencv, shape is [H, W, C]
is_gray: whether the noise is color or gray
noise_num_ratio: ratio of noise number with respect to the total number of
pixels, between [0, 1]
speckle_size: speckle size of noise
salt_ratio: ratio of salt number with respect to the total number of noise
pixels
Returns
-------
mask: mask for salt pepper noise. Positive values in mask is corresponding
to position of salt noise, whereas negative values is corresponding to
position of pepper noise.
"""
if not 0.0 <= noise_num_ratio <= 1.0:
raise ValueError('noise_num_ratio must between [0, 1]')
if not 0.0 <= salt_ratio <= 1.0:
raise ValueError('salt_ratio must between [0, 1]')
# get noise num. Noise num is computed by noise_shape, which is affected
# by speckle_size
noise_shape = get_noise_shape(image, speckle_size)
pixel_num = np.prod(noise_shape[0:2])
noise_num = pixel_num * noise_num_ratio
salt_num = int((noise_num * salt_ratio))
pepper_num = int(np.round(noise_num * (1 - salt_ratio)))
# get mask
salt_index = []
pepper_index = []
if is_gray:
mask = np.zeros(noise_shape[:2], dtype=np.int32)
for shape in noise_shape[:2]:
salt_index.append(np.random.randint(0, shape, salt_num))
pepper_index.append(np.random.randint(0, shape, pepper_num))
mask[tuple(salt_index)] = 1
mask[tuple(pepper_index)] = -1
if image.ndim == 3 and image.shape[2] > 3:
mask = np.expand_dims(mask, axis=2).repeat(3, axis=2)
else:
mask = np.zeros(noise_shape, dtype=np.int32)
for shape in noise_shape:
salt_index.append(np.random.randint(0, shape, salt_num))
pepper_index.append(np.random.randint(0, shape, pepper_num))
mask[tuple(salt_index)] = 1
mask[tuple(pepper_index)] = -1
if speckle_size > 1.0:
# mask should be converted to float type before using cv2.resize
mask = mask.astype(np.float32)
interp_type = np.random.choice(
[cv2.INTER_CUBIC, cv2.INTER_LINEAR, cv2.INTER_NEAREST])
mask = cv2.resize(mask, dsize=image.shape[:2], fx=None, fy=None,
interpolation=interp_type)
mask = np.round(mask).astype(np.int32)
return mask
def add_salt_pepper_noise(image,
is_gray=False,
noise_num_ratio=0.1,
speckle_size=1.0,
salt_value=255,
pepper_value=0,
salt_ratio=0.5):
"""
Add salt and pepper nosie to image.
Parameters
----------
image: image data read by opencv, shape is [H, W, C]
is_gray: whether the noise is color or gray
noise_num_ratio: ratio of noise number with respect to the total number of
pixels, between [0, 1]
speckle_size: speckle size of noise
salt_value: value of salt noise
pepper_value: value of pepper noise
salt_ratio: ratio of salt number with respect to the total number of noise
pixels
Returns
-------
noisy_image: image after adding noise
"""
mask = generate_salt_pepper_noise_mask(image,
is_gray=is_gray,
noise_num_ratio=noise_num_ratio,
speckle_size=speckle_size,
salt_ratio=salt_ratio)
# add noise
noisy_image = image.copy()
if noisy_image.ndim == 3 and noisy_image.shape[2] > 3:
noisy_image[:, :, :3][mask > 0] = salt_value
noisy_image[:, :, :3][mask < 0] = pepper_value
else:
noisy_image[mask > 0] = salt_value
noisy_image[mask < 0] = pepper_value
noisy_image = np.squeeze(noisy_image)
return noisy_image
if __name__ == '__main__':
# read original image / gray scale image / image with alpha channel
image = cv2.imread('lena512color.tiff')
image_gray = cv2.imread('lena512color.tiff', cv2.IMREAD_GRAYSCALE)
alpha = np.ones((*image.shape[:2], 1), dtype=np.uint8) * 255
image_alpha = np.concatenate((image, alpha), axis=2) # 4 channel
# generate noisy image
noisy_image = add_salt_pepper_noise(image, False, 0.1, 5.0)
cv2.imwrite('salt_pepper_noise_color_image_color_noise.png', noisy_image)
noisy_image = add_salt_pepper_noise(image_gray, False, 0.1, 5.0)
cv2.imwrite('salt_pepper_noise_gray_image_color_noise.png', noisy_image)
noisy_image = add_salt_pepper_noise(image_alpha, False, 0.1, 5.0)
cv2.imwrite('salt_pepper_noise_alpha_image_color_noise.png', noisy_image)
noisy_image = add_salt_pepper_noise(image, True, 0.1, 1.5)
cv2.imwrite('salt_pepper_noise_color_image_gray_noise.png', noisy_image)
noisy_image = add_salt_pepper_noise(image_gray, True, 0.1, 1.5)
cv2.imwrite('salt_pepper_noise_gray_image_gray_noise.png', noisy_image)
noisy_image = add_salt_pepper_noise(image_alpha, True, 0.1, 1.5)
cv2.imwrite('salt_pepper_noise_alpha_image_gray_noise.png', noisy_image)
# -*- coding: utf-8 -*-
import cv2
import numpy as np
if __name__ == '__main__':
# read image
image = cv2.imread('lena512color.tiff')
image_gray = cv2.imread('lena512color.tiff', cv2.IMREAD_GRAYSCALE)
alpha = np.ones((*image.shape[:2], 1), dtype=np.uint8) * 255
image_alpha = np.concatenate((image, alpha), axis=2)
# the following image can be changed to image_gray or image_alpha
blur_image = cv2.GaussianBlur(image, ksize=(5, 5), sigmaX=2, sigmaY=2)
cv2.imshow('original_image', image)
cv2.imshow('gaussian_blur_image', blur_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
# -*- coding: utf-8 -*-
import cv2
import numpy as np
if __name__ == '__main__':
# read image
image = cv2.imread('lena512color.tiff')
image_gray = cv2.imread('lena512color.tiff', cv2.IMREAD_GRAYSCALE)
alpha = np.ones((*image.shape[:2], 1), dtype=np.uint8) * 255
image_alpha = np.concatenate((image, alpha), axis=2)
# the following image can be changed to image_gray or image_alpha
blur_image = cv2.boxFilter(image, ddepth=-1, ksize=(5, 7))
cv2.imshow('original_image', image)
cv2.imshow('box_blur_image', blur_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
# -*- coding: utf-8 -*-
import cv2
import numpy as np
def motion_blur(image, kernel_length, angle):
"""
Apply motion blur to image.
Parameters
----------
image: image data read by opencv, shape is [H, W, C]
kernel_length: motion trajectory length of blur kernel
angle: motion trajectory angle
Returns
-------
blur_image: image after blurring
"""
if not (0 <= angle <= 180):
raise ValueError('angle should between [0, 180]')
# preprocess angle and get step along angle direction
horizontal_flip = False
if angle > 90:
angle = 180 - angle
horizontal_flip = True
angle = angle / 180 * np.pi
if 0 <= angle <= np.pi / 4:
step = 1.0 / np.cos(angle)
else:
step = 1.0 / np.sin(angle)
cos_angle = np.cos(angle)
sin_angle = np.sin(angle)
# get coordinates
x, y = [], []
for i in range(kernel_length):
radius = i * step
x.append(radius * cos_angle)
y.append(radius * sin_angle)
x, y = np.round(x).astype(np.int32), np.round(y).astype(np.int32)
# make kernel
x_ksize, y_ksize = np.max(x) + 1, np.max(y) + 1
blur_kernel = np.zeros((y_ksize, x_ksize), np.float32)
blur_kernel[y, x] = 1
blur_kernel = blur_kernel / np.sum(blur_kernel)
# flip kernel. Vertical flip is surely to be apllied because y-axis of
# image is downside, opposite to the normal axis system. Horizontal flip
# applied according to the value of 'horizontal_flip'
blur_kernel = blur_kernel[::-1, :]
if horizontal_flip:
blur_kernel = blur_kernel[:, ::-1]
# use blur kernel to filter image to get motion blur effect
blur_image = cv2.filter2D(image, ddepth=-1, kernel=blur_kernel)
return blur_image
if __name__ == '__main__':
# read image
image = cv2.imread('lena512color.tiff')
image_gray = cv2.imread('lena512color.tiff', cv2.IMREAD_GRAYSCALE)
alpha = np.ones((*image.shape[:2], 1), dtype=np.uint8) * 255
image_alpha = np.concatenate((image, alpha), axis=2)
# the following image can be changed to image_gray or image_alpha
blur_image = motion_blur(image, kernel_length=30, angle=45)
cv2.imshow('original_image', image)
cv2.imshow('motion_blur_image', blur_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
# -*- coding: utf-8 -*-
import cv2
import numpy as np
if __name__ == '__main__':
# read image
image = cv2.imread('lena512color.tiff')
image_gray = cv2.imread('lena512color.tiff', cv2.IMREAD_GRAYSCALE)
alpha = np.ones((*image.shape[:2], 1), dtype=np.uint8) * 255
image_alpha = np.concatenate((image, alpha), axis=2)
# the following image can be changed to image_gray or image_alpha
blur_image = cv2.medianBlur(image, ksize=7)
cv2.imshow('original_image', image)
cv2.imshow('median_blur_image', blur_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
# -*- coding: utf-8 -*-
import cv2
import numpy as np
from util import uniform_random
def grainy_blur(image, radius):
"""
Apply grainy blur to image.
Parameters
----------
image: image data read by opencv, shape is [H, W, C]
radius: radius for jittering the pixels
Returns
-------
blur_image: image after blurring
"""
if not isinstance(radius, (tuple, list)):
radius = (radius, radius)
x_radius, y_radius = radius
# build meshgrid coordinates
height, width = image.shape[:2]
x, y = np.arange(width), np.arange(height)
x, y = np.meshgrid(x, y)
x, y = x.astype(np.float32), y.astype(np.float32)
# get jittered coordinates
x += uniform_random(low=-x_radius, high=x_radius, shape=x.shape)
y += uniform_random(low=-y_radius, high=y_radius, shape=y.shape)
# shrink coordinates
x, y = np.round(x).astype(np.int32), np.round(y).astype(np.int32)
x[x < 0] = 0
y[y < 0] = 0
x[x >= width] = width - 1
y[y >= height] = height - 1
# remap to get blur image
blur_image = image[y, x, ...]
return blur_image
if __name__ == '__main__':
# read image
image = cv2.imread('lena512color.tiff')
image_gray = cv2.imread('lena512color.tiff', cv2.IMREAD_GRAYSCALE)
alpha = np.ones((*image.shape[:2], 1), dtype=np.uint8) * 255
image_alpha = np.concatenate((image, alpha), axis=2)
# the following image can be changed to image_gray or image_alpha
blur_image = grainy_blur(image, radius=5)
cv2.imshow('original_image', image)
cv2.imshow('grainy_blur_image', blur_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
# -*- coding: utf-8 -*-
import cv2
import numpy as np
def jpeg_compression(image, quality_factor):
"""
Apply jpeg compression to image without saving it to disk.
Parameters
----------
image: image data read by opencv, shape is [H, W, C]
quality_factor: jpeg quality factor, between [0, 1]. Higher value means
higher quality image
Returns
-------
jpeg_image: jpeg compressed image
"""
compression_factor = int(quality_factor)
compression_param = [cv2.IMWRITE_JPEG_QUALITY, compression_factor]
image_encode = cv2.imencode('.jpg', image, compression_param)[1]
jpeg_image = cv2.imdecode(image_encode, -1)
return jpeg_image
if __name__ == '__main__':
# read image
image = cv2.imread('lena512color.tiff')
image_gray = cv2.imread('lena512color.tiff', cv2.IMREAD_GRAYSCALE)
alpha = np.ones((*image.shape[:2], 1), dtype=np.uint8) * 255
image_alpha = np.concatenate((image, alpha), axis=2)
# the following image can be changed to image_gray or image_alpha
compressed_image = jpeg_compression(image, quality_factor=10)
cv2.imshow('original_image', image)
cv2.imshow('jpeg_compressed_image', compressed_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
# -*- coding: utf-8 -*-
import cv2
import numpy as np
def mosaic(image, block_size, bbox=None):
"""
Set the bounding box region of image to mosaic.
Parameters
----------
image: image data read by opencv, shape is [H, W, C]
block_size:
bbox: mosaic region, defined as [xmin, ymin, xmax, ymax]. Default is the
full image
Returns
-------
mosaic_image: image with mosaic
"""
if not isinstance(block_size, (tuple, list)):
block_size = (block_size, block_size)
x_step, y_step = block_size
# preprocess bbox
height, width = image.shape[:2]
if bbox is None:
xmin, ymin, xmax, ymax = 0, 0, width, height
else:
xmin, ymin, xmax, ymax = bbox
xmin, ymin = max(xmin, 0), max(ymin, 0)
xmax, ymax = min(xmax, width), min(ymax, height)
# get random index for mosaic region
x_jitter = np.arange(xmin, xmax, x_step)
y_jitter = np.arange(ymin, ymax, y_step)
x_jitter, y_jitter = np.meshgrid(x_jitter, y_jitter)
x_jitter += np.random.randint(0, x_step, x_jitter.shape)
y_jitter += np.random.randint(0, y_step, y_jitter.shape)
x_jitter[x_jitter >= width] = width - 1
y_jitter[y_jitter >= height] = height - 1
# generate mosaic region by cv2.resize function
mosaic_region = image[y_jitter, x_jitter, ...]
mosaic_region = cv2.resize(mosaic_region, dsize=(xmax - xmin, ymax - ymin),
interpolation=cv2.INTER_NEAREST)
mosaic_image = image.copy()
mosaic_image[ymin:ymax, xmin:xmax, ...] = mosaic_region
return mosaic_image
if __name__ == '__main__':
# read image
image = cv2.imread('lena512color.tiff')
image_gray = cv2.imread('lena512color.tiff', cv2.IMREAD_GRAYSCALE)
alpha = np.ones((*image.shape[:2], 1), dtype=np.uint8) * 255
image_alpha = np.concatenate((image, alpha), axis=2)
# the following image can be changed to image_gray or image_alpha
mosaic_image = mosaic(image, block_size=10, bbox=[100, 100, 400, 400])
cv2.imshow('original_image', image)
cv2.imshow('mosaic_image', mosaic_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
。。。