【OpenCV-Python】教程:8-1 图像去噪 Image Denoising

OpenCV Python 图像去噪 Image Denoising

【目标】

  • 非局部均值去噪算法去除图像中的噪声。
  • cv2.fastNlMeansDenoising() , cv2.fastNlMeansDenoisingColored() etc.

【理论】

在前面的章节中,我们已经看到了许多图像平滑技术,如高斯模糊,中值模糊等,它们在一定程度上很好地去除少量的噪声。在这些技术中,我们在像素周围取一个小的邻域,并进行一些操作,如高斯加权平均,值的中值等来替换中心元素。简而言之,一个像素的噪声去除是局部的。

噪声有一个特性。噪声通常被认为是一个均值为零的随机变量。考虑一个有噪声的像素, p = p 0 + n p=p_0+n p=p0+n,其中 p 0 p_0 p0是像素的真实值, n n n是像素中的噪声。您可以从不同的图像中获取大量相同的像素(例如 N N N)并计算它们的平均值。理想情况下,你应该得到 p = p 0 p=p_0 p=p0,因为噪声的均值为零。

您可以通过一个简单的设置自己验证它。将静态相机固定在某个位置几秒钟。这将为您提供大量的帧,或同一场景的大量图像。然后写一段代码来找到视频中所有帧的平均值(这对你来说应该太简单了)。比较最终结果和第一帧。你可以看到噪音减少了。不幸的是,这种简单的方法对相机和场景运动不健壮。通常只有一个噪点图像可用。

想法很简单,我们需要一组相似的图像来平均噪声。考虑图像中的一个小窗口(比如5x5窗口)。同样的补丁很有可能出现在图像中的其他地方。有时在它周围的一个小社区。把这些相似的补丁放在一起并找出它们的平均值怎么样?对于特定的窗口,这是可以的。请看下面的示例图片:

【OpenCV-Python】教程:8-1 图像去噪 Image Denoising_第1张图片

图中的蓝色斑块看起来很相似。绿色的斑块看起来很相似。所以我们取一个像素,在它周围取一个小窗口,在图像中搜索相似的窗口,平均所有的窗口,然后用我们得到的结果替换像素。这种方法是非局部均值去噪。与我们之前看到的模糊技术相比,它需要更多的时间,但它的结果非常好。更多细节和在线演示可以在附加资源的第一个链接中找到。

对于彩色图像,将图像转换为CIELAB色彩空间,然后分别去噪L分量和AB分量。

现在我们将同样的方法应用到视频中。第一个参数是噪声帧的列表。第二个参数imgToDenoiseIndex指定我们需要去噪的帧,为此我们将帧的索引传递到输入列表中。第三个是temporalWindowSize,它指定用于去噪的附近帧的数量。它应该是奇数。在这种情况下,总共使用了temporalWindowSize帧,其中中心帧是要去噪的帧。例如,您传递了一个5帧的列表作为输入。让imgToDenoiseIndex = 2和temporalWindowSize = 3。然后利用帧1、帧2和帧3对帧2进行去噪。

【代码】

【OpenCV-Python】教程:8-1 图像去噪 Image Denoising_第2张图片

import numpy as np 
import cv2 
from matplotlib import pyplot as plt 

img = cv2.imread("assets/die.png")

dst = cv2.fastNlMeansDenoisingColored(img, None, 10, 10, 7, 21)

cv2.imshow("src image", img)
cv2.imshow("denoised image", dst)

cv2.waitKey(0)
cv2.destroyAllWindows()

import numpy as np 
import cv2 
from matplotlib import pyplot as plt 

cap = cv2.VideoCapture("assets/vtest.avi")

# 连续读入帧
img = [cap.read()[1] for i in range(5)]

# 转换灰度
gray = [cv2.cvtColor(i, cv2.COLOR_BGR2GRAY) for i in img]
gray = [np.float64(i) for i in gray]
noise = np.random.randn(*gray[1].shape)*10

# 添加噪声到图像中
noisy = [i+noise for i in gray]

# 转换为 uint8
noisy = [np.uint8(np.clip(i, 0, 255)) for i in noisy]

gray_back = [np.uint8(np.clip(i, 0, 255)) for i in gray]

# 参考连续5帧为第3帧降噪
dst = cv2.fastNlMeansDenoisingMulti(noisy, 2, 5, None, 4, 7, 35)

cv2.imshow("gray", gray_back[2])
cv2.imshow("noisy", noisy[2])
cv2.imshow("dst", dst)

cv2.waitKey(0)
cv2.destroyAllWindows()

【接口】

  • fastNlMeansDenoisingColored
cv2.fastNlMeansDenoisingColored(	src[, dst[, h[, hColor[, templateWindowSize[, searchWindowSize]]]]]	) ->	dst

修改彩色图像的fastnlmeans降噪函数。

  • src: 8位3通道图像
  • dst: 输出结果图像
  • templateWindowSize: 模板 patch 大小,奇数,推荐为7
  • searchWindowSize: 窗口大小(以像素为单位),用于计算给定像素的加权平均。奇数。更大的searchWindowsSize -更长的去噪时间。推荐值21像素
  • h: 亮度组件滤光强度调节参数。较大的h值可以完美地去除噪声,但也可以去除图像细节,较小的h值保留了细节,但也保留了一些噪声
  • hColor: 和h一样,只是颜色分量不同。对于大多数图像,值等于10将足以消除彩色噪声,不扭曲颜色

该函数将图像转换为CIELAB颜色空间,然后使用fastnlmeans降噪函数对给定h参数的L和AB分量分别进行降噪。

  • fastNlMeansDenoisingMulti
cv2.fastNlMeansDenoisingMulti(	srcImgs, imgToDenoiseIndex, temporalWindowSize[, dst[, h[, templateWindowSize[, searchWindowSize]]]]	) ->	dst
cv2.fastNlMeansDenoisingMulti(	srcImgs, imgToDenoiseIndex, temporalWindowSize, h[, dst[, templateWindowSize[, searchWindowSize[, normType]]]]	) ->	dst

利用多帧图像进行降噪

  • srcImgs: 8位,单通道,二通道,三通道,四通道图像序列
  • imgToDenoiseIndex: 需要降噪图像的序号
  • temporalWindowSize: 目标图像周围图像个数
  • dst: 输出与srcImgs图像大小和类型相同的图像。
  • templatewindowsize: 用于计算权重的模板补丁的像素大小。应该是奇数。推荐值7像素
  • searchWindowSize: 窗口大小(以像素为单位),用于计算给定像素的加权平均。应该是奇数。线性影响性能:更大的searchWindowsSize -更长的去噪时间。推荐值21像素
  • h: 参数调节过滤强度。较大的h值可以完美地去除噪声,但也可以去除图像细节,较小的h值保留了细节,但也保留了一些噪声

【参考】

  1. OpenCV: Image Denoising
  2. http://www.ipol.im/pub/art/2011/bcm_nlm/ (It has the details, online demo etc. Highly recommended to visit. Our test image is generated from this link)
  3. Online course at coursera (First image taken from here)
  4. Denoising

你可能感兴趣的:(OpenCV-Python,教程,opencv,python,计算机视觉,图像去噪)