OpenCV-Python-(5)-图像平滑

图像平滑

平滑处理smoothing也称模糊处理bluring,使用频率很高的图像处理方法。平滑处理的用途有很多,最常见的是用来减少图像上的噪点或者失真。在涉及到降低图像分辨率时,平滑处理是非常好用的方法。

使用低通滤波器可以达到图像模糊的目的。

  • cv2.blur(src, ksize[, dst[, anchor[, borderType]]])                                         #均值平滑
  • cv2.boxFilter(src, ksize[,depth[, dst[, anchor[, borderType]]])                     #均值平滑
  • cv2.GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]])         #高斯平滑
  • cv2.dst = cv.medianBlur(src, ksize[, dst] )                                                     #中值平滑
  • cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]])    #双边滤波
  •  

1.均值平滑

均值滤波是典型的线性滤波算法。

它是指在图像上对目标像素给一个模板,该模板包括了其周围的临近像素(以目标象素为中心的周围8个像素,构成一个滤波模板,即去掉目标像素本身),再用模板中的全体像素的平均值来代替原来像素值。

平均是由一个归一化卷积框完成的。只是用卷积框覆盖区域所有像素的平均值来代替中心元素

均值滤波本身存在着固有的缺陷,即它不能很好地保护图像细节,在图像去噪的同时也破坏了图像的细节部分,从而使图像变得模糊,不能很好地去除噪声点。


Opencv中均值模板可以用cv2.blur和cv2.boxFilter。

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

cv2.boxFilter(src, ksize[,depth[, dst[, anchor[, borderType]]])

src-图像矩阵

ksize-滤波平滑窗口尺寸

depth-位深

anchor-锚点

borderType-边界填充类型

import cv2

src = cv2.imread(r'C:\Users\x\Desktop\11.jpg', cv2.IMREAD_ANYCOLOR)
dst = cv2.blur(src, (5,5))
dst1 = cv2.boxFilter(src, -1, (9,9)) #第二个参数的-1表示输出图像使用的深度与输入图像相同
cv2.imshow("src", src)
cv2.imshow('blur', dst)
cv2.imshow('boxFilter', dst1)
cv2.waitKey(0)
cv2.destroyAllWindows()


2.高斯平滑

高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到。

高斯滤波的具体操作是:用一个模板(或称卷积、掩模)扫描图像中的每一个像素,用模板确定的邻域内像素的加权平均灰度值去替代模板中心像素点的值。

高斯滤波后图像被平滑的程度取决于标准差。它的输出是领域像素的加权平均,同时离中心越近的像素权重越高。因此,相对于均值滤波(mean filter)它的平滑效果更柔和,而且边缘保留的也更好

平滑窗口小,对标准差的变化不敏感,平滑效果差别不大。
平滑窗口大,对标准差的变化很敏感,平滑效果差别很大。

cv2.GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]])  

src: 图像矩阵 

ksize: 滤波窗口尺寸 ,高斯卷积大小且宽高均为奇数但可以不相等

sigmaX: 水平方向上的标准差

sigmaY: 垂直方向的标准差默认为0表示与水平方向相同

import cv2

image = cv2.imread(r'C:\Users\x\Desktop\11.jpg', cv2.IMREAD_ANYCOLOR)

dst = cv2.GaussianBlur(image, (9,9), 0.0)
cv2.imshow("image", image)
cv2.imshow("GaussBlur", dst)
cv2.waitKey(0)
cv2.destroyAllWindows()


3.中值平滑

中值滤波法是一种非线性平滑算法,它将每一像素点的灰度值设置为该点某邻域窗口内的所有像素点灰度值的中值。

中值滤波模板就是用卷积框中像素的中值代替中心值,达到去噪声的目的。

前面的滤波器都是用计算得到的一个新值来取代中心像素的值,而中值滤波是用中心像素周围(也可以使他本身)的值来取代他,卷积核的大小也是个奇数

这个模板一般用于去除椒盐噪声

椒盐噪声:也称为脉冲噪声。在图像中,它是一种随机出现的白点或者黑点,可能是亮的区域有黑色像素或是在暗的区域有白色像素(或是两者皆有)。

dst = cv.medianBlur(src, ksize[, dst] )

src:图像矩阵

ksize:滤波窗口尺寸

#API
#medianBlur(src, dst, ksize)

import cv2
import numpy as np

#加椒盐噪声
def salt(image, number):
    
    rows, cols = image.shape[:2]
    saltImage = np.copy(image)
    for i in range(number):
        ranR = np.random.randint(0, rows) #随机产生整数
        ranC = np.random.randint(0, cols)
        saltImage[ranR][ranC] = 255
        
    return saltImage

if __name__ == "__main__":
    
    src1 = cv2.imread(r'C:\Users\x\Desktop\11.jpg', cv2.IMREAD_ANYCOLOR)
    src = salt(src1, 2500)
    dst = cv2.medianBlur(src, 3)
    
    cv2.imshow("image", src)
    cv2.imshow("medianBlurImage", dst)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


4.双边滤波

双边滤波是一种非线性滤波器,它可以达到保持边缘、降噪平滑的效果。

和其他滤波原理一样,双边滤波也是采用加权平均的方法,用周边像素亮度值的加权平均代表某个像素的强度。

