图像增强和滤波图像滤波

举报
Gere 发表于 2022/08/07 19:25:58 2022/08/07
【摘要】 图像滤波原理高斯滤波先看原图在opencv里调用API如下原理代码中值滤波原理Opencv_APICodeSobel滤波Sobel Kernelnote拉普拉斯(**计算二阶导**)欢迎一起来参与leetcode刷题项目高斯滤波二维情况下的高斯滤波分布1 2 π σ x σ y exp ⁡ − ( x − u ) 2 + ( y − v ) 2 2 σ x σ y \frac{1}{2\pi...


高斯滤波

二维情况下的高斯滤波分布
1 2 π σ x σ y exp ⁡ − ( x − u ) 2 + ( y − v ) 2 2 σ x σ y \frac{1}{2\pi \sigma_x \sigma_y} \exp { -\frac{(x-u)^2 + (y-v)^2}{2\sigma_x \sigma_y} } 2πσxσy1exp2σxσy(xu)2+(yv)2
不过一般情况下都是让 x x x方向和 y y y方向的方差相等
1 2 π σ 2 exp ⁡ − ( x − u ) 2 + ( y − v ) 2 2 σ 2 \frac{1}{2\pi \sigma^2} \exp { -\frac{(x-u)^2 + (y-v)^2}{2\sigma^2} } 2πσ21exp2σ2(xu)2+(yv)2


先看原图

plt.imshow(img_d1)

在这里插入图片描述
这个颜色是因为opencv的默认格式为BGR

在opencv里调用API如下

# 这里设置方差都为0.8,你也可以让两个方向的方差不等
plt.imshow(cv.GaussianBlur(img_d1_copy, (5,5), 0.8))

在这里插入图片描述

原理代码

# Gaussian filter
def gaussian_filter_zp(img, K_size=5, sigma=0.8):
	if len(img.shape) == 3:
		H, W, C = img.shape
	else:
		img = np.expand_dims(img, axis=-1)
		H, W, C = img.shape

		
	## Zero padding
	pad = K_size // 2
	print(pad)
	out = np.zeros((H + pad * 2, W + pad * 2, C), dtype=np.float)
	out[pad: pad + H, pad: pad + W] = img.copy().astype(np.float)

	## prepare Kernel
	K = np.zeros((K_size, K_size), dtype=np.float)
	for x in range(-pad, -pad + K_size):
		for y in range(-pad, -pad + K_size):
			K[x + pad, y + pad] = np.exp( -(x ** 2 + y ** 2) / (2 * (sigma ** 2)))
	K /= (sigma * 2 * np.pi)
	K /= K.sum()
	
	print(K)

	tmp = out.copy()
	# filtering
	for y in range(H):
		for x in range(W):
		    for c in range(C):
		        out[pad + y, pad + x, c] = np.sum(K * tmp[y: y + K_size, x: x + K_size, c])

	out = out[pad: pad + H, pad: pad + W].astype(np.uint8)

	return out

上诉代码分两部分,第一部分是根据给定的K_size和方差计算内核
K_size=5, sigma=0.8情况下的内核为

[[0.00048091 0.00501119 0.01094545 0.00501119 0.00048091]
 [0.00501119 0.0522178  0.11405416 0.0522178  0.00501119]
 [0.01094545 0.11405416 0.2491172  0.11405416 0.01094545]
 [0.00501119 0.0522178  0.11405416 0.0522178  0.00501119]
 [0.00048091 0.00501119 0.01094545 0.00501119 0.00048091]]

第二部分是一个卷积的操作,应该叫相关相关操作之前先把图像翻转 18 0 o 180^o 180o就是卷积了
如果你嫌麻烦,opencv有卷积的API

# 这个K就是上面计算出来的高斯核
Gaussian_k = K.copy()
plt.imshow(cv.filter2D(img_d1_copy, -1, Gaussian_k))

在这里插入图片描述
执行代码

plt.subplot(131),plt.imshow(img_d1_copy),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(132),plt.imshow(cv.GaussianBlur(img_d1_copy, (3,3), 1, 1)),plt.title('Gaussian_opencv')
plt.xticks([]), plt.yticks([])
plt.subplot(133), plt.imshow(gaussian_filter_zp(img_d1_copy)),plt.title('gaussian_filter_zp')
plt.xticks([]), plt.yticks([])

在这里插入图片描述

中值滤波

中值滤波和均值滤波都很简单

原理

在图像上给出一个核的大小,计算一个核内的全部像素值,然后把核中心的像素替换为整个核内像素的中值。
在均值滤波和高斯滤波中,计算出来新的像素值可能不属于原始图像,但是中值滤波使用的就是原始图像的像素作为新的像素值。中值滤波可以很好的去除椒盐噪声。

Opencv_API

plt.imshow(cv.medianBlur(img_d1_copy, 5))

在这里插入图片描述

Code

def median_filter_zp(img :np.ndarray, K_size=5):
    H,W,C = img.shape
    
    pad = K_size // 2
    out = np.zeros((H+pad*2, W+pad*2, C), dtype=np.float)
    out[pad:pad+H, pad:pad+W] = img.copy().astype(np.float)
    
    tmp = out.copy()
    
    # filter
    for y in range(H):
        for x in range(W):
            for c in range(C):
                out[pad+y, pad+x, c] = np.median(tmp[y:y+K_size, x:x+K_size, c])
                
    out = out[pad:pad+H, pad:pad+W].astype(np.uint8)
    
    return out

执行

plt.subplot(131),plt.imshow(img_d1_copy),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(132),plt.imshow(cv.medianBlur(img_d1_copy, 5)),plt.title('Median_opencv')
plt.xticks([]), plt.yticks([])
plt.subplot(133), plt.imshow(median_filter_zp(img_d1_copy)),plt.title('median_filter_zp')
plt.xticks([]), plt.yticks([])

在这里插入图片描述

Sobel滤波

sobel滤波器是一种高通滤波器,它能放大图像中的高频成分(边缘),同样的还有Perwitt、Scharr等内核。这些定向滤波器都会计算图像函数的一阶导数。因此在滤波器方向上像素强度变化大的区域将会得到较大的值,计算图像导数的滤波器称为高通滤波器
g r a d ( I ) = [ ∂ I ∂ x , ∂ I ∂ y ] T grad(I) = [\frac{\partial I}{\partial x}, \frac{\partial I}{\partial y}]^T grad(I)=[xI,yI]T

Sobel Kernel

# vertical
array([[-1., -2., -1.],
       [ 0.,  0.,  0.],
       [ 1.,  2.,  1.]])
# horizontal
array([[-1.,  0.,  1.],
       [-2.,  0.,  2.],
       [-1.,  0.,  1.]])

执行步骤和上述代码一样

def different_filter_zp(img: np.ndarray, K_size=3):
    H,W,C = img.shape
    
    # zero padding
    pad = K_size // 2
    out = np.zeros((H+pad*2, W+pad*2, C), dtype=np.float)
    out[pad:pad+H, pad:pad+W] = img.copy().astype(np.float)
    
    tmp = out.copy()
    
    out_v = out.copy()
    out_h = out.copy()
    
    # vertical kernel
    Kv = np.array([[-1., -2., -1.],[0., 0., 0.],[1., 2., 1.]])
    # Horizontal kernel
    Kh = np.array([[-1., 0., 1.],[-2., 0., 2.], [-1., 0., 1.]])
    
    print(K_size)
    # filter
    for y in range(H):
        for x in range(W):
            for c in range(C):
                out_v[y+pad, x+pad, c] = np.sum(Kv * tmp[y:y+K_size, x:x+K_size, c])
                out_h[y+pad, x+pad, c] = np.sum(Kh * tmp[y:y+K_size, x:x+K_size, c])
    out_v = np.clip(out_v, 0, 255)
    out_h = np.clip(out_h, 0, 255)
    
    out_v = out_v[pad:pad+H, pad:pad+W].astype(np.uint8)
    out_h = out_h[pad:pad+H, pad:pad+W].astype(np.uint8)
    
    return out_v, out_h

打印结果

# 执行
different_filter_zp_v, different_filter_zp_h = different_filter_zp(img_d1_RGB)
# print
plt.subplot(1,2,1)
plt.imshow(different_filter_zp_v),plt.title('v')
plt.xticks([]), plt.yticks([])
plt.subplot(1,2,2)
plt.imshow(different_filter_zp_h),plt.title('h')
plt.xticks([]), plt.yticks([])

在这里插入图片描述
对比调用opencvAPI

plt.subplot(1,2,1)
plt.imshow(cv.Sobel(img_d1_RGB,-1, 0,1)), plt.title('Opencv_Sobel_v')
plt.xticks([]),plt.yticks([])
plt.subplot(1,2,2)
plt.imshow(cv.Sobel(img_d1_RGB,-1, 1,0)), plt.title('Opencv_Sobel_h')
plt.xticks([]),plt.yticks([])

在这里插入图片描述

note

相同时求得水平和竖直方向的梯度,建议使用L1范数

plt.imshow(abs(different_filter_zp_v) + abs(different_filter_zp_h))

在这里插入图片描述

拉普拉斯(计算二阶导

l a p l a c i a n ( I ) = ( ∂ I ∂ x ) 2 , ( ∂ I ∂ y ) 2 laplacian(I) =\sqrt{({ \frac{\partial I}{\partial x}})^2, ({\frac{\partial I}{\partial y}})^2} laplacian(I)=(xI)2,(yI)2 
Sobel相比,拉普拉斯算子在计算时可以使用更大的内核,并且对噪声更加敏感,(因为这些更大的内核是用高斯函数的二阶导数计算的),这些算子也称为**高斯-拉普拉斯算子(Laplacian of Gaussion, LOG)**拉普拉斯算子内核的值的累加和总是0.这保证在强度值恒定的区域中,拉普拉斯算子将变为0。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。