opencv學習(三十)之設計線性濾波器filter2D

前面在介紹高斯濾波器的時候我們提到是使用高斯濾波模板kernel與原圖像卷積以達到濾波的效果。通常來講,卷積操作發生於圖像的每一個部分與kernel進行卷積運算,kernel就是一個含有錨點的常數數字,這個錨點通常位於kernel的中心位置。如下圖所示:

這裏寫圖片描述

kernel是怎麼進行卷積運算的的?假設你想知道圖像特定位置的像素經過與kernel卷積運算後的值,遵循以下步驟:
(1). 將kernel的錨點放置到目標像素點上方,kernel其他部分覆蓋像素點領域
(2). 將除錨點及其覆蓋的像素點以外的像素點的值與kernel其他值相乘並相加
(3). 將步驟(2)中得到的結果設置爲圖像目標像素點的像素值
(4). 重複上述三個步驟,用kernel掃描整幅圖像,最終完成對每個像素點的計算
上述運算可以用數學公式概括如下:

這裏寫圖片描述

opencv中提供了filter2D函數來實現圖像的卷積運算,其原型如下:

void cv::filter2D  ( InputArray  src,  
  OutputArray  dst,  
  int  ddepth,  
  InputArray  kernel,  
  Point  anchor = Point(-1,-1),  
  double  delta = 0,  
  int  borderType = BORDER_DEFAULT  
 )  

參數解釋:
. InputArray src: 輸入圖像
. OutputArray dst: 目標圖像,其尺寸和通道與輸入圖像一致
. int ddepth: 期望的目標圖像類型,其對應關係如下:

這裏寫圖片描述

. InputArray kernel: 卷積核kernel,單通道浮點型矩陣, 如果想在不同的通道使用不同的卷積kernel,可以將圖像首先使用split函數將不同的顏色通道分離,然後對每個顏色通道單獨進行處理。
. Point anchor = Point(-1, -1): 錨點,要進行處理的像素值位於kernel中的相對位置,有默認值(-1, -1)位於模板中心。
. double delta = 0: 在存入目標圖像之前可以增加的常數
. int borderType = BORDER_DEFAULT: 用於推斷圖像外部像素的邊界模式,詳細信息可以查看cv::BorderTypes.

該函數適用於任意的線性濾波器,支持就地操作,涉及到圖像外部像素計算則按照指定的邊界模式插入異常像素值。
事實上根據前面的描述我們可以看出函數實際進行的是一種相關運算而非真正意義上的卷積運算,如下:

這裏寫圖片描述

kernel不是錨點周圍的鏡像。如果需要真正的卷積運算,使用cv::flip將內核翻轉並將新的錨點設置爲:

(kernel.cols-anchor.x-1, kernel.rows-anchor.y-1).

如果大尺寸(11或以上)kernel函數使用DFT-based算法(離散傅里葉算法),而對於較小的尺寸函數使用直接算法進行計算

示例程序如下:

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

using namespace std;
using namespace cv;

int main()
{
    Mat srcImage, dstImage;
    srcImage = imread("filter2d.jpg");

    //判斷圖像是否加載成功
    if(!srcImage.data)
    {
        cout << "圖像加載失敗!" << endl;
        return -1;
    }
    else
        cout << "圖像加載成功!" << endl << endl;

    //初始化濾波器參數
    Mat kernel;
    Point anchor;
    double delta;
    int ddepth;
    int kernel_size;

    anchor = Point(-1, -1);
    delta = 0;
    ddepth = -1;

    int c;

    int ind = 0;
    while(true)
    {
        c = waitKey(500);

        //按下ESC退出程序
        if((char)c==27)
        {
            break;
        }

        kernel_size = 3+2*(ind%5);
        kernel = Mat::ones(kernel_size, kernel_size, CV_32F)/(float)(kernel_size*kernel_size);

        //應用濾波器
        filter2D(srcImage, dstImage, ddepth, kernel, anchor, delta, BORDER_DEFAULT);
        cout << "當前濾波器尺寸爲: " << kernel_size << endl;
        imshow("線性濾波器", dstImage);
        ind++;
    }

    return 0;
}

程序運行結果:
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章