openISP学习11-BNF — Bilateral Noise Filtering(双边滤波降噪)

文章目录

1.算法原理

双边滤波(Bilateral Filter)结合了空间域高斯滤波和值域相似性加权,在平滑噪声的同时保留边缘

经典双边滤波权重:

复制代码
w(i,j) = G_spatial(||p-q||) × G_range(|I(p)-I(q)|)

上面双边滤波权重公式,它定义了如何计算邻域内像素对中心像素的"影响力(权重)"。

说白了,它要表达了一个核心思想:一个像素要想对中心像素产生影响,它必须同时满足"离得近"和"长得像"这两个条件。我们从下面2个方面再理解下:

1. 符号的含义

  • w(i,j)) :最终计算出的综合权重。它决定了邻域内的像素 q 对中心像素 p 的影响程度。

  • p和q : p 代表图像中的中心像素(正在被处理的像素), q 代表中心像素周围的邻域像素。

  • ∣∣p−q∣∣ :代表像素 p 和 q 之间的空间距离(即它们在图像上的物理坐标距离,比如横纵坐标的差值)。

  • ∣I( p)−I(q)∣ :代表像素 p 和 q 之间的像素值差异( I 代表强度或颜色,比如灰度值从 0 到 255 的差异)。

2.为什么要相乘

上面已经从空间上和值上分别给**"离得近"和"长得像"的元素给与最大的权重,那么他们相乘,意味着一票否决制,有点"与"**运算的味道.

  • 如果两个像素离得很近,但颜色差异很大(比如跨越了物体边缘), G_range的值会非常小,导致最终权重 w 趋近于 0。
  • 如果两个像素颜色很像,但离得非常远, G_spatial的值会非常小,最终权重 w 同样趋近于 0。
  • 只有当两个像素既在空间上相邻,又在颜色上相似时,它们的乘积才会产生显著的权重。
算法值域权重量化

openISP 默认值:差值范围 rthres=[128,32,8]权重rw=[0,8,16,32](差异越大权重越小)

在算法中计算的是5x5邻域内像素值的权重,所以最后得到也是一个5x5的矩阵. 下面就是判断中心像素域5x5邻域像素插值,根据插值范围,分别赋予不同的rw权重.

复制代码
if   rdiff >= rthres[0]:         rw = rw[0]   (差异很大,权重最小)
elif rdiff ∈ [rthres[1], rthres[0]): rw = rw[1]
elif rdiff ∈ [rthres[2], rthres[1]): rw = rw[2]
elif rdiff < rthres[2]:          rw = rw[3]   (差异很小,权重最大)
空间权重(dw 矩阵)

符合高斯分布,中间像素的权重自然最大

复制代码
 8  12  32  12   8
12  64 128  64  12
32 128 1024 128  32    (高斯分布近似)
12  64 128  64  12
 8  12  32  12   8

高斯函数:

2.算法核心代码

实现细节
  • 仅处理 Y(亮度)通道,5×5 窗口
  • 逐像素双重循环,逐邻居计算值域差,计算量大
  • padding 2 像素(reflect 模式)
关键参数
参数 说明
dw 5×5 空间距离权重矩阵
rw 4 级值域权重 rw0, rw1, rw2, rw3
rthres 值域阈值 rthres0, rthres1, rthres2
clip 输出最大值
最终像素输出

output = Σ(pixel × dw × rw) / Σ(dw × rw)

算法代码实现
python 复制代码
class BNF:
    'Bilateral Noise Filtering'

    def __init__(self, img, dw, rw, rthres, clip):
        self.img = img
        self.dw = dw
        self.rw = rw
        self.rthres = rthres
        self.clip = clip

    def padding(self):
        img_pad = np.pad(self.img, (2, 2), 'reflect')
        return img_pad

    def clipping(self):
        np.clip(self.img, 0, self.clip, out=self.img)
        return self.img

    def execute(self):
        img_pad = self.padding()
        img_pad = img_pad.astype(np.uint16)
        raw_h = self.img.shape[0]
        raw_w = self.img.shape[1]
        bnf_img = np.empty((raw_h, raw_w), np.uint16)
        rdiff = np.zeros((5,5), dtype='uint16')
        for y in range(img_pad.shape[0] - 4):
            for x in range(img_pad.shape[1] - 4):
                #print("[x,y]:["+str(x)+','+str(y)+']')
                for i in range(5):
                    for j in range(5):
                        rdiff[i,j] = abs(img_pad[y+i,x+j].astype(int) - img_pad[y+2, x+2].astype(int))
                        # rdiff[i,j] = abs(img_pad[y+i,x+j] - img_pad[y+2, x+2])
                        if rdiff[i,j] >= self.rthres[0]:
                            rdiff[i,j] = self.rw[0]
                        elif rdiff[i,j] < self.rthres[0] and rdiff[i,j] >= self.rthres[1]:
                            rdiff[i,j] = self.rw[1]
                        elif rdiff[i,j] < self.rthres[1] and rdiff[i,j] >= self.rthres[2]:
                            rdiff[i,j] = self.rw[2]
                        elif rdiff[i,j] < self.rthres[2]:
                            rdiff[i,j] = self.rw[3]
                weights = np.multiply(rdiff, self.dw)
                bnf_img[y,x] = np.sum(np.multiply(img_pad[y:y+5,x:x+5], weights[:,:])) / np.sum(weights)
        self.img = bnf_img
        return self.clipping()

3.测试代码

测试是用千问帮忙写的,代码生产力一个张30x30随机图,然后使用BNF算法后,能看到图像平滑了许多.

python 复制代码
import cv2
import numpy as np
import matplotlib.pyplot as plt
from bnf import *

# 假设 BNF 类已经存在于当前环境(即您提供的代码)
# from your_module import BNF 

# 1. 准备测试图像 (强烈建议裁剪或缩放,否则纯Python循环会运行极慢)
img = cv2.imread('test.jpg', cv2.IMREAD_GRAYSCALE)
if img is None:
    # 如果没有图片,生成一张带噪点的测试图
    img = np.random.randint(0, 256, (30, 30), dtype=np.uint8)
else:
    # 裁剪为 100x100 大小以加速测试
    img = img[0:100, 0:100] 

# 2. 配置双边滤波参数 (与算法原理一致)
dw = np.array([
    [8, 12, 32, 12, 8],
    [12, 64, 128, 64, 12],
    [32, 128, 1024, 128, 32],
    [12, 64, 128, 64, 12],
    [8, 12, 32, 12, 8]
], dtype=np.uint16)

rthres = [128, 32, 8]
rw = [0, 8, 16, 32]
clip_val = 255

# 3. 执行算法
bnf_filter = BNF(img, dw, rw, rthres, clip_val)
processed_img = bnf_filter.execute()

# 4. 左右对比显示
plt.figure(figsize=(12, 6))

# 左侧:处理前
plt.subplot(1, 2, 1)
plt.imshow(img, cmap='gray')
plt.title('Original Image')
plt.axis('off')

# 右侧:处理后
plt.subplot(1, 2, 2)
plt.imshow(processed_img, cmap='gray')
plt.title('BNF Processed Image')
plt.axis('off')

plt.tight_layout()
plt.show()
  • 测试效果
  • 测试效果2:
    说实话,虽然主要的边缘保留了,但是感觉这个算法小姑有点差强人意,图像中一些细节都抹去了.
相关推荐
2401_853493942 小时前
有哪些好用的可商用的免费图片素材网站?
图像处理·平面设计·ai生图·设计素材·设计素材网站
armwind3 小时前
openISP学习13-FCS — False Color Suppression(假彩色抑制)
图像处理·计算机视觉
armwind3 小时前
openISP学习10-NLM — Non-Local Means Denoising(非局部均值降噪)
图像处理·计算机视觉
armwind5 小时前
openISP学习15-BCC — Brightness/Contrast Control(亮度/对比度控制)
图像处理·计算机视觉
装不满的克莱因瓶6 小时前
掌握条件生成对抗网络(Conditional GAN)模型结构——从无条件生成到可控生成的进阶
人工智能·pytorch·python·深度学习·神经网络·生成对抗网络·计算机视觉
Deitymoon6 小时前
RV1126——OSD模块
计算机视觉·音视频·rv1126·osd
放大的EZ7 小时前
Comfyui 教程-22
图像处理·人工智能·计算机视觉
YOLO数据集集合7 小时前
无人机航拍桥梁巡检数据集 | 桥梁结构缺陷检测 深度学习目标检测数据10338期
深度学习·yolo·目标检测·计算机视觉·无人机