最近做图像处理尝试的时候发现了一个磨皮算法发现不仅可以磨皮还可以很好的进行去噪消除一些斑点的图形,于是分享在这里。
本文的参考:图像保边滤波算法集锦--Surface Blur(表面模糊滤波)算法与实现_surface blur算法-CSDN博客
我们从surface-blur的执行方式谈一下自己的理解,实际上就是开一个窗口,对窗口中的中心像素与窗口中其他的像素值进行对比通过权重调整,使得图像中的平滑区域得到有效的平滑处理,而边缘区域的细节得以保留。也是一种保边滤波。
在这个公式中:
是输出的像素值;
是在这个公式中的邻域半径,实际上指的是在这个算法中窗口开的大小;
是一个阈值,这个阈值需要自己给出来,取值的范围是[0-255],这阈值我自己理解的是用来判断这个窗口中心像素是否是边缘的一个判断条件。
是当前像素,也就是窗口的中心像素。
是窗口中第i个像素。
公式通过计算邻域内像素值的加权平均来确定当前像素的值,实际上就是根据每个像素值与当前窗口中心像素值的差异来调整输出的权重。
当很大的时候会比较小,也就是减小当前窗口对中心像素的影响,其实这个时候中心像素值会被判断为图像的边缘,不会被过渡平滑。
当很小的时候会很大,会让这个像素进行平滑。
通过如上方式这个公式即实现了平滑磨皮,也实现保留边缘信息。
import cv2
import numpy as np
def surfaceblur(img, r, y):
# 获取图片的大小,只取图片前两个维度,忽略颜色通道
h, w = img.shape[:2]
# 拆分图像的RGB通道
R, G, B = cv2.split(img)
# surface-blur function
def surfaceblurprocess(channel):
# 填充图像边界,r为填充的半径
padded = np.pad(channel, [(r, r), (r, r)], 'reflect')
output = np.zeros_like(channel, dtype=np.float32)
# 遍历像素区
for i in range(r, h + r):
for j in range(r, w + r):
neighborhood = padded[i - r:i + r + 1, j - r:j + r + 1]
center_value = padded[i, j]
weight = 1 - np.abs(neighborhood - center_value) / (2.5 * y)
weighted_sum = np.sum(weight * neighborhood)
weight_sum = np.sum(weight)
output[i - r, j - r] = weighted_sum / weight_sum
output = np.clip(output, 0, 255).astype(np.uint8)
return output
# 计算通道
R_blurred = surfaceblurprocess(R)
G_blurred = surfaceblurprocess(G)
B_blurred = surfaceblurprocess(B)
# 合并处理后的通道
blurred_img = cv2.merge((R_blurred, G_blurred, B_blurred))
return blurred_img
# 图片的读取PNG
img = cv2.imread('path')
# 设置参数
r1 = 1 # 邻域半径
y1 = 8 # 阈值
blurred_img1 = surfaceblur(img, r1, y1)
# 显示图像
cv2.imshow('Original Image', img)
cv2.imshow('Surface Blurred Image1', blurred_img1 )
cv2.waitKey(0) # 等待按键按下
cv2.destroyAllWindows() # 销毁所有窗口
原图
磨皮后
可以看到对于椒盐噪声也有一些用处。