OpenCV圖像濾波算法總結(Python)

參考博客:https://www.cnblogs.com/FHC1994/p/9097231.html
https://blog.csdn.net/wsp_1138886114/article/details/82872838#11__7
https://blog.csdn.net/wangleixian/article/details/78237597
https://www.zhihu.com/question/54918332/answer/142137732

一.圖像的濾波處理

**過濾 :**是信號和圖像處理中基本的任務。其目的是根據應用環境的不同,選擇性的提取圖像中某些認爲是重要的信息。過濾可以移除圖像中的噪音、提取感興趣的可視特徵、允許圖像重採樣等等。
**頻域分析 :**將圖像分成從低頻到高頻的不同部分。低頻對應圖像強度變化小的區域,而高頻是圖像強度變化非常大的區域。在頻率分析領域的框架中,濾波器是一個用來增強圖像中某個波段或頻率並阻塞(或降低)其他頻率波段的操作。低通濾波器是消除圖像中高頻部分,但保留低頻部分。高通濾波器消除低頻部分。

  • 濾波(高通、低通、帶通、帶阻) 、模糊、去噪、平滑等。

1、均值模糊(低通濾波)、中值模糊(中值濾波)、用戶自定義模糊

import cv2
import numpy as np


def blur_demo(image):
    """
    均值模糊 : 去隨機噪聲有很好的去噪效果
    (1, 15)是垂直方向模糊,(15, 1)是水平方向模糊
    """
    dst = cv2.blur(image, (1, 15))
    cv2.imshow("avg_blur_demo", dst)


def median_blur_demo(image):    # 中值模糊  對椒鹽噪聲有很好的去燥效果
    dst = cv2.medianBlur(image, 5)
    cv2.imshow("median_blur_demo", dst)


def custom_blur_demo(image):
    """
    用戶自定義模糊
    下面除以25是防止數值溢出
    """
    kernel = np.ones([5, 5], np.float32)/25
    dst = cv2.filter2D(image, -1, kernel)
    cv2.imshow("custom_blur_demo", dst)


src = cv2.imread("C:\\Users\\Tony.Hsu\\Desktop\\cat.jpg")
img = cv2.resize(src, None, fx=0.8, fy=0.8, interpolation=cv2.INTER_CUBIC)
cv2.imshow('input_image', img)

blur_demo(img)
median_blur_demo(img)
custom_blur_demo(img)

cv2.waitKey(0)
cv2.destroyAllWindows()

結果如下:
在這裏插入圖片描述
注意:

  1. 均值濾波是典型的線性濾波算法,它是指在圖像上對目標像素給一個模板,該模板包括了其周圍的臨近像素(以目標像素爲中心的周圍8個像素,構成一個濾波模板,即去掉目標像素本身),再用模板中的全體像素的平均值來代替原來像素值。
    低通濾波(均值模糊)函數原型:blur(src, ksize[, dst[, anchor[, borderType]]]) -> dst
    src參數表示待處理的輸入圖像。
    ksize參數表示模糊內核大小。比如(1,15)表示生成的模糊內核是一個1*15的矩陣。
    dst參數表示輸出與src相同大小和類型的圖像。
    anchor參數、borderType參數可忽略.
  2. 中值濾波法是一種非線性平滑技術,它將每一像素點的灰度值設置爲該點某鄰域窗口內的所有像素點灰度值的中值。具體原理參見博客:https://blog.csdn.net/weixin_37720172/article/details/72627543
    中值濾波(中值模糊)函數原型:medianBlur(src, ksize[, dst]) -> dst
    src參數表示待處理的輸入圖像。
    ksize參數表示濾波窗口尺寸,必須是奇數並且大於1。比如這裏是5,中值濾波器就會使用5×5的範圍來計算,即對像素的中心值及其5×5鄰域組成了一個數值集,對其進行處理計算,當前像素被其中值替換掉。
    dst參數表示輸出與src相同大小和類型的圖像。
  3. 用戶自定義模糊------所用函數:filter2D()
    函數原型: filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]]) -> dst
    src參數表示待處理的輸入圖像。
    ddepth參數表示目標圖像深度,輸入值爲-1時,目標圖像和原圖像深度保持一致
    kernel: 卷積核(或者是相關核),一個單通道浮點型矩陣。修改kernel矩陣即可實現不同的模糊

2.高斯模糊/濾波------去噪效果好

