Python-OpenCV——Image Blurring(Image Smoothing)


通過將圖像與低通濾波器內核卷積來實現圖像模糊。它有助於消除噪音。它實際上從圖像中去除了高頻內容(例如:噪聲,邊緣)。因此在此操作中邊緣會有點模(嗯,有模糊技術,也不會模糊邊緣)。 OpenCV主要提供四種模糊技術。

需要注意的是,圖像模糊也叫圖像平滑,它有助於降低噪聲,但有噪聲與模糊並不是等同的。

均值模糊

這是通過將圖像與標准化的盒式過濾器( normalized box filter)進行卷積來完成的。它只取內核區域下所有像素的平均值並替換中心元素。這是由函數cv2.blur()或cv2.boxFilter()完成的。查看文檔以獲取有關內核的更多詳細信息。我們應該指定內核的寬度和高度。 3x3標准化的盒式過濾器如下所示:

$$K = \frac{1}{9} \begin{bmatrix} 1 & 1 & 1 \\ 1 & 1 & 1 \\ 1 & 1 & 1 \end{bmatrix}$$

 Note: 如果您不想使用規范化的框過濾器,請使用cv2.boxFilter()。將參數normalize = False傳遞給函數。 

      使用5x5大小的內核檢查下面的示例演示:

import cv2
import numpy as np

img = cv2.imread("./Pictures/girl.png")

blur2 = cv2.blur(img, (5,5))


htich = np.hstack((img,blur2))
cv2.imwrite("./Pictures/mreger_img.png", htich)
cv2.imshow("merged_img", htich)
cv2.waitKey(0)
cv2.destroyAllWindows()

效果:

中值模糊(中值濾波)

這里,函數cv2.medianBlur()取內核區域下所有像素的中值,並用該中值替換中心元素。這對圖像中的椒鹽噪聲非常有效。有趣的是,在上述濾波器中,中心元素是新計算的值,其可以是圖像中的像素值或新值。但在中值模糊中,中心元素總是被圖像中的某個像素值所取代。它有效地降低了噪音。其內核大小應為正奇數

     例如,自己手動添加的椒鹽噪聲、模擬實現的中值濾波、庫中的中值濾波。

import cv2
import numpy as np


def saltpepper(img,rate):
    m=int((img.shape[0]*img.shape[1])*rate)
    for a in range(m):
        i=int(np.random.random()*img.shape[1])
        j=int(np.random.random()*img.shape[0])
        if img.ndim==2:
            img[j,i]=255
        elif img.ndim==3:
            img[j,i,0]=255
            img[j,i,1]=255
            img[j,i,2]=255
    for b in range(m):
        i=int(np.random.random()*img.shape[1])
        j=int(np.random.random()*img.shape[0])
        if img.ndim==2:
            img[j,i]=0
        elif img.ndim==3:
            img[j,i,0]=0
            img[j,i,1]=0
            img[j,i,2]=0
    return img

def My_medianBlur(img, kernal):
    l = int((kernal-1) / 2)
    ret = img.copy()
    for i in range(0, img.shape[0]):
        for j in range(0, img.shape[1]):
            x_s = y_s = -l
            x_t = y_t = l
            if i <= l:
                x_s = i
            if j <= l:
                y_s = j
            if i >= img.shape[0] - l - 1:
                x_t =  img.shape[0] - i - 1
            if j >= img.shape[1] - l - 1:
                y_t =  img.shape[1] - j - 1
            part=[]
            for k1 in range(x_s, x_t + 1):
                for k2 in range(y_s, y_t + 1):
                    part.append(img[i + k1][j + k2])
            part.sort()           #排序以找到中間值
            length = len(part)
            mid = int(length / 2)
            ret[i][j] = part[mid]
    return ret

raw_img = cv2.imread('./Pictures/1.jpg', cv2.IMREAD_GRAYSCALE)


img = raw_img.copy()
sp_img = saltpepper(img,0.02)    #添加椒鹽噪聲,會改變原圖像


img1 = My_medianBlur(sp_img, 5)
img2 = cv2.medianBlur(sp_img, 5)

htich1 = np.hstack((raw_img, sp_img))
htich2 = np.hstack((img1, img2))
vtich = np.vstack((htich1, htich2))    #對比顯示,左上為原圖,右上為添加椒鹽噪聲,左下為自實現中值濾波,右下為庫中的中值濾波

cv2.imshow('median_img',vtich)
cv2.waitKey(0)
cv2.destroyAllWindows()  
                
        

效果:

高斯模糊

      在此,使用高斯核代替箱式濾波器。它是通過函數cv2.GaussianBlur()完成的。我們應該指定內核的寬度和高度,它應該是正數和奇數。我們還應分別指定X和Y方向的標准偏差,sigmaX和sigmaY。如果僅指定了sigmaX,則sigmaY與sigmaX相同。如果兩者都為零,則根據內核大小計算它們。高斯模糊在從圖像中去除高斯噪聲方面非常有效。

      與均值模糊相比,只是把卷積模板中的值換一下,不是全1了,換成一組符合高斯分布的數值放在模板里面,比如這時中間的數值最大,往兩邊走越來越小,構造一個小的高斯包。

      如果需要,可以使用函數cv2.getGaussianKernel()創建高斯內核。

