OpenCV圖像卷積之cv.filter2D()函數(shù)詳解
API
照例,我們搬一下官網(wǎng)的 API:
C++
void cv::filter2D(InputArray src, OutputArray dst, int ddepth, InputArray kernel, Point anchor=Point(-1, -1), double delta=0, int borderType=BORDER_DEFAULT )
Python
dst=cv.filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]])
函數(shù)詳解
這個函數(shù)一般是用于圖像的卷積,但 OpenCV 文檔里說這個函數(shù)不完全等于圖像卷積。這一點說實話我看到的時候也震驚到了,我一直是拿它當(dāng)卷積來用的。但是仔細(xì)考慮后,我認(rèn)為這一點完全是定義上的差異,日常用的圖像卷積定義和這個函數(shù)的功能實際上是一致的。
HelloWorld
直接上手做往往能給人最直觀的感受。因此,最開始這里我要放一個使用這個函數(shù)的最小化程序,可以稱之為該函數(shù)的 hello world 程序。這個程序跑通了,就可以很方便地嘗試其他參數(shù)的作用了。
# HelloWrold Program of cv.filter2D # by Aling on 2021/1/18 import numpy as np import cv2 as cv def main(): img = cv.imread("你想讀的圖片") # 定義卷積核 kernel = np.ones((10, 10)) / 100 # 執(zhí)行濾波 avg_filtered = cv.filter2D(img, -1, kernel) # 顯示圖片 cv.imshow("Average filtered", avg_filtered) cv.waitKey(0) cv.destroyAllWindows() if __name__ == "__main__": main()
這個程序讀取一張圖片,并將其通過10 x 10 的卷積核作均值濾波并顯示結(jié)果。
參數(shù)詳解
同樣的,這里把各個參數(shù)打一張表:
參數(shù) | 類型 | 是否必須指定(默認(rèn)值) | 具體含義 |
---|---|---|---|
src | numpy.ndarray | 是 | 原圖像 |
ddepth | int | 是 | 目標(biāo)圖像深度(指數(shù)據(jù)類型) |
kernel | numpy.ndarray | 是 | 卷積核 |
anchor | tuple | 否(卷積核中心) | 卷積錨點 |
delta | 是數(shù)據(jù)類就行 | 否(0) | 偏移量,卷積結(jié)果要加上這個數(shù)字 |
borderType | int (實際上是 enum 類) | 否(cv.BORDER_DEFALUT ) | 邊緣類型 |
src
這個參數(shù)沒什么好說的,就是原圖像。它可以是任何色彩模式,這就意味著如果你把原本送到這個函數(shù)里的圖片從黑白變成了彩色(單通道變成了 3 通道),你并不需要更改其他參數(shù)。本身,對多通道的圖像,卷積就是以通道為單位進(jìn)行的。
ddepth
這個參數(shù)有點費解了。大部分情況下不需要管它是干嘛的,直接把它設(shè)成 -1 就沒有任何問題。
參數(shù)名 ddepth
,英文是 desired depth,即期望深度。什么意思呢?我們來看它的可能取值表(來自這里):
輸入深度(src.depth() ) | 期望深度(ddepth ) |
---|---|
CV_8U | -1/CV_16S/CV_32F/CV_64F |
CV_16U/CV_16S | -1/CV_32F/CV_64F |
CV_32F | -1/CV_32F/CV_64F |
CV_64F | -1/CV_64F |
這個表里的一大串 CV
打頭的符號到底是什么意思呢?實際上這些符號的末尾字母對應(yīng)了數(shù)據(jù)類型:
U == Unsigned int # 無符號整型 S == Signed int # 有符號整型 F == Float # 浮點型
中間的數(shù)字很顯然代表了數(shù)據(jù)類型所占用的空間(bit)。所以,所謂深度,其實指的是數(shù)據(jù)類型。
那就好說了,你會發(fā)現(xiàn)這里其實是規(guī)定了輸出數(shù)據(jù)的類型,包括每個通道的每個像素占用多少空間。輸出數(shù)據(jù)的類型必須根據(jù)上面的表格中輸入對應(yīng)的類型指定。這里 -1 表示輸出類型和輸入相同。
不過,值得注意的是,似乎有些數(shù)據(jù)類型無法通過 cv2.imshow
正常顯示,可以用 matplotlib.pyplot.imshow
來代替。
但是,還是注意,沒有關(guān)于數(shù)據(jù)類型的特別要求時,這個功能是不需要的,取 -1 即可。
kernel & anchor
這兩個參數(shù)都是卷積相關(guān)的,因此放在一節(jié)里面講述。接下來的內(nèi)容假設(shè)你已經(jīng)了解了圖像卷積。
這里,kernel
很顯然表示的是卷積核,這是一個 numpy.ndarray
類型的矩陣。這個矩陣的生成可以用 numpy
自帶的函數(shù),但是對于復(fù)雜一些的卷積核,OpenCV 內(nèi)部的一些函數(shù)顯然更合適。如 getStructuringElement
,getGaussianKernel
,前者用于獲取特定形狀的核,后者則是高斯核生生成器(不過要注意生成的是一個向量)。
# 方法一示例 kernel = cv.getStructuringElement(cv.MORPH_RECT, (11, 11)) # 方法二示例 vector = cv.getGaussianKernel(11, -1) kernel = vector @ vector.T
anchor
則表示錨點。什么叫錨點呢?看下面這張圖:
可以說,錨點 anchor
決定了卷積核相對于生成目標(biāo)點的位置。雖然錨點是相對于卷積核來定義的,但是卷積的過程更像是通過錨點去尋找卷積核。遍歷圖像中的每一個像素,以每一個像素為錨點,按照相對位置生成卷積范圍,和卷積核對應(yīng)元素相乘再求和得到目標(biāo)圖像中對應(yīng)像素的值??梢杂霉奖硎境桑?/p>
這實際上就是一般的圖像卷積計算方法。OpenCV 文檔里面敘述的卷積定義則是需要將卷積核圍繞錨點對稱變換,再用上面的公式計算。這種方法更接近卷積原始的定義,但是對圖像的卷積一般的應(yīng)用而言(濾波、深度學(xué)習(xí))這兩種定義實際上沒有什么區(qū)別。、
錨點用一個元組指定,是相對于卷積核左上角的坐標(biāo),從 0 開始:
# 替換掉 HelloWorld 程序的對應(yīng)行。 avg_filtered = cv.filter2D(img, -1, kernel, (1, 2))
delta
這個參數(shù)的存在其實有些費解,它的效果很簡單,就是把卷積的結(jié)果加上一個固定的數(shù)字。直觀上將,它將整個圖像變亮或者變暗了。從應(yīng)用上來說,它實際上將卷積過程擴(kuò)展成了一般的線性運算( ∗ * ∗ 表示卷積):
這個線性運算可以將結(jié)果限定在某一符合要求的范圍內(nèi)(比如大于 0),而且不會阻斷梯度的傳遞。
borderType
這個參數(shù)更改的是 border 的生成方式。這個 border,也就是邊緣,是在靠近邊緣的部分卷積時用到的,參考上面那張圖。無論 anchor
是什么,總有些邊緣上的點對應(yīng)的卷積范圍無法完全落在原圖內(nèi),這就需要對原圖進(jìn)行擴(kuò)展。擴(kuò)展的方法就是我們這里參數(shù)的含義。
這個參數(shù)取值是 OpenCV 里的 cv::BorderTypes
enum 類定義的值,其可能取值及其對于邊緣的作用結(jié)果如下圖所示(圖片來自 OpenCV Python 教程):
要注意幾點:
cv.BORDER_WARP
在這個函數(shù)里面是不支持的;cv.BORDER_CONSTANT
會將邊緣取為 0(黑色),而且沒法改,因為原函數(shù)并沒有留出相關(guān)的接口。
擴(kuò)展——濾波相關(guān)函數(shù)
圖像濾波是一個很常用的功能,對此,OpenCV 也定義了很多函數(shù)。這里介紹的 cv.filter2D
是這些函數(shù)中可控性最高的,因為你可以用自定義的核進(jìn)行卷積。但是一些常用的濾波,我們可以不必自己定義相應(yīng)的核,直接用定義好的函數(shù)就可以了。
均值濾波
dst = cv.blur(img, (11, 11)) # 等效于: dst = cv.filter2D(img, -1, np.ones((11, 11))/11**2)
高斯濾波
dst = cv.GaussianBlur(img, (11, 11), -1) # 等效于 vector = cv.getGaussianKernel(11, -1) kernel = vector @ vector.T dst = cv.filter2D(img, -1, kernel)
中值濾波
dst = cv.medianBlur(img, 11)
注意中值濾波是取中位數(shù)作為目標(biāo)值,是一個非線性濾波子,因此無法通過線性濾波的 cv.filter2D
來等效實現(xiàn)。
參考鏈接
總結(jié)
到此這篇關(guān)于OpenCV圖像卷積之cv.filter2D()函數(shù)詳解的文章就介紹到這了,更多相關(guān)OpenCV圖像卷積cv.filter2D()函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python獲取和設(shè)置代理的動態(tài)IP的方式
在網(wǎng)絡(luò)世界中,代理和動態(tài)IP是非常常見的概念,尤其對于需要大規(guī)模訪問網(wǎng)站或者需要隱藏真實IP地址的應(yīng)用程序來說,更是必不可少的工具,本文將給大家介紹如何使用編程技術(shù)來實現(xiàn)動態(tài)IP的設(shè)置和管理,需要的朋友可以參考下2024-05-05python3反轉(zhuǎn)字符串的3種方法(小結(jié))
這篇文章主要介紹了python3反轉(zhuǎn)字符串的3種方法(小結(jié)),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11python學(xué)習(xí)之panda數(shù)據(jù)分析核心支持庫
這篇文章主要給大家介紹了關(guān)于python學(xué)習(xí)之panda數(shù)據(jù)分析核心支持庫的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05Python的socket模塊源碼中的一些實現(xiàn)要點分析
我們平時引入Python的socket模塊利用其中的方法可以輕松地寫出搭建socket通信的程序,今天我們就來看一下Python的socket模塊源碼中的一些實現(xiàn)要點分析,領(lǐng)略Python簡潔代碼的一些背后功勞.2016-06-06