OpenCV系列之影像平滑

頭頂的松果發表於2020-10-16

目標

  1. 使用各種低通濾鏡模糊影像
  2. 將定製的濾鏡應用於影像(2D卷積)

接下來,就簡單介紹一下這倆種常用的濾鏡技術。

影像模糊(影像平滑)

通過將影像與低通濾波器核心進行卷積來實現影像模糊。這對於消除噪音很有用。它實際上從影像中消除了高頻部分(例如噪聲,邊緣)。因此,在此操作中邊緣有些模糊。(有一些模糊技術也可以不模糊邊緣)。OpenCV主要提供四種型別的模糊技術。

  1. 平均
    這是通過將影像與歸一化框濾鏡進行卷積來完成的。它僅獲取核心區域下所有畫素的平均值,並替換中心元素。這是通過功能cv.blur()或cv.boxFilter()完成的。檢查文件以獲取有關核心的更多詳細資訊。我們應該指定核心的寬度和高度。3x3歸一化框式過濾器如下所示:
    在這裡插入圖片描述
    如下所示,其核心大小是5X5:
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# 1:平均
def imgJZ():
     img = cv.imread('E:\Opencv\Demo\IMG\opencv-logo-white.png')
     blur=cv.blur(img,(5,5))
     plt.subplot(121)
     plt.imshow(img)
     plt.title('Original')
     plt.xticks([])
     plt.yticks([])
     plt.subplot(122)
     plt.imshow(blur)
     plt.title('Blurred')
     plt.xticks([])
     plt.yticks([])
     plt.show()
if __name__ == '__main__':
        imgJZ()

執行看一下效果,明細出現了濾鏡效果,如下圖所示:
均值測試
注意:如果您不想使用標準化的框式過濾器,請使用cv.boxFilter()。將引數normalize = False傳遞給函式。

  1. 高斯模糊
    使用高斯核,代替盒式濾波器。這個功能是通過cv.GaussianBlur() 完成的。我們應指定核心的寬度和高度,該寬度和高度應為正數和奇數。我們還應指定X和Y方向的標準偏差,分別為sigmaX和sigmaY。如果僅指定sigmaX,則將sigmaY與sigmaX相同。如果兩個都為零,則根據核心大小進行計算。高斯模糊對於從影像中去除高斯噪聲非常有效。

如果需要,可以使用函式cv.getGaussianKernel() 建立高斯核心。
可以修改以上程式碼以實現高斯模糊:

blur = cv.GaussianBlur(img,(5,5),0)

完整程式碼如下:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
#高斯濾波器
def imgGaussianBlur():
    img = cv.imread('E:\Opencv\Demo\IMG\opencv-logo-white.png')
    blur = cv.GaussianBlur(img, (5, 5), 0)
    plt.subplot(121)
    plt.imshow(img)
    plt.title('Original')
    plt.xticks([])
    plt.yticks([])
    plt.subplot(122)
    plt.imshow(blur)
    plt.title('Blurred')
    plt.xticks([])
    plt.yticks([])
    plt.show()

if __name__ == '__main__':
        imgGaussianBlur()

執行檢視一下效果圖如下:
在這裡插入圖片描述
3. 中位模糊
函式cv.medianBlur() 提取核心區域下所有畫素的中值,並將中心元素替換為該中值。這對於消除影像中的椒鹽噪聲非常有效。有趣的是,在上述過濾器中,中心元素是新計算的值,該值可以是影像中的畫素值或新值。但是在中值模糊中,中心元素總是被影像中的某些畫素值代替。有效降低噪音。其核心大小應為正奇數整數。

我向原始影像新增了50%的噪聲並應用了中值模糊。檢查結果:

medianBlur = cv.medianBlur(img,5)

完整程式碼如下:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# 中位模糊
def imgMedianBlur():
    img = cv.imread('E:\Opencv\Demo\IMG\opencv.png')
    median =cv.medianBlur(img,5)
    plt.subplot(121)
    plt.imshow(img)
    plt.title('Original')
    plt.xticks([])
    plt.yticks([])
    plt.subplot(122)
    plt.imshow(median)
    plt.title('Blurred')
    plt.xticks([])
    plt.yticks([])
    plt.show()

if __name__ == '__main__':
      imgMedianBlur()

好了,執行一下,看一下效果圖:
中位模糊

  1. 雙邊濾波
    cv.bilateralFilter() 在去除噪聲的同時保持邊緣清晰銳利非常有效。但是,與其他過濾器相比,該操作速度較慢。我們已經看到,高斯濾波器採用畫素周圍的鄰域並找到其高斯加權平均值。高斯濾波器僅是空間的函式,也就是說,濾波時會考慮附近的畫素。它不考慮畫素是否具有幾乎相同的強度。它不考慮畫素是否是邊緣畫素。因此它也模糊了邊緣,這是我們不想做的。