# 高斯模糊    輪廓還在,保留圖像的主要特徵  高斯模糊比均值模糊去噪效果好
import cv2
import numpy as np


def clamp(pv):
    """防止顏色值超出顏色取值範圍(0-255)"""
    if pv > 255:
        return 255
    if pv < 0:
        return 0
    else:
        return pv


def gaussian_noise(image):        # 加高斯噪聲
    h, w, c = image.shape
    for row in range(h):
        for col in range(w):
            # 獲取三個高斯隨機數
            # 第一個參數:概率分佈的均值,對應着整個分佈的中心
            # 第二個參數:概率分佈的標準差,對應於分佈的寬度
            # 第三個參數:生成高斯隨機數數量
            s = np.random.normal(0, 20, 3)
            # 獲取每個像素點的bgr值
            b = image[row, col, 0]   # blue
            g = image[row, col, 1]   # green
            r = image[row, col, 2]   # red
            # 給每個像素值設置新的bgr值
            image[row, col, 0] = clamp(b + s[0])
            image[row, col, 1] = clamp(g + s[1])
            image[row, col, 2] = clamp(r + s[2])
    cv2.namedWindow("noise image", cv2.WINDOW_NORMAL)
    cv2.imshow("noise image", image)
    dst = cv2.GaussianBlur(image, (15, 15), 0)  # 高斯模糊
    cv2.namedWindow("Gaussian", cv2.WINDOW_NORMAL)
    cv2.imshow("Gaussian", dst)


# 讀入圖片
src = cv2.imread('C:\\Users\\Tony.Hsu\\Desktop\\cat.jpg')
cv2.namedWindow("input_image", cv2.WINDOW_NORMAL)
cv2.imshow('input_image', src)

gaussian_noise(src)
# 給圖片創建毛玻璃特效
# 第二個參數:高斯核的寬和高(建議是奇數)
# 第三個參數:x和y軸的標準差
dst = cv2.GaussianBlur(src, (15, 15), 0)   # 高斯模糊
cv2.namedWindow("Gaussian Blur", cv2.WINDOW_NORMAL)
cv2.imshow("Gaussian Blur", dst)

結果如下:
在這裏插入圖片描述

注意:
1.高斯模糊實質上就是一種均值模糊,只是高斯模糊是按照加權平均的,距離越近的點權重越大,距離越遠的點權重越小。通俗的講,高斯濾波就是對整幅圖像進行加權平均的過程,每一個像素點的值,都由其本身和鄰域內的其他像素值經過加權平均後得到。
2. 高斯模糊GaussianBlur函數原型:GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]]) -> dst
src參數表示待處理的輸入圖像。
ksize參數表示高斯濾波器模板大小。 ksize.width和ksize.height可以不同,但它們都必須是正數和奇數。或者,它們可以是零,即(0, 0),然後從σ計算出來。
sigmaX參數表示 X方向上的高斯內核標準差。
sigmaY參數表示 Y方向上的高斯內核標準差。 如果sigmaY爲零,則設置爲等於sigmaX,如果兩個sigma均爲零,則分別從ksize.width和ksize.height計算得到。
  補:若ksize不爲(0, 0),則按照ksize計算,後面的sigmaX沒有意義。若ksize爲(0, 0),則根據後面的sigmaX計算ksize

3.numpy包裏的random模塊用於生成隨機數,random模塊裏的normal函數表示的是生成高斯隨機數。
normal函數默認原型:normal(loc=0.0, scale=1.0, size=None)。
loc參數表示高斯分佈的中心點。
scale參數表示高斯分佈的標準差σ。
size參數表示產生隨機數的個數。size取值可以爲(m,n,k),表示繪製mnk個樣本。
4.高斯模糊具體原理見博文:https://blog.csdn.net/u012992171/article/details/51023768

3.邊緣保留濾波EPF

"""
    bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]]) -> dst
    - src: 輸入圖像。
    - d:   在過濾期間使用的每個像素鄰域的直徑。如果輸入d非0,則sigmaSpace由d計算得出,如果sigmaColor沒輸入,則sigmaColor由sigmaSpace計算得出。
    - sigmaColor: 色彩空間的標準方差,一般儘可能大。
    較大的參數值意味着像素鄰域內較遠的顏色會混合在一起,
    從而產生更大面積的半相等顏色。
    - sigmaSpace: 座標空間的標準方差(像素單位),一般儘可能小。
    參數值越大意味着只要它們的顏色足夠接近,越遠的像素都會相互影響。
    當d > 0時,它指定鄰域大小而不考慮sigmaSpace。
      否則,d與sigmaSpace成正比。
"""

# 邊緣保留濾波(EPF)  高斯雙邊、均值遷移
import cv2


def bi_demo(image):   # 雙邊濾波
    dst = cv2.bilateralFilter(image, 0, 100, 15)
    cv2.namedWindow("bi_demo", cv2.WINDOW_NORMAL)
    cv2.imshow("bi_demo", dst)


def shift_demo(image):   # 均值遷移
    dst = cv2.pyrMeanShiftFiltering(image, 10, 50)
    cv2.namedWindow("shift_demo", cv2.WINDOW_NORMAL)
    cv2.imshow("shift_demo", dst)


src = cv2.imread('C:\\Users\\Tony.Hsu\\Desktop\\cat.jpg')
cv2.namedWindow('input_image', cv2.WINDOW_NORMAL)
cv2.imshow('input_image', src)

bi_demo(src)
shift_demo(src)

cv2.waitKey(0)
cv2.destroyAllWindows()

結果如下:
在這裏插入圖片描述

注意:
1.雙邊濾波(Bilateral filter)是一種非線性的濾波方法,是結合圖像的空間鄰近度和像素值相似度的一種折中處理,同時考慮空域信息和灰度相似性,達到保邊去噪的目的。雙邊濾波器顧名思義比高斯濾波多了一個高斯方差sigma-d,它是基於空間分佈的高斯濾波函數,所以在邊緣附近,離的較遠的像素不會太多影響到邊緣上的像素值,這樣就保證了邊緣附近像素值的保存。但是由於保存了過多的高頻信息,對於彩色圖像裏的高頻噪聲,雙邊濾波器不能夠乾淨的濾掉,只能夠對於低頻信息進行較好的濾波
2.雙邊濾波函數原型:bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]]) -> dst
src參數表示待處理的輸入圖像。
d參數表示在過濾期間使用的每個像素鄰域的直徑。如果輸入d非0,則sigmaSpace由d計算得出,如果sigmaColor沒輸入,則sigmaColor由sigmaSpace計算得出。
sigmaColor參數表示色彩空間的標準方差,一般儘可能大。較大的參數值意味着像素鄰域內較遠的顏色會混合在一起,從而產生更大面積的半相等顏色。
sigmaSpace參數表示座標空間的標準方差(像素單位),一般儘可能小。參數值越大意味着只要它們的顏色足夠接近,越遠的像素都會相互影響。當d > 0時,它指定鄰域大小而不考慮sigmaSpace。 否則,d與sigmaSpace成正比。

雙邊濾波原理:
https://blog.csdn.net/edogawachia/article/details/78837988,https://blog.csdn.net/MoFMan/article/details/77482794https://www.cnblogs.com/qiqibaby/p/5296681.html
3.均值漂移pyrMeanShiftFiltering函數原型:pyrMeanShiftFiltering(src, sp, sr[, dst[, maxLevel[, termcrit]]]) -> dst
src參數表示輸入圖像,8位,三通道圖像。
sp參數表示漂移物理空間半徑大小。
sr參數表示漂移色彩空間半徑大小。
dst參數表示和源圖象相同大小、相同格式的輸出圖象。
maxLevel參數表示金字塔的最大層數。
termcrit參數表示漂移迭代終止條件。

均值漂移原理:
https://blog.csdn.net/dcrmg/article/details/52705087
https://blog.csdn.net/qq_23968185/article/details/51804574
https://blog.csdn.net/jinshengtao/article/details/30258833

四.高通過濾/濾波(邊緣檢測/高反差保留)

使用的函數有:cv2.Sobel() , cv2.Schar() , cv2.Laplacian()
Sobel,scharr其實是求一階或者二階導數。scharr是對Sobel的優化。
Laplacian是求二階導數。

"""
dst = cv2.Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]])
src:    需要處理的圖像;
ddepth: 圖像的深度,-1表示採用的是與原圖像相同的深度。 
        目標圖像的深度必須大於等於原圖像的深度;
dx和dy: 求導的階數,0表示這個方向上沒有求導,一般爲0、1、2。

dst     不用解釋了;
ksize: Sobel算子的大小,必須爲1、3、5、7。  ksize=-1時,會用3x3的Scharr濾波器,
        它的效果要比3x3的Sobel濾波器要好 
scale: 是縮放導數的比例常數,默認沒有伸縮係數;
delta: 是一個可選的增量,將會加到最終的dst中, 默認情況下沒有額外的值加到dst中
borderType: 是判斷圖像邊界的模式。這個參數默認值爲cv2.BORDER_DEFAULT。

"""

import cv2

img = cv2.imread('C:\\Users\\Tony.Hsu\\Desktop\\cat.jpg', cv2.IMREAD_COLOR)
x = cv2.Sobel(img, cv2.CV_16S, 1, 0)
y = cv2.Sobel(img, cv2.CV_16S, 0, 1)

absx = cv2.convertScaleAbs(x)
absy = cv2.convertScaleAbs(y)
dist = cv2.addWeighted(absx, 0.5, absy, 0.5, 0)

cv2.imshow('original_img', img)
cv2.imshow('y', absy)
cv2.imshow('x', absx)
cv2.imshow('dsit', dist)

cv2.waitKey(0)
cv2.destroyAllWindows()

結果如下:

在這裏插入圖片描述

在這裏插入圖片描述

import cv2

img = cv2.imread('C:\\Users\\Tony.Hsu\\Desktop\\cat.jpg', cv2.IMREAD_COLOR)

laplace = cv2.Laplacian(img, cv2.CV_16S, ksize=3)

laplacian = cv2.convertScaleAbs(laplace)

cv2.imshow('laplacian', laplacian)

cv2.waitKey(0)

cv2.destroyAllWindows()

結果如下:
在這裏插入圖片描述
注意:
1.Sobel算子依然是一種過濾器,只是其是帶有方向的。在OpenCV-Python中,使用Sobel的算子的函數原型如下:
dst = cv2.Sobel(src,ddepth,dx,dy[, dst[, ksize[, scale[, delta[, borderType]]]]])
函數返回其處理結果。
前四個是必須的參數:
第一個參數是需要處理的圖像;
第二個參數是圖像的深度,-1表示採用的是與原圖像相同的深度。目標圖像的深度必須大於等於原圖像的深度;
dx和dy表示的是求導的階數,0表示這個方向上沒有求導,一般爲0、1、2。
其後是可選的參數:
dst不用解釋了;ksize是Sobel算子的大小,必須爲1、3、5、7。 ksize=-1時,會用3x3的Scharr濾波器,它的效果要比3x3的Sobel濾波器要好;
scale是縮放導數的比例常數,默認情況下沒有伸縮係數;
delta是一個可選的增量,將會加到最終的dst中,同樣,默認情況下沒有額外的值加到dst中;
borderType是判斷圖像邊界的模式。這個參數默認值爲cv2.BORDER_DEFAULT。

2.在Sobel函數的第二個參數這裏使用了cv2.CV_16S.因爲OpenCV文檔中對Sobel算子的介紹中有這麼一句:“in the case of 8-bit input images it will result in truncated derivatives".即Sobel建立的圖像位數不夠,會有截斷。因此要使用16位有符號的數據類型,即cv2.CV_16S.在經過處理後,別忘了用convertScaleAbs()函數將其轉回原來的uint8形式。否則將無法顯示圖像,而只是一個黑色窗口。
convertScaleAbs()的原型位——dst = cv2.convertScaleAbs(src[, dst[, alpha[, beta]]]),其中可選參數alpha是伸縮係數,beta是加到結果上的一個值。結果返回uint8類型的圖片。

3.Laplace算子的函數原型如下: dst = cv2.Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]])——前兩個是必須的參數:第一個參數是需要處理的圖像,第二個參數是圖像的深度,-1表示採用的是與原圖相同的深度。目標圖像的深度必須大於等於原圖的深度。
dst不用解釋了;ksize是Sobel算子的大小,必須爲1、3、5、7。 ksize=-1時,會用3x3的Scharr濾波器,它的效果要比3x3的Sobel濾波器要好;
scale是縮放導數的比例常數,默認情況下沒有伸縮係數;
delta是一個可選的增量,將會加到最終的dst中,同樣,默認情況下沒有額外的值加到dst中;
borderType是判斷圖像邊界的模式。這個參數默認值爲cv2.BORDER_DEFAULT。

4.opencv官方文檔:
https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_filtering/py_filtering.html?highlight=filter

發佈了24 篇原創文章 · 獲贊 6 · 訪問量 3692
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章