快速双边滤波——Python实现

版权声明:我是南七小僧,微信: to_my_love ,2020年硕士毕业,寻找 自然语言处理,图像处理,软件开发等相关工作,欢迎交流思想碰撞。 https://blog.csdn.net/qq_25439417/article/details/89028516

介绍
课程的最后一个实验是处理雀斑,网上查找了很多方法,最后我选择了快速双边滤波。但是实验又不能直接调用 opencv 的库,因此,我参照了 这个博客,将用 C 写的快速双边滤波改用 Python 重新写了一遍。

快速双边滤波是啥呢,官方滴说,它是一种非线性的滤波方法。它最大的特点就是既使用了颜色的相似度,又利用了空间的距离相似度。也就是说,它在进行滤波的过程中,不光要考虑周围像素值与中点像素值的大小之差,还需要考虑空间上的距离,进而确定该点对中间点的影响因子。

至于为啥要用快速双边滤波呢,,因为不优化的话,实在是太慢了。。。有兴趣可以试一下。

优化代码
主要的优化思路如下,提前计算好高斯模板,提前计算好各灰度值的滤波模板

代码实现
完整的代码如下:

# -*- coding: UTF-8 -*-
import numpy as np
import cv2
import math

def bilateralFilter(img, radius, sigmaColor, sigmaSpace) : 
    B, G, R = cv2.split(img)
    B_tran, G_tran, R_tran = cv2.split(img)
    img_height = len(B)
    img_width = len(B[0])
    # 计算灰度值模板系数表
    color_coeff = -0.5 / (sigmaColor * sigmaColor)
    weight_color = []       # 存放颜色差值的平方
    for i in range(256) :
        weight_color.append(np.exp(i * i * color_coeff))
    # 计算空间模板
    space_coeff = -0.5 / (sigmaSpace * sigmaSpace)
    weight_space = []     # 存放模板系数
    weight_space_row = [] # 存放模板 x轴 位置
    weight_space_col = [] # 存放模板 y轴 位置
    maxk = 0
    for i in range(-radius, radius+1) :
        for j in range(-radius, radius+1) :
            r_square = i*i + j*j
            r = np.sqrt(r_square)
            weight_space.append(np.exp(r_square * space_coeff))
            weight_space_row.append(i)
            weight_space_col.append(j)
            maxk = maxk + 1
    # 进行滤波
    for row in range(img_height) :
        for col in range(img_width) :
            value = 0
            weight = 0
            for i in range(maxk) :
                m = row + weight_space_row[i]
                n = col + weight_space_col[i]
                if m < 0 or n < 0 or m >= img_height or n >= img_width :
                    val = 0
                else :
                    val = B[m][n]
                w = np.float32(weight_space[i]) * np.float32(weight_color[np.abs(val - B[row][col])])
                value = value + val * w
                weight = weight + w
            B_tran[row][col] = np.uint8(value / weight)
    # 绿色通道
    for row in range(img_height) :
        for col in range(img_width) :
            value = 0
            weight = 0
            for i in range(maxk) :
                m = row + weight_space_row[i]
                n = col + weight_space_col[i]
                if m < 0 or n < 0 or m >= img_height or n >= img_width :
                    val = 0
                else :
                    val = G[m][n]
                w = np.float32(weight_space[i]) * np.float32(weight_color[np.abs(val - G[row][col])])
                value = value + val * w
                weight = weight + w
            G_tran[row][col] = np.uint8(value / weight)
    # 红色通道
    for row in range(img_height) :
        for col in range(img_width) :
            value = 0
            weight = 0
            for i in range(maxk) :
                m = row + weight_space_row[i]
                n = col + weight_space_col[i]
                if m < 0 or n < 0 or m >= img_height or n >= img_width :
                    val = 0
                else :
                    val = R[m][n]
                w = np.float32(weight_space[i]) * np.float32(weight_color[np.abs(val - R[row][col])])
                value = value + val * w
                weight = weight + w
            R_tran[row][col] = np.uint8(value / weight)
    cv2.imshow("beauty_after", cv2.merge([B_tran, G_tran, R_tran]))
    cv2.imwrite("beauty_after.png", cv2.merge([B_tran, G_tran, R_tran]))

img = cv2.imread("beauty1.png")
cv2.imshow("original image", img)

# bilateralFilter(img, 5, 45, 100)
bilateralFilter(img, 3, 30, 80)

img = cv2.imread("beauty_after.png")
bilateralFilter(img, 3, 30, 80)

cv2.waitKey(0)


总结
三个维度的滤波不应该像我这样写,应该一起处理,我分成了三个通道进行处理,代码就显得有点长,但这样十分方便,如果有时间的话,还是不要像我这样写。

需要注意的一点是,这段代码在处理图片的效果上不是很好,相比于 opencv 的库,效果差了很多,尤其是处理大图片的时候,使用时需要注意。

猜你喜欢

转载自blog.csdn.net/qq_25439417/article/details/89028516