1. 程式人生 > >Opencv中cvFilter2D卷積函式的計算過程分析

Opencv中cvFilter2D卷積函式的計算過程分析

接上一篇,介紹了矩陣卷積的計算方法,我們選擇了用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是邊緣拷貝,通過邊緣拷貝補全矩陣進行計算。