所用的加权平均基于高斯分布

之所以能够达到保边去噪的滤波效果是因为滤波器由两个函数构成:一个函数是由几何空间距离决定滤波器系数,另一个是由像素差值决定滤波器系数。 

高斯滤波器只考虑像素之间的空间关系,而不会考虑像素值之间的关系(像素的相似度)。所以这种方法不会考虑一个像素是否位于边界。因此边界也会别模糊掉,而这正不是我们想要 。

双边滤波在同时使用空间高斯权重和灰度值相似性高斯权重。空间高斯函数确保只有邻近区域的像素对中心点有影响,灰度值相似性高斯函数确保只有与中心像素灰度值相近的才会被用来做模糊运算。所以这种方法会确保边界不会被模糊掉,因为边界处的灰度值变化比较大。

cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]])

src:图像矩阵

d:邻域直径

sigmaColor:颜色标准差 ,参数值较大时意味着在像素点领域内的更多的颜色会被混合在一起

sigmaSpace:空间标准差,参数的较大值意味着更远的像素将与相互影响,只要它们的颜色足够相近
 

import cv2
 
image = cv2.imread(r'C:\Users\x\Desktop\48.jpg', cv2.IMREAD_ANYCOLOR)
    
dst = cv2.bilateralFilter(image, 9, 5, 5)
dst1 = cv2.bilateralFilter(image, 9, 100, 100)
dst2 = cv2.bilateralFilter(image, 9, 50, 50)

cv2.imshow("image", image)
cv2.imshow('bilateralFilter', dst)
cv2.imshow('bilateralFilter1', dst1)
cv2.imshow('bilateralFilter2', dst2)

cv2.waitKey(0)
cv2.destroyAllWindows()


5.联合双边滤波

该算法可以使方形条纹消失,对边缘保留也非常好

联合双边滤波与双边滤波唯一不同:
双边滤波是根据原图,对于每个位置,通过该位置与其邻域的灰度值的差的指数来估计相似性

联合双边滤波是首先对原图进行高斯平滑,根据平滑结果,用当前的位置及其邻域的值的差来估计相似性权重模板。

import cv2
import numpy as np
import math

#空间距离权重模板
def getClosenessWeight(sigma_g, H, W):
    
    r, c = np.mgrid[0:H:1, 0:W:1] #有两部分。[0]是y轴的范围。[1]是x轴的范围
    #模板中心
    cH = (H - 1) // 2
    cW = (W - 1) // 2
    r -= cH
    c -= cW
    closeWeight = np.exp(-0.5*(np.power(r,2)+np.power(c,2))/math.pow(sigma_g,2)) #sigma_g空间距离权重模板标准差
    
    return closeWeight
     
def jointBLF(I, H, W, sigma_g, sigma_d, borderType=cv2.BORDER_DEFAULT):
    
    #构建空间距离模板
    closenessWeight = getClosenessWeight(sigma_g, H, W)
    #对I进行平滑
    Ig = cv2.GaussianBlur(I, (W,H), sigma_g)
    #模板中心位置 ,(H x W) 是模板的大小
    cH = (H - 1) // 2
    cW = (W - 1) // 2
    #对原图和高斯平滑的结果扩充边界
    Ip = cv2.copyMakeBorder(I, cH, cH, cW, cW, borderType)
    Igp = cv2.copyMakeBorder(Ig, cH, cH, cW, cW, borderType)
    #图像矩阵的行、列数
    rows, cols = I.shape
    i, j = 0, 0
    #联合双边滤波的结果
    jblf = np.zeros(I.shape, np.float64)
    
    for r in np.arange(cH, cH+rows, 1):
        for c in np.arange(cW, cW+cols, 1):
            #当前的位置的值
            pixel = Igp[r][c]
            #当前位置的邻域
            rTop, rBottom, cLeft, cRight = r-cH, r+cH, c-cW, c+cW
            #从Igp中截取该邻域,用于构建相似性权重模板
            region = Igp[rTop:rBottom+1, cLeft:cRight+1]
            #用上述邻域,构建该位置的相似性模板
            similarityWeight = np.exp(-0.5*np.power(region-pixel,2.0)/math.pow(sigma_d,2.0))
            #两个模板相乘
            Weigth = closenessWeight * similarityWeight
            #将权重模板归一化
            Weigth = Weigth / np.sum(Weigth)
            #权重模板和邻域相对应的位置相乘并求和
            jblf[i][j] = np.sum(Ip[rTop:rBottom+1, cLeft:cRight+1]*Weigth)
            
            j += 1
            
        j = 0
        i += 1
    
    return jblf

if __name__ == "__main__":
    
    Image = cv2.imread(r'C:\Users\x\Desktop\OpenCV-Pic\5\img7.jpg', cv2.IMREAD_GRAYSCALE)
    
    #将8位图转为浮点型
    fImage = Image.astype(np.float64)
    
    #联合双边滤波返回值为浮点型
    jblf = jointBLF(fImage, 5, 5, 7, 2)
    #再转为8位图
    jblf = np.round(jblf)
    jblf = jblf.astype(np.uint8)
    
    cv2.imshow("image", Image)
    cv2.imshow("jblf", jblf)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()

猜你喜欢

转载自blog.csdn.net/qq_40755643/article/details/84035850