Opencv中图像噪声与图像平滑

图像噪声

由于图像采集、处理等过程都存在一定的误差而存在响应的噪声。其中,噪声包括高斯噪声、均匀分布噪声、脉冲噪声(椒盐噪声)等

高斯噪声(Gaussian noise)
由于高斯噪声在空间和频域中数学上的易处理性,这种噪声(也称为正态噪声)模型经常被用于实践中。高斯随机变量z的Probability Density Function(PDF)由下式给出:
p(z)=\frac{1}{\sqrt{2 \pi} \sigma} e^{\frac{-(z-\mu)^{2}}{2 \sigma^{2}}}
其中z表示灰度值,μ表示z的平均值或期望值,σ表示z的标准差。标准差的平方σ2称为z的方差。高斯函数的曲线如图所示。

高斯噪声.jpg

当z服从上式的高斯分布时候,其值有70%落在[(μ-σ),(μ+σ)]内,有95%落在[(μ-2σ),( μ+2σ)]范围内。

均匀分布噪声 (Uniform noise)
均匀噪声分布的概率密度:
p(z)=\left\{\begin{array}{l}{\frac{1}{b-a}, a \leq z \leq b} \\ {0, { 其他}}\end{array}\right.
概率密度函数的期望值和方差可由下式给出:
\mu=\frac{a+b}{2} \quad \sigma^{2}=\frac{(b-a)^{2}}{12}
脉冲噪声(椒盐噪声)
(双极)脉冲噪声的PDF:
p(z)=\left\{\begin{array}{ll}{P_{a}} & {z=a} \\ {P_{b}} & {z=b} \\ {0} & 其他{}\end{array}\right.
如果b>a,灰度值b在图像中将显示为一个亮点,a的值将显示为一个暗点。若Pa或Pb为零,则脉冲噪声称为单极脉冲。如果Pa和Pb均不可能为零,尤其是它们近似相等时,脉冲噪声值将类似于随机分布在图像上的胡椒和盐粉微粒。由于这个原因,双极脉冲噪声也称为椒盐噪声。同时,它们有时也称为散粒和尖峰噪声。

噪声脉冲可以是正的,也可以是负的。在一幅图像中,脉冲噪声总是数字化为最小值或最大值(纯黑或纯白)。负脉冲以一个黑点(胡椒点)出现在图像中。由于相同的原因,正脉冲以白点(盐点)出现在图像中。

噪声.jpg

图像平滑(图像模糊)

在已知噪声模型的基础上,对噪声的空间域滤波。

主要包括:均值滤波器、中值滤波器、高斯模糊、双边滤波器。

均值滤波器(Mean Filters)
采用均值滤波模板对图像噪声进行滤除。令S_{x y} 表示中心在(x, y)点,尺寸为m×n 的矩形子图像窗口的坐标组。
均值滤波器
\hat{f}(x, y)=\frac{1}{m n} \sum_{(s, t) \in S_{x y}} g(s, t)
由一个归一化卷积框完成的。它只是用卷积框覆盖区域所有像素的平均值来代替中心元素。可以使用函数 cv2.blur() 和 cv2.boxFilter() 来完这个任务。
注意:如果你不想使用归一化卷积框,你应该使用 cv2.boxFilter(),这时要传入参数 normalize=False。

cv2.blur(src, dst, ksize, anchor, borderType)

参数意义如下:

  • src:输入图像
  • dst:输出图像
  • ksize:卷积核的大小
  • anchor:默认值 (-1,-1) ,表示核中心
  • borderType:边界类型,参见图像扩边

例子

def img_show(name,img):
    """matplotlib图像显示函数
    name:字符串,图像标题
    img:numpy.ndarray,图像
    """
    if len(img.shape) == 3:
        img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
    plt.imshow(img,'gray')
    #plt.xticks([])
    #plt.yticks([])
    plt.xlabel(name,fontproperties='FangSong',fontsize=12)
    

if __name__=="__main__":

    img1 = cv2.imread("Fig0333(a)(test_pattern_blurring_orig).tif")
    
    img2 = cv2.blur(img1,(5,5))
    plt.figure(figsize=(10,8),dpi=80)
    plt.subplot(121)
    img_show('原图',img1)
    plt.subplot(122)
    img_show('均值滤波',img2)
均值滤波.png

高斯模糊(Gaussian Blur)
G(x, y)=e^{-\frac{x^{2}+y^{2}}{2 \sigma^{2}}}
由于Gaussian函数有着一些良好的特性,对二维连续Gaussian分布经采样、量化,并使模板归一化,便可得到二维Gaussian滤波模板。

\sigma是高斯分布的标准差,又称滤波器的尺度,决定了高斯滤波器作用邻域的空间范围。随着逐渐远离滤波中心,G(x,y)权值逐渐减小到零,这表明离滤波器中心较近的像素比远处的像素更重要。因此,高斯低通滤波器是一种加权均值滤波器。

把卷积核换成高斯核(简单来说,方框不变,将原来每个方框的值是相等的,现在里面的值是符合高斯分布的,方框中心的值最大,其余方框根据距离中心元素的距离递减,构成一个高斯小山包。原来的求平均数现在变成求加权平均数,全就是方框里的值)。实现的函数是 cv2.GaussianBlur()。我们需要指定高斯核的宽和高(必须是奇数)。以及高斯函数沿 X,Y 方向的标准差。如果我们只指定了 X 方向的的标准差,Y 方向也会取相同值。如果两个标准差都是 0,那么函数会根据核函数的大小自己计算。高斯滤波可以有效的从图像中去除高斯噪音。如果你愿意的话,你也可以使用函数 cv2.getGaussianKernel() 自己构建一个高斯核。
如果要使用高斯模糊的话,上边的代码应该写成:

GaussianBlur(src, ksize, sigmaX, sigmaY, borderType)
#0是指根据窗口大小(5,5)来计算高斯函数标准差
blur = cv2.GaussianBlur(img,(5,5),0)

参数意义如下:

  • src:输入图像
  • ksize:卷积核的大小
  • sigmaX:在X方向高斯分布的标准差(二维高斯核函数可以拆分成水平方向和竖直方向的一维高斯核函数)
  • sigmaY:在Y方向高斯分布的标准差(如果只会设置sigmaX,默认sigmaY=sigmaX)
  • borderType:边界类型

例子:对椒盐噪声的图像进行高斯模糊

def img_show(name,img):
    """matplotlib图像显示函数
    name:字符串,图像标题
    img:numpy.ndarray,图像
    """
    if len(img.shape) == 3:
        img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
    plt.imshow(img,'gray')
    #plt.xticks([])
    #plt.yticks([])
    plt.xlabel(name,fontproperties='FangSong',fontsize=12)
    

if __name__=="__main__":

    img1 = cv2.imread("Fig0335(a)(ckt_board_saltpep_prob_pt05).tif")
    
#    img2 = cv2.blur(img1,(5,5))
    img2 = cv2.GaussianBlur(img1,(7,7),0)
    img3 = cv2.GaussianBlur(img1,(7,7),5)
    img4 = cv2.GaussianBlur(img1,(7,7),10)
    
    plt.figure(figsize=(10,8),dpi=80)
    plt.subplot(221)
    img_show('原图',img1)
    plt.subplot(222)
    img_show('高斯模糊($\sigma$=0)',img2)    
    plt.subplot(223)
    img_show('高斯模糊($\sigma$=5)',img3)
    plt.subplot(224)
    img_show('高斯模糊($\sigma$=10)',img4)
椒盐噪声1.png

中值滤波器(Median filter)
\hat{f}(x, y)=\underset{(s, t) \in S_{x y}}{\operatorname{Med}}\{g(s, t)\}
中值滤波可去掉椒盐噪声,平滑效果优于均值滤波,在抑制随机噪声的同时能保持图像边缘少受模糊。

这个滤波器经常用来去除椒盐噪声。前面的滤波器都是用计算得到的一个新值来取代中心像素的值,而中值滤波是用中心像素周围(也可以使他本身)的值来取代它。它能有效的去除噪声。卷积核的大小也应该是一个奇数。

median = cv2.medianBlur(src,dst,ksize)

参数意义如下:

  • src:输入图像
  • dst:输出图像
  • ksize:卷积核的大小

例子

def img_show(name,img):
    """matplotlib图像显示函数
    name:字符串,图像标题
    img:numpy.ndarray,图像
    """
    if len(img.shape) == 3:
        img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
    plt.imshow(img,'gray')
    #plt.xticks([])
    #plt.yticks([])
    plt.xlabel(name,fontproperties='FangSong',fontsize=12)
    

if __name__=="__main__":

    img1 = cv2.imread("Fig0335(a)(ckt_board_saltpep_prob_pt05).tif")
  
    img2 = cv2.medianBlur(img1,5)
    
    plt.figure(figsize=(10,8),dpi=80)
    plt.subplot(121)
    img_show('原图',img1)
    plt.subplot(122)
    img_show('中值滤波',img2)    
中值滤波.png

双边滤波(bilateral Filter)

函数 cv2.bilateralFilter() 能在保持边界清晰的情况下有效的去除噪音。但是这种操作与其他滤波器相比会比较慢。我们已经知道高斯滤波器是求中心点邻近区域像素的高斯加权平均值。这种高斯滤波器只考虑像素之间的空
间关系,而不会考虑像素值之间的关系(像素的相似度)。所以这种方法不会考虑一个像素是否位于边界。因此边界也会别模糊掉,而这正不是我们想要。双边滤波在同时使用空间高斯权重和灰度值相似性高斯权重。空间高斯函
数确保只有邻近区域的像素对中心点有影响,灰度值相似性高斯函数确保只有与中心像素灰度值相近的才会被用来做模糊运算。所以这种方法会确保边界不会被模糊掉,因为边界处的灰度值变化比较大。

双边滤波是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折中处理,同时考虑空域信息和灰度相似性,优点是可以做边缘保存。在边缘附近,离得较远的像素不会对边缘上的像素值影响太多,这样就保证了边缘附近像素值的保存。但是由于保存了过多的高频信息,对于彩色图像里的高频噪声,双边滤波器不能很好地滤掉,只能对低频噪声很好地滤波。

cv2.bilaralFilter(src,dst,d,sigmaColor,sigmaSpace,borderType=BORDER_DEFAULT)
#9 邻域直径,两个75分别是空间高斯函数标准差,灰度值相似性高斯函数标准差
blur = cv2.bilateralFilter(img,9,75,75)

参数意义如下:

  • src:输入图像
  • dst:输出图像
  • d:表示在过滤过程中每个像素邻域的直径。如果这个值被设为非正数,那么opencv会从第五个参数sigmaSpace来计算出她。
  • sigmaColor:颜色空间滤波器的sigma值,这个参数的值越大,就表明该像素领域内有越宽广的颜色会被混到一起
  • sigmaSpace:坐标空间滤波器的sigma值,坐标空间的标注方差。它的数值越大,意味着越远的像素会相互影响,从而使更大的区域中足够相似的颜色获取相同的颜色,当d>0时,d指定了尺寸,此参数没什么用,否则,d正比于这个参数值。
  • borderType:用于推断图像外部像素的某种边界模式。

例子

def img_show(name,img):
    """matplotlib图像显示函数
    name:字符串,图像标题
    img:numpy.ndarray,图像
    """
    if len(img.shape) == 3:
        img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
    plt.imshow(img,'gray')
    #plt.xticks([])
    #plt.yticks([])
    plt.xlabel(name,fontproperties='FangSong',fontsize=12)
    

if __name__=="__main__":

    img1 = cv2.imread("gooey.jpg")

    img2 = cv2.bilateralFilter(img1,9,75,75)
    
    plt.figure(figsize=(10,8),dpi=80)
    plt.subplot(121)
    img_show('原图',img1)
    plt.subplot(122)
    img_show('双边滤波',img2)   
双边滤波.png

参考文献:《数字图像处理》《OpenCV-Python 中文教程》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342