Opencv中cvFilter2D卷積函式的計算過程分析
阿新 • • 發佈:2019-01-29
接上一篇,介紹了矩陣卷積的計算方法,我們選擇了用0來補全,但是在Opencv中的CVFilter2D函式是用邊緣拷貝的方式。
CvFilter2D函式
void cvFilter2D( const CvArr* src, CvArr* dst, const CvMat* kernel, CvPoint anchor=cvPoint(-1,-1)); src 輸入影象. dst 輸出影象. kernel 卷積核, 單通道浮點矩陣. 如果想要應用不同的核於不同的通道,先用 cvSplit 函式分解影象到單個色彩通道上,然後單獨處理。 anchor 核的錨點表示一個被濾波的點在核內的位置。 錨點應該處於核內部。預設值 (-1,-1) 表示錨點在核中心。 函式 cvFilter2D 對影象進行線性濾波,支援 In-place 操作。當核運算部分超出輸入影象時,函式從最近鄰的影象內部象素差值得到邊界外面的象素值。
嘗試
先上程式碼,
#include<opencv2\opencv.hpp> using namespace cv; using namespace std; //列印 void ShowMat(CvMat *m) { int i, j; for (i = 0; i<m->rows; i++) { for (j = 0; j<m->cols; j++) { double ImgPixelVal = cvGetReal2D(m, i, j); cout << ImgPixelVal << " "; } cout << endl; } } int main() { //卷積核 float A[] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, -1.0, -2.0, -1.0 }; float B[] = { 9,8,7, 4,5,6, 7,8,9 }; CvMat Ma = cvMat(3, 3, CV_32FC1, A);//核矩陣 cout << "卷積核" << endl; ShowMat(&Ma); cout << endl; CvMat Mb = cvMat(3, 3, CV_32FC1, B);//輸入 //原矩陣 cout << "原矩陣" << endl; ShowMat(&Mb); cout << endl; CvMat *C = cvCreateMat(3, 3, CV_32FC1); cvFilter2D(&Mb, C, &Ma, cvPoint(1, 1)); //輸出後 cout << "卷積後" << endl; ShowMat(C); cout << endl; }
輸出的結果
為了不讓資料有偶然性,所以卷積核很古怪,大家不要在意,我們只是要研究他的計算過程。
首先我們發現91 這個值就是 1*9+2*8+3*7+4*4+5*5+6*6-1*7-2*8-1*9=91。即對應的元素相乘後,求和。而且卷積核沒有旋轉180°
然後我們可以看到如果用我上一篇介紹的邊緣用0補全,是得不到這個結果的,所以我們肯定Opencv不是用0補全。
那下面的問題就是Opencv到底是怎麼補全的
問號裡面該填什麼
???
???
之後,我們就猜測是不是邊緣複製,
==========》
通過計算後發現,果然是這樣。1*9+2*9+3*8+4*9+5*9+6*8-1*4-2*4-1*5=163
其他也逐一驗證 。
結論:
1.Opencv中,卷積核不會進行180°的旋轉
2.CvFilter2D是邊緣拷貝,通過邊緣拷貝補全矩陣進行計算。