src 代表:輸入圖像
dst 代表:輸出圖像
kernel代表: 卷積核, 單通道浮點矩陣。 如果想要應用不同的核於不同的通道,先用 cvSplit 函數分解圖像到單個色彩通道上,然後單獨處理。
anchor 代表:核的錨點表示一個被濾波的點在覈內的位置。 錨點應該處於核內部。默認值 (-1,-1) 表示錨點在覈中心。
這裏我們創建一個適當大小的矩陣,將係數連同源圖像和目標圖像一起傳遞給cvFilter2D()。我們還可以有選擇地輸人一個CvPoint指出核的中心位置,默認值(cvPoint (-1, -1))會設參考點爲核的中心。如果定義了參考點,核的大小可以是偶數,否則只能是奇數。
源圖像src和目標圖像dst大小應該相同,有些人可能認爲考慮到卷積核的額外的長和寬,源圖像src應該大於目標圖像dst。但是在OpenCV裏源圖像src和目標圖像dst的大小是可以一樣的,因爲在默認情況下,在卷積之前,OpenCV通過複製源圖像src的邊界創建了虛擬像素,這樣以便於目標圖像dst邊界的像素可以被填充。
這裏我們所討論的卷積核的係數應該是浮點類型的,這就意味着我們必須用CV_32F來初始化矩陣。
下面以《學習OpenCV 》第六章第二題爲例進行距離2、可分核。利用行[ (1/16,2/16,1/16),(2/16,4/16,2/16),(1/16,2/16,1/16)]和在中間的參考點創建一個3*3的高斯核。
a:在一幅圖像上運行此核並且顯示結果。
b: 對a中的卷積矩陣進行可分核處理,並再次顯示。
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
using namespace std;
using namespace cv;
int main(int argc, const char * argv[]) {
/*1、加載一幅灰度圖像*/
const char filename[] = "/Users/linwang/Downloads/30.png";
IplImage * Img = cvLoadImage(filename,CV_LOAD_IMAGE_GRAYSCALE);
/*2、縮小一倍*/
IplImage *out = cvCreateImage(cvSize(Img->width/2,Img->height/2), Img->depth, Img->nChannels);
cvResize(Img, out);
/*3、構造卷積矩陣,生成卷積核*/
float k1[9] = {0.0625, 0.0625 * 2, 0.0625,
0.0625 * 2, 0.0625 * 4, 0.0625 * 2,
0.0625, 0.0625 * 2, 0.0625};
CvMat kernel1 = cvMat(3, 3, CV_32FC1,k1);
cout<<kernel1.rows<<" -> "<<kernel1.cols<<" -> "<<kernel1.step<<" -> "<<endl;
for(int i = 0;i<kernel1.rows;i++)
{
float *ptr1 = kernel1.data.fl + i * kernel1.rows;
for (int j = 0; j<kernel1.cols; j++)
{
cout<<" "<<(*(ptr1 + j ));
}
cout<<endl;
}
/*4、製作一個交叉核(1/4,2/4,1/4),即一維行向量*/
float k2[3] = {0.25,0.5,0.25};
CvMat kernel2 = cvMat(1,3,CV_32FC1,k2);
cout<<kernel2.rows<<" -> "<<kernel2.cols<<" -> "<<kernel2.step<<" -> "<<endl;
for(int i = 0;i<kernel2.rows;i++)
{
float *ptr2 = kernel2.data.fl + i * kernel2.rows;
for (int j = 0; j<kernel2.cols; j++)
{
cout<<" "<<(*(ptr2 + j ));
}
cout<<endl;
}
/*5、製作一個下降核(1/4,2/4,1/4),即一維列向量*/
float k3[3] = {0.25,0.5,0.25};
CvMat kernel3 = cvMat(3,1,CV_32FC1,k3);
cout<<kernel3.rows<<" -> "<<kernel3.cols<<" -> "<<kernel3.step<<" -> "<<endl;
for(int i = 0;i<kernel3.rows;i++)
{
float *ptr3 = kernel3.data.fl + i * kernel3.rows;
for (int j = 0; j<kernel3.cols; j++)
{
cout<<" "<<(*(ptr3 + j ));
}
cout<<endl;
}
/*6、Clone一個dst圖片*/
IplImage * dst1 = cvCloneImage(out);
cvSetZero(dst1);
IplImage * dst2 = cvCloneImage(out);
cvSetZero(dst2);
IplImage * dst3 = cvCloneImage(out);
cvSetZero(dst3);
IplImage * dst4 = cvCloneImage(out);
cvSetZero(dst4);
/*7、進行過濾*/
cvFilter2D(out, dst1, &kernel1);
cvFilter2D(out, dst2, &kernel2);
cvFilter2D(out, dst3, &kernel3);
cvFilter2D(dst2, dst4,&kernel3); //相當於分別在水平和豎直方向進行濾波,分核再合併
/*8、圖片顯示*/
cvShowImage("1/2->Src", out);
cvShowImage("Filter1", dst1);
cvShowImage("Filter2", dst2);
cvShowImage("Filter3", dst3);
cvShowImage("Filter34", dst4);
cvWaitKey(0);
cvReleaseImage(&Img);
cvReleaseImage(&dst1);
cvReleaseImage(&dst2);
cvReleaseImage(&dst3);
return 0;
}