天天看點

OpenCV實作自己的線性濾波器 C++

卷積

卷積是在每一個圖像塊與某個算子(核)之間進行的運算。

核說白了就是一個固定大小的數值數組。該數組帶有一個 錨點 ,一般位于數組中央。

OpenCV實作自己的線性濾波器 C++

如何用核實作卷積

假如你想得到圖像的某個特定位置的卷積值,可用下列方法計算:

  1. 将核的錨點放在該特定位置的像素上,同時,核内的其他值與該像素鄰域的各像素重合;
  2. 将核内各值與相應像素值相乘,并将乘積相加;
  3. 将所得結果放到與錨點對應的像素上;
  4. 對圖像所有像素重複上述過程。

用公式表示上述過程如下:

OpenCV實作自己的線性濾波器 C++

幸運的是,我們不必自己去實作這些運算,OpenCV為我們提供了函數 filter2D 。

代碼實作:

  • 載入一幅圖像
  • 對圖像執行 歸一化塊濾波器 。舉例來說,如果該濾波器核的大小為 
    OpenCV實作自己的線性濾波器 C++
     ,則它會像下面這樣:
    OpenCV實作自己的線性濾波器 C++
    程式将執行核的大小分别為3、5、7、9、11的濾波器運算。
  • 該濾波器每一種核的輸出将在螢幕上顯示2秒
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>

using namespace cv;

/** @函數main */
int main ( int argc, char** argv )
{
  /// 聲明變量
  Mat src, dst;

  Mat kernel;
  Point anchor;
  double delta;
  int ddepth;
  int kernel_size;
  char* window_name = "filter2D Demo";

  int c;

  /// 載入圖像
  src = imread( argv[1] );

  if( !src.data )
  { return -1; }

  /// 建立視窗
  namedWindow( window_name, CV_WINDOW_AUTOSIZE );

  /// 初始化濾波器參數
  anchor = Point( -1, -1 );
  delta = 0;
  ddepth = -1;

  /// 循環 - 每隔0.5秒,用一個不同的核來對圖像進行濾波
  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(src, dst, ddepth , kernel, anchor, delta, BORDER_DEFAULT );
      imshow( window_name, dst );
      ind++;
    }

  return 0;
}
           

效果:

OpenCV實作自己的線性濾波器 C++

增加邊界填充:

#include "opencv2/imgproc/imgproc.hpp"

#include "opencv2/highgui/highgui.hpp"

#include <stdlib.h>

#include <stdio.h>

using namespace cv;

/// 全局變量

int top, bottom, left, right;

int borderType;

Scalar value;

char* window_name = "copyMakeBorder Demo";

RNG rng(12345);

int main ( int argc, char** argv )

{

    /// 聲明變量

    Mat src, dst;

    Mat kernel;

    Point anchor;

    double delta;

    int ddepth;

    int kernel_size;

    char* window_name = "filter2D Demo";

    /// 載入圖像

    src = imread( argv[1] );

    if( !src.data )

        return -1;

    namedWindow( window_name, CV_WINDOW_AUTOSIZE );

    /// 初始化輸入參數

    top = (int) (0.05*src.rows); bottom = (int) (0.05*src.rows);

    left = (int) (0.05*src.cols); right = (int) (0.05*src.cols);

    dst = src;

    imshow( window_name, dst );

    // 初始化濾波器參數

    anchor = Point( -1, -1 );

    delta = 0;

    ddepth = -1;

    // 循環 - 每隔2秒,用一個不同的核來對圖像進行濾波

    int ind = 0;

    while( true )

    {

      int c = waitKey(2000);

      if( (char)c == 27 ){                /// 按'ESC'可退出程式

          break;

      }else if( (char)c == 'c' ){

          borderType = BORDER_CONSTANT;

      }else if( (char)c == 'r' ){

          borderType = BORDER_REPLICATE;

      }

      /// 更新歸一化塊濾波器的核大小

      kernel_size = 3 + 2*( ind%5 );

      kernel = Mat::ones( kernel_size, kernel_size, CV_32F )/ (float)(kernel_size*kernel_size);

      /// 使用濾波器

      filter2D(src, dst, ddepth , kernel, anchor, delta, BORDER_DEFAULT );

      value = Scalar( rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255) );

      copyMakeBorder( dst, dst, top, bottom, left, right, borderType, value );

      imshow( window_name, dst );

      ind++;

    }

    return 0;

}

效果:

OpenCV實作自己的線性濾波器 C++

繼續閱讀