OpenCV 之 空間濾波

1  空間濾波 

1.1  基本概念

  空間域,在圖像處理中,指的是像平面自己; 空間濾波,則是在像平面內,對像素值所進行的濾波處理。html

     

  如上圖所示,假設點 (x, y) 爲圖像 f 中的任意點,中間正方形是該點的 3x3 鄰域 (也稱爲 「濾波器」)函數

  當該鄰域,從圖像的左上角開始,以水平掃描的方式,逐個像素移動,最後到右下角時,便會產生一幅新的圖像。ui

1.2  濾波機制

 若輸入圖像爲 f(x, y),則經空間濾波後,輸出圖像 g(x, y) 爲spa

 $\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) 爲濾波器模板.net

 

 更形象的解釋,以下圖:卷積核(也即旋轉180°的濾波器模板) 像手電筒同樣,對圖像 f(x, y) 中的像素,從左至右從上到下,逐個掃描計算後,便獲得了輸出圖像 g(x, y)設計

 

1.3  相關和卷積

  空間濾波中,相關和卷積,是兩個容易混淆的概念,如下面的輸入圖像 f(x,y) 和 濾波器模板 w(x, y) 爲例:3d

 

  相關 (Correlation),和上述的濾波機制同樣,即濾波器模板逐行掃描圖像,並計算每一個位置像素乘積和的過程。code

 

  卷積 (Convolution),和 "相關" 過程相似,可是要首先旋轉 180°,而後再執行和 「相關」 同樣的操做。htm

  二維中的旋轉 180°,等於沿一個座標軸翻轉該模板,而後再沿另外一個座標軸再次翻轉該模板。blog

 

    注意:若是濾波器模板是對稱的,則相關和卷積獲得的結果是同樣的。

 

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

相關文章
相關標籤/搜索