函數原型:

dst = cv.GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType=BORDER_DEFAULT]]] 
參數 描述
SRC 輸入圖像
DST 輸出圖像
ksize 高斯內核大小。[高度寬度]。高度和寬度應該是奇數,並且可以具有不同的值。如果ksize設置為[0 0],則從sigma值計算ksize。
sigmaX 沿X軸(水平方向)的內核標准偏差。
sigmaY 沿Y軸(垂直方向)的內核標准偏差。如果sigmaY = 0,則sigmaX取sigmaX值
borderType 在圖像邊界上應用內核時指定圖像邊界。可能的值有:cv.BORDER_CONSTANT cv.BORDER_REPLICATE cv.BORDER_REFLECT cv.BORDER_WRAP cv.BORDER_REFLECT_101 cv.BORDER_TRANSPARENT cv.BORDER_REFLECT101 cv.BORDER_DEFAULT cv.BORDER_ISOLATED

(其實上面兩種也有同樣的參數)

上面的代碼可以修改為高斯模糊:

blur2 = cv2.GaussianBlur(img,(5,5),cv2.BORDER_DEFAULT)

效果:

 

雙邊濾波

      cv2.bilateralFilter()在降低噪音方面非常有效,同時保持邊緣清晰。但與其他過濾器相比,操作速度較慢。我們已經看到高斯濾波器采用像素周圍的鄰域並找到其高斯加權平均值。該高斯濾波器僅是空間的函數,即,在濾波時考慮附近的像素。它沒有考慮像素是否具有幾乎相同的強度。它不考慮像素是否是邊緣像素。所以它也模糊了邊緣,我們不想這樣做。

      雙邊濾波器在空間中也采用高斯濾波器,但還有一個高斯濾波器,它是像素差的函數。空間的高斯函數確保僅考慮附近的像素用於模糊,而強度差的高斯函數確保僅具有與中心像素相似強度的那些像素被認為是模糊的。因此它保留了邊緣,因為邊緣處的像素將具有較大的強度變化。

      具體的,圖像中每個像素處的強度值被來自附近像素的強度值的加權平均值替換。該權重可以基於高斯分布。至關重要的是,權重不僅取決於歐幾里德像素距離,還取決於輻射度差異。例如,范圍差異,例如顏色強度,深度距離等。這通過系統地循環每個像素並相應地調整相鄰像素的權重來保留銳邊。

參數 描述
src 原圖片
dst 目標圖片,形狀與原圖片相同
d 過濾期間使用的每個像素鄰域的直徑。如果它是負數,則從sigmaSpace計算。
sigmaColor 在顏色空間進行過濾,參數的值越大意味着像素鄰域內的更遠的顏色(參見sigmaSpace)將混合在一起,從而產生更大的半等顏色區域。
sigmaSpace 在坐標空間進行過濾,較大的參數值意味着只要它們的顏色足夠接近,更遠的像素就會相互影響(參見sigmaColor)。當d> 0時,無論sigmaSpace如何,它都指定鄰域大小。否則,d與sigmaSpace成比例。

將上面的代碼修改為雙邊濾波,與高斯模糊進行對比:

blur3 = cv2.bilateralFilter(img,20,75,75)

效果:

可見,保留了線條,但臉部明顯已被模糊。

 

2D卷積

與一維信號一樣,圖像也可以使用各種低通濾波器(LPF),高通濾波器(HPF)等進行濾波.LPF有助於消除噪聲,模糊圖像等.HPF濾波器有助於查找邊緣圖片。

OpenCV提供了一個函數cv2.filter2D()來將自定義內核與圖像進行卷積。

例如,為了簡便仍使用平均值,我們將嘗試對圖像進行平均濾波。 5x5平均濾波器內核如下所示:

$$K = \frac{1}{25} \begin{bmatrix} 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \end{bmatrix}$$

操作是這樣的:將此內核保持在像素上方,添加該內核下方的所有25個像素,取其平均值並用新的平均值替換中心像素。它繼續對圖像中的所有像素執行此操作。試試這段代碼並檢查結果:

import cv2
import numpy as np

img = cv2.imread("./Pictures/girl.png")

blur2 = cv2.blur(img,(5,5),cv2.BORDER_DEFAULT)

kernel = np.ones((5,5),np.float32)/25
blur3 = cv2.filter2D(img,-1,kernel)

htich = np.hstack((img,blur2,blur3))
cv2.imwrite("./Pictures/mreger_img.png", htich)
cv2.imshow("merged_img", htich)
cv2.waitKey(0)
cv2.destroyAllWindows()

效果:

 

 

 

參考鏈接:

1、高斯模糊https://www.tutorialkart.com/opencv/python/opencv-python-gaussian-image-smoothing/

2、雙邊濾波http://opencvexamples.blogspot.com/2013/10/applying-bilateral-filter.html

3、官方文檔https://docs.opencv.org/3.1.0/d4/d13/tutorial_py_filtering.html

4、cv2.filter2D示例https://www.programcreek.com/python/example/89373/cv2.filter2D


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM