1 空間濾波
1.1 基本概念
空間域,在圖像處理中,指的是像平面本身; 空間濾波,則是在像平面內,對像素值所進行的濾波處理。
如上圖所示,假設點 $(x, y)$ 為圖像 $f$ 中的任意點,中間正方形是該點的 3x3 鄰域 (也稱為 “濾波器”)
當該鄰域,從圖像的左上角開始,以水平掃描的方式,逐個像素移動,最后到右下角時,便會產生一幅新的圖像。
1.2 濾波機制
若輸入圖像為 $f(x, y)$,則經空間濾波后,輸出圖像 $g(x, y)$ 為
$\quad g(x, y) = \sum \limits_{s=-a}^a \: \sum \limits_{t=-b}^b {w(s, t)\:f(x+s, y+t)} $,其中 $w(s, t)$ 為濾波器模板
更形象的解釋,如下圖:卷積核 (也即旋轉180°的濾波器模板) 像手電筒一樣,對圖像 $f(x, y)$ 中的像素,從左至右從上到下,逐個掃描計算后,便得到了輸出圖像 $g(x, y)$
1.3 相關和卷積
空間濾波中,相關和卷積,是兩個容易混淆的概念,以下面的輸入圖像 $f(x,y)$ 和 濾波器模板 $w(x, y)$ 為例:
相關 (Correlation),和上述的濾波機制一樣,即濾波器模板逐行掃描圖像,並計算每個位置像素乘積和的過程。
卷積 (Convolution),和 "相關" 過程類似,但是要首先旋轉 180°,然后再執行和 “相關” 一樣的操作。
二維中的旋轉 180°,等於沿一個坐標軸翻轉該模板,然后再沿另一個坐標軸再次翻轉該模板。
注意:如果濾波器模板是對稱的,則相關和卷積得到的結果是一樣的。
2 filter2D 和 flip
OpenCV 中,用戶可自定義濾波器模板,然后使用 filter2D() 函數,對圖像進行空間濾波
void filter2D ( InputArray src, OutputArray dst, int ddepth, InputArray kernel, Point anchor = Point(-1,-1), double delta = 0, int borderType = BORDER_DEFAULT )
其公式如下:
$ dst(x, y) = \sum \limits_{0 < x' <kernel.cols, \\ 0<y'<kernel.rows} \: kernel(x', y') * src(x+x'-anchor.x, y+y'-anchor.y) $
可以看出,錨點 $(anchor.x, anchor.y)$ 並不是 kernel 的鏡像中心。
實際上,filter2D 求的是 相關,不是 卷積。
要想得到真正的卷積 (convolution),首先,使用 flip() 函數翻轉 kernel,然后,設置新的錨點 $(kernel.cols - anchor.x - 1, kernel.rows -anchor.y -1)$
void flip ( InputArray src, OutputArray dst, int flipCode // 0, flip around x-axis; 1,flip around y-axis; -1, flip around both axes );
3 代碼示例
下面詳細闡述,如何設計濾波器模板,配合 filter2D() 函數,實現圖像的一階和二階偏導運算。
在 x 方向上,一階和二階偏導數的計算結果,如下圖所示:
3.1 一階偏導
圖像在 x 和 y 方向的一階偏導如下:
$\frac {\partial f}{\partial x} = f(x+1,y) - f(x,y)$
$\frac {\partial f}{\partial y} = f(x, y+1) - f(x, y)$
則對應的濾波器模板為 $K_{x} = \begin{bmatrix} -1 & 1 \end{bmatrix} $,$K_{y} = \begin{bmatrix} -1 \\ 1 \end{bmatrix} $
3.2 二階偏導
同樣的,在 x 和 y 方向的二階偏導如下:
$\frac {\partial f^2} {\partial x^2} = f(x+1, y) + f(x-1, y)- 2f(x,y)$
$\frac {\partial f^2}{\partial y^2} = f(x, y+1) + f(x, y-1)- 2f(x,y)$
$\frac {\partial f^2}{\partial x \partial y} = f(x+1, y+1) - f(x+1, y) - f(x, y+1)+ f(x,y)$
則各自的濾波器模板為 $K_{xx} = \begin{bmatrix} 1 & -2 & 1 \end{bmatrix} $,$K_{yy} = \begin{bmatrix} 1 \\ -2 \\ 1 \end{bmatrix} $,$K_{xy} = \begin{bmatrix} 1 & -1 \\ -1 & 1 \end{bmatrix} $
3.3 代碼實現
#include "opencv2/imgproc.hpp" #include "opencv2/highgui.hpp" using namespace cv; int main() { // 讀取圖像 Mat src = imread("test.bmp"); if(src.empty()) { return -1; } cvtColor(src, src, CV_BGR2GRAY); Mat kx = (Mat_<float>(1,2) << -1, 1); // 1行2列的 dx 模板 Mat ky = (Mat_<float>(2,1) << -1, 1); // 2行1列的 dy 模板 Mat kxx = (Mat_<float>(1,3) << 1, -2, 1); // 1行3列的 dxx 模板 Mat kyy = (Mat_<float>(3,1) << 1, -2, 1); // 3行1列的 dyy 模板 Mat kxy = (Mat_<float>(2,2) << 1, -1, -1, 1); // 2行2列的 dxy 模板 // 一階偏導 Mat dx, dy; filter2D(src, dx, CV_32FC1, kx); filter2D(src, dy, CV_32FC1, ky); // 二階偏導 Mat dxx, dyy, dxy; filter2D(src, dxx, CV_32FC1, kxx); filter2D(src, dyy, CV_32FC1, kyy); filter2D(src, dxy, CV_32FC1, kxy); // 顯示圖像 imshow("dx", dx); imshow("dy", dy); imshow("dxx", dxx); imshow("dyy", dyy); imshow("dxy", dxy); waitKey(0); }
以袋裝洗手液作為輸入圖像,得到的偏導圖像如下:
參考資料:
OpenCV Tutorials / imgproc module / Making your own linear filters
<數字圖像處理> 岡薩雷斯, 第3章 灰度變換與空間濾波
圖像卷積與濾波的一些知識點,zouxy09