双边滤波实现
一. 实验主题
Design a bilateral filter in some programming language (such as C/C++, Matlab, or Python as you like). Using it to process some images, for example, Cameraman, Lena, and so on.
二. 实验内容
实验需要在实现双边滤波算法的基础上进一步探索,可以从以下的其中一方面进行探索:
探究模版的不同参数对不同图像处理效果的分析与探究(例如模版大小、步长、高斯核);
不同双边滤波模版算法的复杂度分析与探究;
双边滤波算法的改进与结果分析;
双边滤波算法对加有不同噪声的模拟图像的研究;
双边滤波对于应用场景的探究与挖掘;
其他有意义或具有一定创新性的探究。
三. 前置简介
噪声类别:
椒盐噪声(盐=白色,椒=黑色):
椒盐噪声是数字图像中的常见噪声,一般是由图像传感器、传输信道及解码处理等产生的黑白相见的亮暗点噪声,椒盐噪声常由图像切割产生。椒盐噪声是指两种噪声:盐噪声(salt noise)及椒噪声(pepper noise)。盐噪声一般是白色噪声,椒噪声一般是黑色噪声,前者高灰度噪声,后者属于低灰度噪声,一般两种噪声同时出现,呈现在图像上就是黑白杂点。图像去除脉冲干扰及椒盐噪声最常用的算法是中值滤波,图像模拟添加椒盐噪声是通过随机获取像素值点并设置为高亮点来实现的。
随机噪声:
随机噪声,又称背景噪声,由时间上随机产生的大量起伏骚扰积累而造成的,其值在给定瞬间内不能预测的噪声。说实话没大理解,后来在老师的ppt课件上发现了随机值脉冲噪声,感觉它的效果和椒盐噪声很像。又百度了一下,发现脉冲噪声的特点是无规则。于是本算法基本和椒盐噪声的实现相似,可以控制噪声数量,随机生成黑白杂点,但此黑白杂点也是随机色值(a,b,c)(255-a,255-b,255-c),其中a,b,c是0-30的随机数,这些杂点在图像坐标内随机分布。
高斯噪声:
高斯噪声是指概率密度函数服从高斯分布(即正态分布)的一类噪声。如果一个噪声,它的幅度服从高斯分布,而它的功率谱密度又是分布均匀的,则称它为高斯白噪声。高斯白噪声的二阶矩不想关,一阶矩为常数,是指先后信号在时间上的相关性。高斯白噪声包括热噪声和散粒噪声。高斯噪声完全由其时变平均值和两瞬时的协方差函数来确定,若噪声为平稳的,则平均值与时间无关,而协方差函数则变成仅和所考虑的两瞬时之方差有关的相关函数,它在意义上等效于功率谱密度。高斯噪声可以由大量独立的脉冲产生,从而在任何有限时间间隔内,这些脉冲中的每一个脉冲值与所有脉冲值的总和相比都可以忽略不计。
去噪算法:
数字图像处理中的去噪算法是一种用于减少图像中噪声的技术,可以改善图像的质量并提高后续图像处理的准确性。以下是几种常见的数字图像处理中的去噪算法:
(1)中值滤波器:这是一种简单而有效的去噪算法,它基于对每个像素周围的邻域进行排序,并用其中值代替该像素。这种算法对于椒盐噪声和斑点噪声都很有效。
(2)高斯滤波器:这是一种基于加权平均的滤波算法,它使用一个高斯核函数对周围的像素进行加权平均,以产生平滑的图像。这种算法适用于高斯噪声。
(3)双边滤波器:这是一种基于空间域和灰度值域的滤波算法,它可以保留边缘信息并去除噪声。该算法考虑到了像素间的空间距离和灰度值差异,使用一个加权平均来减少噪声的影响。
(4)小波变换去噪:小波变换可以将图像分解为不同尺度的子带,并去除高频噪声。在去噪过程中,选择一个适当的阈值来保留低频信号,并过滤掉高频信号。
(5)总变差去噪:总变差去噪算法利用了图像中相邻像素间的变化量,通过最小化总变差来去除噪声。该算法可以有效去除平滑性较强的噪声。
本次实验介绍双边滤波器算法。
双边滤波算法:
双边滤波是一种经典的图像处理算法,用于在保持边缘信息的同时,对图像进行平滑处理。它的主要思想是在像素值相似的区域内,保留边缘信息,而在像素值差异较大的区域内,进行平滑处理。具体地说,双边滤波算法是通过将一个高斯滤波器与一个距离加权函数相结合来实现的。高斯滤波器用于对像素值进行平滑处理,而距离加权函数则用于控制在边缘处的滤波程度。距离加权函数通常使用像素之间的欧式距离来计算,它可以使得像素值相近的区域权重更大,从而保留边缘信息。同时,还可以使用像素之间的灰度值差异来计算权重,以控制像素值差异较大的区域的平滑程度。双边滤波算法在图像去噪、图像增强、边缘检测等领域有着广泛的应用。但是由于它的计算量较大,需要对算法进行优化才能在实际应用中取得较好的效果。双边滤波算法的数学表达式如图一:

图一
其中, Ifiltered (x,y)是滤波后的像素值,I(x,y) 是原始像素值,(i,j) 是以 (x,y) 为中心的滤波窗口 ω中的像素,w_p 和 w_s 是距离加权函数,分别用于计算空间权重和灰度权重。空间权重 wp (i,j,x,y) 表示像素 (i,j) 与中心像素 (x,y) 之间的距离权重,它可以使用高斯函数来计算

图二
其中,wp (i,j,x,y)是空间核函数的标准差,控制着像素之间的距离对滤波结果的影响程度。灰度权重 ws (I(i,j),I(x,y)) 表示像素 (i,j) 和 (x,y) 之间的灰度值差异权重,它也可以使用高斯函数来计算

图三
其中,ws 是灰度核函数的标准差,控制着像素灰度值之间的差异对滤波结果的影响程度。Wp (x,y) 是归一化系数,用于保证滤波后的像素值在 [0, 255] 的范围内。它的计算公式如下:

图四
上述公式中的 Wp表示以 (x,y) 为中心的滤波窗口。
四. 设计思想
采用面向对象的编程思想,封装了图片操作类ImageProcessor、双边滤波器BilateralFilter两个类。图片操作类内定义了一系列的静态函数、通过类直接可以调用其中的函数,对图片进行原始的操作,如读取图片、保存图片、图片加高斯噪声、图片加椒盐噪声等功能。双边滤波器类则封装了计算参数和去噪等函数,通过传入图片、像素邻域半径、颜色空间滤波器的sigma值、空间中滤波器的sigma值以创建一个图片滤波器对象,随后调用通过图片操作类对加了噪声的图片进行操作,通过自设的各种参数即可得到双边滤波后的图片。
程序运行步骤简介:
导入图片。
通过图片操作类生成对象生成带高斯噪声和椒盐噪声的图片。
生成双边滤波器对象对产生的噪声图片进行处理。
对处理好的图片进行分析。
五. 环境配置
-
开发环境:win11
-
编程语言:Python3.10.10
-
编译器:Pycharm2023.3.2
-
包管理工具:Anaconda3-2023
六. 实验过程
1.导入照片:
ImageProcessor类里的函数
def read_image(file_path: str) -> np.ndarray: image = cv2.imread(file_path) image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) return image
读取照片函数def read_image(file_path: str)注释;
参数:
Args :
file_path (str): 图片文件的路径
Returns:
np.ndarray: 图片数组,像素值在[0, 255]之间
使用cv2库中cv2.imread(addr, flags)函数读取图片
主函数创建对象并调用函数:
# 读取图片original_image = ImageProcessor.read_image('test.jpg')
2.照片加上噪声
ImageProcessor类里的函数
高斯噪声:
@staticmethod def add_gaussian_noise(image: np.ndarray, mean: float, std_dev: float) -> np.ndarray: noise = np.random.normal(mean, std_dev, image.shape) noisy_image = np.clip(image + noise, 0, 255).astype(np.uint8) return noisy_image
制造高斯噪声函数add_gaussian_noise(image: np.ndarray, mean: float, std_dev: float):注释:
参数:
Args :
image (np.ndarray): 输入的图片数组,像素值在[0, 255]之间;mean (float): 高斯分布的均值;
std_dev (float): 高斯分布的标准差;
Returns:
np.ndarray: 添加了高斯噪声后的图片数组,像素值在[0, 255]之间
使用np.random.normal(mean, std_dev, image.shape)来随机生成参数对图片处理
主函数里用刚刚创建的对象处理
# 添加高斯噪声 gaussian_noisy_image = ImageProcessor.add_gaussian_noise(original_image, mean=0, std_dev=30)
椒盐噪声:
ImageProcessor类里的函数
@staticmethod def add_salt_and_pepper_noise(image: np.ndarray, noise_density: float) -> np.ndarray: noise = np.random.rand(*image.shape) noisy_image = np.copy(image) noisy_image[noise < noise_density / 2] = 0 noisy_image[noise > 1 - noise_density / 2] = 255 return noisy_image
制造椒盐噪声函数:def add_salt_and_pepper_noise(image: np.ndarray, noise_density: float):注释:
参数:
Args:
image (np.ndarray): 输入的图片数组,像素值在[0, 255]之间;
noise_density (float): 噪声密度,即噪声点占图片总像素点数的比例;
Returns:
np.ndarray: 添加了椒盐噪声后的图片数组,像素值在[0, 255]之间
用np.random.rand(*image.shape)来随机生成参数图片进行处理。
主函数里用刚刚创建的对象处理
# 添加椒盐噪声 salt_and_pepper_noisy_image = ImageProcessor.add_salt_and_pepper_noise(original_image, noise_density=0.05)
3.对加噪点的图片导入双边滤波器进行处理
BilateralFilter里面的函数
def __init__(self, image: np.ndarray, spatial_radius: int, color_sigma: float, space_sigma: float) -> None: self.image = image self.spatial_radius = spatial_radius self.color_sigma = color_sigma self.space_sigma = space_sigma
def apply(self) -> np.ndarray: image = self.image filtered_image = np.zeros_like(image) pad_size = self.spatial_radius image = cv2.copyMakeBorder(image, pad_size, pad_size, pad_size, pad_size, cv2.BORDER_REFLECT) for i in range(pad_size, image.shape[0] - pad_size): for j in range(pad_size, image.shape[1] - pad_size): filtered_value = np.zeros(image.shape[2]) weight_sum = 0.0 for k in range(i - pad_size, i + pad_size + 1): for l in range(j - pad_size, j + pad_size + 1): color_diff = np.linalg.norm(image[k, l] - image[i, j]) spatial_diff = np.linalg.norm([k - i, l - j]) weight = np.exp(-color_diff ** 2 / (2 * self.color_sigma ** 2) - spatial_diff ** 2 / ( 2 * self.space_sigma ** 2)) filtered_value += weight * image[k, l] weight_sum += weight filtered_image[i - pad_size, j - pad_size] = filtered_value / weight_sum return filtered_image
初始函数:def init(self, image: np.ndarray, spatial_radius: int, color_sigma: float, space_sigma: float):注释:
参数
Args:
image (np.ndarray): 输入的图片数组,像素值在[0, 255]之间
spatial_radius (int): 像素邻域半径
color_sigma (float): 颜色空间滤波器的sigma值
space_sigma (float): 空间中滤波器的sigma值
Returns:
None
由使用者在主函数写入参数导入到self
双边滤波处理函数:def apply(self):注释:
参数
Returns:
filtered_image: 双边滤波后的图片数组,像素值在[0, 255]之间
这是主题函数:具体思路如下:
1.定义一个和原图像大小相同的全零矩阵filtered_image,用于存储滤波后的图像。
2.计算填充后的图像大小,并使用cv2.copyMakeBorder函数将原始图像填充。
3.遍历图像中的每个像素位置(i, j),对于每个像素,计算其在邻域内所有像素的加权平均值,其中每个像素的权重由空间距离和颜色距离计算得出。
4.将加权平均值作为该像素的输出像素值,将其存储在filtered_image矩阵中的对应位置。
5.返回filtered_image矩阵作为滤波后的图像。
主函数调用:
# 对噪声图片进行双边滤波
bf = BilateralFilter(gaussian_noisy_image, spatial_radius=5, color_sigma=30, space_sigma=50)
gaussian_noisy_filtered_image = bf.apply()
# 对噪声图片进行双边滤波
bf = BilateralFilter(salt_and_pepper_noisy_image, spatial_radius=5, color_sigma=30, space_sigma=50)
salt_and_pepper_filtered_image = bf.apply()
导出图片
ImageProcessor类里的函数
@staticmethod def save_image(file_path: str, image: np.ndarray) -> None: image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) cv2.imwrite(file_path, image)
读取照片函数def read_image(file_path: str)注释;
参数:
Args :
file_path (str): 图片文件的路径
Returns:
np.ndarray: 图片数组,像素值在[0, 255]之间
使用cv2库中cv2.imread(addr, flags)函数读取图片
主函数创建对象并调用函数:
#保存结果
ImageProcessor.save_image('D:....\\gaussian_noise.jpg', gaussian_noisy_image)
ImageProcessor.save_image('D:....\\gaussian_noise_filtered.jpg', gaussian_noisy_filtered_image)
ImageProcessor.save_image('D:....\\salt_and_pepper_noise.jpg', salt_and_pepper_noisy_image)
ImageProcessor.save_image('D:....\\salt_and_pepper_noise_filtered.jpg', salt_and_pepper_filtered_image)
5. 流程图

图五
七. 实验结果
结果一
高斯分布均值mean:0
高斯分布的标准差:30
椒盐噪声的噪声密度:0.05
像素邻域半径:5
颜色空间滤波器的sigma值:30
空间中滤波器的sigma值:50
原图:

图六
高斯噪声(图七)和椒盐噪声(图八):

图七

图八
处理好的高斯噪声图片(图九)和处理好的椒盐噪声鱼片(图十)
图九

图十

结果二
高斯分布均值mean:0
高斯分布的标准差:30
椒盐噪声的噪声密度:0.05
像素邻域半径:5
颜色空间滤波器的sigma值:30
空间中滤波器的sigma值:50
原图:

图十一
高斯噪声(图十二)和椒盐噪声(图十三):

图十二

图十三
处理好的高斯噪声图片(图十四)和处理好的椒盐噪声鱼片(图十五)

图十四

图十五
由于此实验图过于大,需要仔细看清楚请观察请查看附件中的图。
https://github.com/HCDuo/BilateralFilterTest
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
