卷積
卷積是在每一個圖像塊與某個算子(核)之間進行的運算。
核
核說白了就是一個固定大小的數值數組。該數組帶有一個 錨點 ,一般位于數組中央。
如何用核實作卷積
假如你想得到圖像的某個特定位置的卷積值,可用下列方法計算:
- 将核的錨點放在該特定位置的像素上,同時,核内的其他值與該像素鄰域的各像素重合;
- 将核内各值與相應像素值相乘,并将乘積相加;
- 将所得結果放到與錨點對應的像素上;
- 對圖像所有像素重複上述過程。
用公式表示上述過程如下:
幸運的是,我們不必自己去實作這些運算,OpenCV為我們提供了函數 filter2D 。
代碼實作:
- 載入一幅圖像
- 對圖像執行 歸一化塊濾波器 。舉例來說,如果該濾波器核的大小為 ,則它會像下面這樣: 程式将執行核的大小分别為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;
}
效果:
增加邊界填充:
#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;
}
效果: