Image denoising with block-matching and 3D filtering. SPID 2006

https://www.spiedigitallibrary.org/conference-proceedings-of-spie/6064/606414/Image-denoising-with-block-matching-and-3D-filtering/10.1117/12.643267.short

是啥


BM3D 是一种基于分块匹配和三维协同滤波的图像降噪算法,与之前讲的 NLM 算法有以下两点不同之处

  • 降噪时算法操作的单位是图像块,而不是 NLM 的逐像素处理,速度比 NLM 快
  • 对于相似块,块内先进行正交变换,然后叠加在一起变成三维矩阵后再块间进行正交变换,文中称为三维滤波(也称协同滤波**)**

BM3D 的优缺点

优点:

  1. 在保持较高降噪效果的同时,算法的计算速度相对较快,适合大规模图像处理。
  2. BM3D算法采用分块匹配策略,可以处理非线性噪声,适用范围广。
  3. 算法具有较强的自适应性和鲁棒性,可以有效处理多种不同类型的图像噪声

缺点:

  1. BM3D算法的参数调节相对较为复杂,需要一定的经验和技巧才能得到最佳的降噪效果。
  2. 算法对于高斯噪声的降噪效果较好,但对于其他噪声类型的降噪效果可能不如其他算法。
  3. 算法在处理低对比度图像时可能会出现失真和伪影等问题,需要进行一定的处理和优化。

怎么做


算法流程

BM3D 算法流程分为两步,这两步的流程是一致的,在一些计算上会有差异

  1. 分块,把图像分成一个个大小相同的块,每个块大小为 NxN
  2. 匹配,对于每个块,通过相似性度量找到最相似的 K 个块
  3. 聚合,对上一步获得的块进行排序,通过硬阈值(第二步为 Wiener Filtering)的方式获得 M 个块
  4. 协同滤波,将聚合获得的块组合成三维矩阵,先块内正交后块间正交,最后卡阈值获得降噪块
  5. 重构,将所有的块拼起来,获得降噪后的图片

大体和 NLM 流程相似,主要区别是协同滤波,它的优点是可以更好的保存图像细节

协同滤波

由上面流程所述,对于相似块,协同滤波块内先进行正交变换,然后叠加在一起变成三维矩阵后再块间进行正交变换。


在这里,正交变换是指将图像信号从时域转换成频域,如离散余弦变换(DCT)和傅里叶变换,如下图所示


如何生成右边频域图的 python 代码如下

import cv2
import numpy as np
import matplotlib.pyplot as plt# Set up a figure twice as tall as it is wide
fig = plt.figure()
fig.suptitle('DCT Visualization', fontsize=16)# Second subplot
ax = fig.add_subplot(1, 1, 1, projection='3d')image = cv2.imread("assets/a0016.jpg", 0)
# resize 到 100 方便后面可视化
image = cv2.resize(image, (100, 100))
# 加入噪音
# size = image.shape
# noise = np.random.normal(0, 0.001 ** 0.5, size)
# image = image + 1 * noiseimg_dct = np.float32(image)
dct = cv2.dct(img_dct)
# 方便可视化,这里除于100,并把大于10的都置零
dct_out = abs(dct) / 100
dct_out[dct_out > 8] = 0h, w = dct_out.shapeX = np.arange(0, w, 1)
Y = np.arange(0, h, 1)
X, Y = np.meshgrid(X, Y)surf = ax.plot_surface(X, Y, dct_out, rstride=1, cstride=1,linewidth=0, antialiased=False)
ax.set_zlim(-4, 8)plt.show()

一般来说噪音都是高斯随机分布,会遍布整个区域,包括高频和低频,而非噪音一般在低频区域,通过将小于某个值置零的方法(也就是硬阈值)可以去除掉噪音。关于时域转频域的相关原理后续单独展开说

但若噪音方与低频非噪音相近,硬阈值则会抹掉图像细节,因此对块间也进行了正交变换,再次提取相似块相同位置的低频信息

为什么块间正交变换后就可以保留更多的图像细节呢?

我们假设找到的相似块,他们图像细节抛除噪音后是一致的,那么我们在横向计算正交变换的时候,理论上非噪音的部分还是会聚集在低频区域,噪音还是会遍布整个范围,因此可以再次使用硬阈值

Python 代码实现

下面代码只实现了第一步

import cv2
import numpy as np
import mathdef process_bar(percent, start_str='', end_str='', total_length=0):bar = ''.join(["\033[31m%s\033[0m" % '   '] * int(percent * total_length)) + ''bar = '\r' + start_str + bar.ljust(total_length) + ' {:0>4.1f}%|'.format(percent * 100) + end_strprint(bar, end='', flush=True)image = cv2.imread('assets/a0016.jpg')
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)size = image.shape  # h w c# 生成噪声
image = np.array(image / 255, dtype=np.float32)
noise = np.random.normal(0, 0.001 ** 0.5, size)
imnoise = image + 1 * noise# cv2.imshow('result',imnoise)
# cv2.waitKey()sigma = 1
searchsize = 16  # 图像搜索区域半径
blocksize = 4  # 图像块尺寸
blockstep = 2  # 搜索步长
blockmaxnum = 8  # 相似块最大数量
searchblocksize = searchsize / blocksize  # 半径内块个数
kai = np.kaiser(blocksize, 5)
kai = np.dot(kai[:, None], kai[None, :])  # 二维kaiserdiffT = 100  # 允许纳入数组的最大diff
coefT = 0.0005diffArray = np.zeros(blockmaxnum)  # 相似块
similarBoxArray = np.zeros((blocksize, blocksize, blockmaxnum))
# jinbuqu csdn newland# 让图像尺寸符合倍数
newh = math.floor((size[0] - blocksize) / blockstep) * blockstep - searchsize
neww = math.floor((size[1] - blocksize) / blockstep) * blockstep - searchsizenewh = math.floor((size[0] - newh - blocksize) / blockstep) * blockstep + newh
neww = math.floor((size[1] - neww - blocksize) / blockstep) * blockstep + newwimnoise = imnoise[0:newh, 0:neww]# 初始化分子分母
imnum = np.zeros(imnoise.shape)
imden = np.zeros(imnoise.shape)# 将左上角作为块的坐标.每个块独立做一次去噪,只要关注一块的计算就行
for y in range(0, newh - blocksize, blockstep):  # 检查能不能完整走到底,范围对不对systart = max(0, y - searchsize)syend = min(newh - blocksize, y + searchsize - 1)process_bar(y / (newh - blocksize), start_str='进度', end_str="100", total_length=15)for x in range(0, neww - blocksize, blockstep):sxstart = max(0, x - searchsize)sxend = min(neww - blocksize, x + searchsize - 1)# 排序矩阵初始化similarBoxArray[:, :, 0] = imnoise[y: y + blocksize, x: x + blocksize]hasboxnum = 1diffArray[0] = 0# 不算自己for sy in range(systart, syend, blockstep):for sx in range(sxstart, sxend, blockstep):if sy == y and sx == x:continuediff = np.sum(np.abs(imnoise[y: y + blocksize, x: x + blocksize] - imnoise[sy: sy + blocksize, sx: sx + blocksize]))if diff > diffT:continue# 塞入changeid = 0if hasboxnum < blockmaxnum - 1:changeid = hasboxnumhasboxnum = hasboxnum + 1else:# 排序for difid in range(1, blockmaxnum - 1):if diff < diffArray[difid]:changeid = difidif changeid != 0:similarBoxArray[:, :, changeid] = imnoise[sy: sy + blocksize, sx: sx + blocksize]diffArray[changeid] = diff# 开始做dctfor difid in range(1, hasboxnum):similarBoxArray[:, :, difid] = cv2.dct(similarBoxArray[:, :, difid])# 开始做1d,阈值操作,计算非零个数notzeronum = 0for y1d in range(0, blocksize):for x1d in range(0, blocksize):temp3ddct = cv2.dct(similarBoxArray[y1d, x1d, :])zeroidx = np.abs(temp3ddct) < coefTtemp3ddct[zeroidx] = 0notzeronum = notzeronum + temp3ddct[temp3ddct != 0].sizesimilarBoxArray[y1d, x1d, :] = cv2.idct(temp3ddct)[:, 0]if notzeronum < 1:notzeronum = 1# 最终恢复图像所用到的分子分母for difid in range(1, hasboxnum):# 求权重:kaiser * wweight = kai / ((sigma ** 2) * notzeronum)imidct = cv2.idct(similarBoxArray[:, :, difid])# 分子,分母imnum[y: y + blocksize, x: x + blocksize] += imidct * weightimden[y: y + blocksize, x: x + blocksize] += weightx = x + blocksizey = y + blocksize# 完成去噪
imout = imnum / imdencv2.imshow('in', imnoise)
cv2.waitKey(0)
cv2.imshow('out', imout)
cv2.waitKey(0)

参考链接


下面这篇文章写的很详细,图文并茂
https://blog.csdn.net/qq_33552519/article/details/108632146

https://blog.csdn.net/sinat_29018995/article/details/123032100

BM3D 图像降噪算法与 Python 实现相关推荐

  1. 可复现的图像降噪算法总结——超赞整理

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 本文转自:AI算法与图像处理 图像降噪,是最简单也是最基础的图像处 ...

  2. 图像降噪算法——低秩聚类:WNNM算法

    图像降噪算法--低秩聚类:WNNM算法 图像降噪算法--低秩聚类:WNNM算法 1. 基本原理 2. matlab代码 3. 结论 图像降噪算法--低秩聚类:WNNM算法 同样是为了完善自己知识版图的 ...

  3. 图像降噪算法——稀疏表达:K-SVD算法

    图像降噪算法--稀疏表达:K-SVD算法 图像降噪算法--稀疏表达:K-SVD算法 1. 基本原理 2. python代码 3. 结论 图像降噪算法--稀疏表达:K-SVD算法 为了完善下自己降噪算法 ...

  4. 图像降噪算法——DnCNN / FFDNet / CBDNet / RIDNet / PMRID / SID

    图像降噪算法--DnCNN / FFDNet / CBDNet / RIDNet / PMRID / SID 图像降噪算法--DnCNN / FFDNet / CBDNet / RIDNet / PM ...

  5. 图像降噪算法——Variance Stabilizing Transform / Generalization Anscombe Transform算法

    图像降噪算法--Variance Stabilizing Transform / Generalization Anscombe Transform算法 图像降噪算法--Variance Stabil ...

  6. 图像降噪算法——图像降噪算法总结

    图像降噪算法--图像降噪算法总结 图像降噪算法--图像降噪算法总结 图像降噪算法--图像降噪算法总结 前面这段时间我看了几篇和图像降噪相关的Review,给我的感觉就是SLAM这一研究领域像是一片汪洋 ...

  7. 图像降噪算法——时域降噪算法

    图像降噪算法--时域降噪算法 图像降噪算法--时域降噪算法 1.<MeshFLow Video Denoising> 2. <Real-Time Video Denoising On ...

  8. 图像降噪算法——小波硬阈值滤波(下)

    图像降噪算法--小波硬阈值滤波(下) 图像降噪算法--小波硬阈值滤波(下) 1. 基本原理 2. C++代码实现 3. 结论 图像降噪算法--小波硬阈值滤波(下) 1. 基本原理 关于离散小波变换的原 ...

  9. 图像降噪算法——小波硬阈值滤波(上)

    图像降噪算法--小波硬阈值滤波(上) 图像降噪算法--小波硬阈值滤波(上) 1. 多分辨率展开 2. 尺度函数 3. 小波函数 4. 小波级数展开 5. 离散小波变换 6. 快速小波变换 7. 图像小 ...

  10. 图像降噪算法——维纳滤波

    图像降噪算法--维纳滤波 图像降噪算法--维纳滤波 1. 基本原理 2. C++代码实现 3. 结论 图像降噪算法--维纳滤波 维纳滤波是在频域中处理图像的一种算法,是一种非常经典的图像增强算法,不仅 ...

最新文章

  1. esp32 micropython spiffs_二十一,ESP32 SPIFFS:读取一个文件
  2. Set精讲(Java)·算法常用集合处理方法
  3. MySQL的查询缓存
  4. PAT1004 成绩排名【vector sort排序、string的使用】
  5. Oracle 中 call 和 exec的区别
  6. 序列元素IT面试题——判断合法出栈序列
  7. Spring JSR-250 注释
  8. 【elasticsearch】elasticsearch 精确匹配 与 全文搜索
  9. mysql数据库别名_MySQL数据库表名、列名、别名区分大小写的问题
  10. 集中式还是分布式?账务类数据库架构的选型
  11. 在javascript使用EL表达式注意事项
  12. RMAN数据库恢复 之归档模式有(无)备份-丢失数据文件的恢复
  13. Git拉取指定远程分支
  14. python里我最容易搞不清楚问题之一的encode和decode
  15. 孤读Paper——《Deep Snake for Real-Time Instance Segmentation》
  16. 短视频去水印解析二次运用--全网短视频解析去水印软件
  17. 局域网查共享计算机的ip地址吗,如何查看电脑的内网IP地址?
  18. 域名型通配符ssl证书_通配符SSL证书是否支持三级子域名?
  19. itop使用TF卡烧写uboot
  20. 【JS】学习记录【页面打印】

热门文章

  1. 安卓学习教程总结:芯灵思开发板安卓底层开发
  2. 计算机考研402,考研初试402高分复试被淘汰,原来因为这几点被pass掉,以此为戒...
  3. js 正则替换换行符
  4. 机器视觉学习笔记(1)——OpenCV配置
  5. TNSPING只用于测试DB Listener是否可用,特别注意它不能检测数据库是否已经启动。
  6. 9. 结构体可以直接赋值吗
  7. [数据结构]---单调栈
  8. python argmin_python中argmin函数_Python numpy.argmin()用法及代码示例
  9. oracle 正则表达式匹配
  10. Java性能调优方法:基于等待的调优