2013-07-31 36 views
2

我正在嘗試將一些代碼從Matlab遷移到Opencv,並且需要一個精確的梯度函數副本。我已經嘗試過cv :: Sobel函數,但由於某些原因,生成的cv :: Mat中的值與Matlab版本中的值不同。我需要在單獨的矩陣中使用X和Y梯度來進行進一步的計算。matlab在opencv中的梯度等效函數

任何變通方法,可以實現,這將是巨大的

+0

'CV ::索貝爾()'正是你想要的。如果您發佈您使用的代碼(以及您期望輸出的代碼),我們可以查看並查看您的問題。 – Aurelius

回答

0

你必須調用索貝爾2次,用參數:

xorder = 1, yorder = 0 

xorder = 0, yorder = 1 

你必須選擇合適的內核尺寸。

documentation

它可能仍然是這個Matlab實現不同,最好你應該檢索的內核使用有...

編輯:

如果需要指定你自己的內核,你可以使用更通用的filter2D。您的目的地深度將爲CV_16S(16位有符號)。

+0

我仍然不確定使用哪種borderType會產生類似的結果。對這些的更詳細的解釋將真的有幫助 –

+0

我正在尋找matlab梯度和cv :: Sobel之後的矩陣精確結果。 –

+0

@ArpanShah是否清楚邊界類型隻影響圖像邊界上的像素(因此,如果您的內核大小爲3,則爲第一行,第一列,最後一行,最後一列,否則爲前2行,前2列等)。如果你的內核大小是5,依此類推)。只有當你計算Sobel的區域不是整個圖像時,纔會使用與默認值不同的東西,但是其中的某些區域超出區域限制的信息仍然有意義 – Antonio

0

Matlab對內部行和邊界行計算不同的漸變(對於列當然也是如此)。在邊界,這是一個簡單的前向差異gradY(1) = row(2) - row(1)。內部行的梯度由中心差gradY(2) = (row(3) - row(1))/2計算。

我想你不能在OpenCV中的整個矩陣上運行單個卷積濾波器來獲得相同的結果。使用cv::Sobel()ksize = 1,然後處理邊界(手動或通過應用[1 -1]過濾器)。

6

索貝爾只能計算圖像像素的二階導數,這不是我們想要的。

(F(1 + 1,J)+ F(I-1,J) - 2F(I,J))/ 2

我們要的是

(F(1 + I,J)-f(I-1,J))/ 2

因此,我們需要應用

Mat kernelx = (Mat_<float>(1,3)<<-0.5, 0, 0.5); 
Mat kernely = (Mat_<float>(3,1)<<-0.5, 0, 0.5); 
filter2D(src, fx, -1, kernelx) 
filter2D(src, fy, -1, kernely); 

Matlab將邊界像素與內部像素區別開來。所以上面的代碼在邊界值上是錯誤的。可以使用BORDER_CONSTANT以一個常數擴展邊界值,不幸的是常數是OpenCV的-1,不能改爲0(這是我們想要的)。

關於邊界值,我沒有一個非常簡潔的答案。只要嘗試用手來計算一階導數...

+1

哦,事實上,你可以使用copyMakeBorder()來擴展具有特定常數值的Mat的邊界。 –

0

裴的回答是部分正確的。Matlab使用這些計算邊界:

G(:,1)= A(:,2) - A(:,1); G(:,N)= A(:,N)-A(:,N-1);

所以用下面的OpenCV的代碼來完成的梯度:

static cv::Mat kernelx = (cv::Mat_<double>(1, 3) << -0.5, 0, 0.5); 
static cv::Mat kernely = (cv::Mat_<double>(3, 1) << -0.5, 0, 0.5); 
cv::Mat fx, fy; 

cv::filter2D(Image, fx, -1, kernelx, cv::Point(-1, -1), 0, cv::BORDER_REPLICATE); 
cv::filter2D(Image, fy, -1, kernely, cv::Point(-1, -1), 0, cv::BORDER_REPLICATE); 

fx.col(fx.cols - 1) *= 2; 
fx.col(0) *= 2; 
fy.row(fy.rows - 1) *= 2; 
fy.row(0) *= 2;