雙邊濾波器在空間中也採用高斯濾波器,但是又有一個高斯濾波器,它是畫素差的函式。空間的高斯函式確保僅考慮附近畫素的模糊,而強度差的高斯函式確保僅考慮強度與中心畫素相似的那些畫素的模糊。由於邊緣的畫素強度變化較大,因此可以保留邊緣。

原理分析:

雙邊濾波與高斯濾波器相比,對於影像的邊緣資訊能過更好的儲存。其原理為一個與空間距離相關的高斯函式與一個灰度距離相關的高斯函式相乘:

  • 空間距離
    指的是當前點與中心點的歐式距離。空間域高斯函式其數學形式為:
    在這裡插入圖片描述

  • 灰度距離
    指的是當前點灰度與中心點灰度的差的絕對值。值域高斯函式其數學形式為:
    在這裡插入圖片描述
    其中gray(xi,yi)為當前點灰度值,gray(xc,yc)為中心點灰度值,sigma為值域標準差。

對於高斯濾波,僅用空間距離的權值係數核與影像卷積後,確定中心點的灰度值。即認為離中心點越近的點,其權重係數越大。

雙邊濾波中加入了對灰度資訊的權重,即在鄰域內,灰度值越接近中心點灰度值的點的權重更大,灰度值相差大的點權重越小。此權重大小,則由值域高斯函式確定。

兩者權重係數相乘,得到最終的卷積模板。由於雙邊濾波需要每個中心點鄰域的灰度資訊來確定其係數,所以其速度與比一般的濾波慢很多,而且計算量增長速度為核大小的平方。
在這裡插入圖片描述
在這裡插入圖片描述

引數選擇:

  • 空間域sigma選取:
    其中核大小通常為sigma的6sigma + 1。因為離中心點3sigma大小之外的係數與中點的係數只比非常小,可以認為此之外的點與中心點沒有任何聯絡,及權重係數為0.OpenCV中預設的計算公式也是如此,OpenCV參考文件內容如下:“對應高斯引數的 Gaussian sigma (標準差). 如果為零,則標準差由下面的核尺寸計算: sigma = (n/2 - 1)*0.3 + 0.8, 其中 n=param1 對應水平核,n=param2對應垂直核.”
  • 值域sigma選取:
    另灰度差△g = abs(gray(xi,yi)- gray(xc,yc)),忽略常數的影響,因此其函式可以簡化為:
    在這裡插入圖片描述

總結分析:

  1. Sigma越大,邊緣越模糊,極限情況為simga無窮大,值域係數近似相等(忽略常數時,將近為exp(0)= 1),與高斯模板(空間域模板)相乘後可認為等效於高斯濾波。

  2. Sigma越小,邊緣越清晰,極限情況為simga無限接近0,值域係數近似相等(接近exp(-∞) = 0),與高斯模板(空間域模板)相乘後,可近似為係數皆相等,等效於源影像。

瞭解了雙邊濾波與高斯濾波的區別,下面就具體看看實現效果吧:

以下示例顯示了使用雙邊過濾器的使用方法,關於具體使用方法和引數說明,參考官方文件《雙邊濾波》

blur = cv.bilateralFilter(img,9,75,75)

完整程式碼如下:

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

# 雙邊濾波
def imgBilateralFilter():
    img = cv.imread('E:\Opencv\Demo\IMG\opencv.png')
    blur = cv.bilateralFilter(img,9,75,75)
    plt.subplot(121)
    plt.imshow(img)
    plt.title('Original')
    plt.xticks([])
    plt.yticks([])
    plt.subplot(122)
    plt.imshow(blur)
    plt.title('Blurred')
    plt.xticks([])
    plt.yticks([])
    plt.show()

if __name__ == '__main__':
      imgBilateralFilter()

好了,看一下效果吧:
雙邊濾波

2D卷積(影像過濾)

與一維訊號一樣,還可以使用各種低通濾波器(LPF),高通濾波器(HPF)等對影像進行濾波。LPF有助於消除噪聲,使影像模糊等。HPF濾波器有助於在影像中找到邊緣。

OpenCV提供了一個函式cv.filter2D來將核心與影像進行卷積。例如,我們將嘗試對影像進行平均濾波。5x5平均濾波器核心如下所示:
在這裡插入圖片描述
操作如下:保持這個核心在一個畫素上,將所有低於這個核心的25個畫素相加,取其平均值,然後用新的平均值替換中心畫素。它將對影像中的所有畫素繼續此操作。試試如下程式碼:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
#2d卷積神經網路
def img2D_Averaging():
    img = cv.imread('E:\Opencv\Demo\IMG\opencv.png')
    kernel = np.ones((5, 5), np.float32) / 25
    dst = cv.filter2D(img, -1, kernel)
    plt.subplot(121), plt.imshow(img), plt.title('Original')
    plt.xticks([]), plt.yticks([])
    plt.subplot(122), plt.imshow(dst), plt.title('Averaging')
    plt.xticks([]), plt.yticks([])
    plt.show()
    
if __name__ == '__main__':
      img2D_Averaging()

完成效果圖如下:
在這裡插入圖片描述

相關文章