opencv 对图片滤波处理方式

本文研究 opencv 对图片的滤波方式

滤波方式

生成测试图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def zone(x, y):
return 0.5 * (1 + math.cos(x * x + y * y))

SIZE = 597
image = np.zeros((SIZE, SIZE))

start = -8.2
end = 8.2
step = 0.0275

def dist_center(y, x):
global SIZE
center = SIZE / 2
return math.sqrt( (x - center)**2 + (y - center)**2)

for y in range(0, SIZE):
for x in range(0, SIZE):
if dist_center(y, x) > 300:
continue
y_val = start + y * step
x_val = start + x * step
image[y, x] = zone(x_val, y_val)

new_image=image*255
show_images([new_image])

png

低通滤波器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import scipy.stats as st
def gkern(kernlen=21, nsig=2):
"""Returns a 2D Gaussian kernel array."""

interval = (2 * nsig + 1.) / (kernlen)
x = np.linspace(-nsig - interval / 2., nsig + interval / 2., kernlen + 1)
kern1d = np.diff(st.norm.cdf(x))
kernel_raw = np.sqrt(np.outer(kern1d, kern1d))
kernel = kernel_raw / kernel_raw.sum()
return kernel

kernel_size = 11

lowpass_kernel_gaussian = gkern(kernel_size)
lowpass_kernel_gaussian = lowpass_kernel_gaussian / lowpass_kernel_gaussian.sum()

lowpass_kernel_box = np.ones((kernel_size, kernel_size))
lowpass_kernel_box = lowpass_kernel_box / (kernel_size * kernel_size)

lowpass_image_gaussian = cv2.filter2D(new_image, -1, lowpass_kernel_gaussian)
lowpass_image_box = cv2.filter2D(new_image, -1, lowpass_kernel_box)
show_images([new_image,lowpass_image_gaussian,lowpass_image_box])

png

高通滤波器

1
2
3
4
5
6
7
# 在空间域中,可以通过从图像本身中减去低通滤波图像来获得高通滤波图像(如非锐化掩模)
highpass_image_gaussian = image - lowpass_image_gaussian
highpass_image_gaussian = np.absolute(highpass_image_gaussian)

highpass_image_box = image - lowpass_image_box
highpass_image_box = np.absolute(highpass_image_box)
show_images([new_image,highpass_image_gaussian,highpass_image_box])

png

带阻滤波器

1
2
3
# 在空间域中,可以通过将低通滤波与高通滤波图像(在不同阈值下)相加来获得带阻滤波图像
bandreject_image = lowpass_image_gaussian + highpass_image_box
show_images([new_image,bandreject_image])

png

带通滤波器

1
2
3
4
# 在空间域中,可以通过从图像本身中减去带阻滤波图像来获得带通滤波图像
bandpass_image = image - bandreject_image
bandpass_image = np.absolute(bandpass_image)
show_images([new_image,bandpass_image])

png

低通滤波 - 去躁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# 生成椒盐噪声:给图片添加黑白噪点,椒指的是黑色的噪点(0,0,0)盐指的是白色的噪点(255,255,255),通过设置amount来控制添加噪声的比例,值越大添加的噪声越多,图像损坏的更加严重
#设置添加椒盐噪声的数目比例
from turtle import title
s_vs_p = 0.5
#设置添加噪声图像像素的数目
amount = 0.04
impulse_noisy_img = np.copy(image)
#添加salt噪声
num_salt = np.ceil(amount * image.size * s_vs_p)
#设置添加噪声的坐标位置
coords = [np.random.randint(0,i - 1, int(num_salt)) for i in image.shape]
impulse_noisy_img[coords[0],coords[1],:] = [255,255,255]
#添加pepper噪声
num_pepper = np.ceil(amount * image.size * (1. - s_vs_p))
#设置添加噪声的坐标位置
coords = [np.random.randint(0,i - 1, int(num_pepper)) for i in image.shape]
impulse_noisy_img[coords[0],coords[1],:] = [0,0,0]

# 生成高斯噪声:给图片添加一个服从高斯分布的噪声,可以通过调节高斯分布标准差(sigma)的大小来控制添加噪声程度,sigma越大添加的噪声越多图片损坏的越厉害
#设置高斯分布的均值和方差
mean = 0
#设置高斯分布的标准差
sigma = 25
#根据均值和标准差生成符合高斯分布的噪声
gauss = np.random.normal(mean,sigma,image.shape)
#给图片添加高斯噪声
gauss_noisy_img = image + gauss
#设置图片添加高斯噪声之后的像素值的范围
gauss_noisy_img = np.clip(gauss_noisy_img,a_min=0,a_max=255)

# 生成泊松噪声
#计算图像像素的分布范围
vals = len(np.unique(image))
vals = 2 ** np.ceil(np.log2(vals))
#给图片添加泊松噪声
poisson_noisy_img = np.random.poisson(image * vals) / float(vals)

# 生成乘性噪声
#随机生成一个服从分布的噪声
img_height,img_width,img_channels=image.shape
gauss = np.random.randn(img_height,img_width,img_channels)
#给图片添加speckle噪声
speckle_noisy_img = image + image * gauss
#归一化图像的像素值
speckle_noisy_img = np.clip(speckle_noisy_img,a_min=0,a_max=255)

noise_images=[image,impulse_noisy_img,gauss_noisy_img,poisson_noisy_img,speckle_noisy_img]
titles=['original','impulse_noisy','gauss_noisy','poisson_noisy','speckle_noisy']
show_images(noise_images,titles=titles,nrows=1,imsize=8)

png

均值滤波

对各种噪声都有一定的抑制作用

1
2
3
4
5
6
7
# 均值滤波
dst_images=[]
for idx,noise_image in enumerate(noise_images):
dst_images.append(cv2.blur(noise_image, (5,5)))

show_images(noise_images,titles=titles,nrows=1,imsize=8) # 原始噪声
show_images(dst_images,titles=titles,nrows=1,imsize=8) # 去躁后


png
png

高斯滤波

对随机噪声比较好,对椒盐噪声效果不好

1
2
3
4
5
6
7
# 高斯滤波
dst_images=[]
for idx,noise_image in enumerate(noise_images):
dst_images.append(cv2.GaussianBlur(noise_image,(5,5),0))

show_images(noise_images,titles=titles,nrows=1,imsize=8) # 原始噪声
show_images(dst_images,titles=titles,nrows=1,imsize=8) # 去躁后

png
png

中值滤波

对椒盐噪声效果比较好

1
2
3
4
5
6
7
8
# 中值滤波
dst_images=[]
for idx,noise_image in enumerate(noise_images):
noise_image=noise_image.astype(np.uint8)
dst_images.append(cv2.medianBlur(noise_image, 5))

show_images(noise_images,titles=titles,nrows=1,imsize=8) # 原始噪声
show_images(dst_images,titles=titles,nrows=1,imsize=8) # 去躁后


png
png

双边滤波

1
2
3
4
5
6
7
8
# 双边滤波
dst_images=[]
for idx,noise_image in enumerate(noise_images):
noise_image=noise_image.astype(np.uint8)
dst_images.append(cv2.bilateralFilter(noise_image,9,75,75))

show_images(noise_images,titles=titles,nrows=1,imsize=8) # 原始噪声
show_images(dst_images,titles=titles,nrows=1,imsize=8) # 去躁后


png
png

方框滤波

1
2
3
4
5
6
7
dst_images=[]
for idx,noise_image in enumerate(noise_images):
# noise_image=noise_image.astype(np.uint8)
dst_images.append(cv2.boxFilter(noise_image,-1,(5,5)))

show_images(noise_images,titles=titles,nrows=1,imsize=8) # 原始噪声
show_images(dst_images,titles=titles,nrows=1,imsize=8) # 去躁后


png
png

二维卷积滤波

1
2
3
4
5
6
7
8
9
# 二维卷积滤波
kernel = np.ones((5,5), np.float32)/25 #滤波器
dst_images=[]
for idx,noise_image in enumerate(noise_images):
# noise_image=noise_image.astype(np.uint8)
dst_images.append(cv2.filter2D(noise_image, -1, kernel))

show_images(noise_images,titles=titles,nrows=1,imsize=8) # 原始噪声
show_images(dst_images,titles=titles,nrows=1,imsize=8) # 去躁后


png
png

fastNlMeansDenoisingColored

非局部去噪,速度很慢,可以调参的去噪方法,去噪针对彩色图

1
2
3
4
5
6
7
8
# fastNlMeansDenoisingColored
dst_images=[]
for idx,noise_image in enumerate(noise_images):
noise_image=noise_image.astype(np.uint8)
dst_images.append(cv2.fastNlMeansDenoisingColored(noise_image, None, 15, 15, 7, 21))

show_images(noise_images,titles=titles,nrows=1,imsize=8) # 原始噪声
show_images(dst_images,titles=titles,nrows=1,imsize=8) # 去躁后

png
png

fastNlMeansDenoising

非局部去噪,速度很慢,可以调参的去噪方法

1
2
3
4
5
6
7
8
9
# fastNlMeansDenoising
dst_images=[]
for idx,noise_image in enumerate(noise_images):
noise_image=noise_image.astype(np.uint8)
noise_gray= cv2.cvtColor(noise_image, cv2.COLOR_BGR2GRAY)
dst_images.append(cv2.fastNlMeansDenoising(noise_gray, None, 15, 8, 25))

show_images(noise_images,titles=titles,nrows=1,imsize=8) # 原始噪声
show_images(dst_images,titles=titles,nrows=1,imsize=8) # 去躁后


png
png

高通滤波 - 提取边缘

1
2
3
4
img_path='../demo.png'
img=cv2.imread(img_path)
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
show_images([img,gray])

png

1
2
3
# 二值化
binary=cv2.inRange(gray,1,255)
show_images([gray,binary])

png

拉普拉斯算子

1
2
3
4
5
# 使用Laplace函数
dst=cv2.Laplacian(binary,cv2.CV_8U)

titles=['original','dst']
show_images([binary,dst],titles=titles,nrows=1,imsize=8)

png

Sobel 算子

1
2
3
4
5
6
grad_x=cv2.Sobel(binary,-1,1,0)
grad_y=cv2.Sobel(binary,-1,0,1)
soble_img=cv2.addWeighted(grad_x,1.0,grad_y,1.0,0)

titles=['original','grad_x','grad_y','dst']
show_images([binary,grad_x,grad_y,soble_img],titles=titles,nrows=1,imsize=8)


png

Canny 算子

1
2
3
dst=cv2.Canny(binary,100,150)
titles=['original','dst']
show_images([binary,dst],titles=titles,nrows=1,imsize=8)

png