我正在嘗試將一些代碼從Matlab遷移到Opencv,並且需要一個精確的梯度函數副本。我已經嘗試過cv :: Sobel函數,但由於某些原因,生成的cv :: Mat中的值與Matlab版本中的值不同。我需要在單獨的矩陣中使用X和Y梯度來進行進一步的計算。matlab在opencv中的梯度等效函數
任何變通方法,可以實現,這將是巨大的
我正在嘗試將一些代碼從Matlab遷移到Opencv,並且需要一個精確的梯度函數副本。我已經嘗試過cv :: Sobel函數,但由於某些原因,生成的cv :: Mat中的值與Matlab版本中的值不同。我需要在單獨的矩陣中使用X和Y梯度來進行進一步的計算。matlab在opencv中的梯度等效函數
任何變通方法,可以實現,這將是巨大的
你必須調用索貝爾2次,用參數:
xorder = 1, yorder = 0
和
xorder = 0, yorder = 1
你必須選擇合適的內核尺寸。
它可能仍然是這個Matlab實現不同,最好你應該檢索的內核使用有...
編輯:
如果需要指定你自己的內核,你可以使用更通用的filter2D。您的目的地深度將爲CV_16S(16位有符號)。
我仍然不確定使用哪種borderType會產生類似的結果。對這些的更詳細的解釋將真的有幫助 –
我正在尋找matlab梯度和cv :: Sobel之後的矩陣精確結果。 –
@ArpanShah是否清楚邊界類型隻影響圖像邊界上的像素(因此,如果您的內核大小爲3,則爲第一行,第一列,最後一行,最後一列,否則爲前2行,前2列等)。如果你的內核大小是5,依此類推)。只有當你計算Sobel的區域不是整個圖像時,纔會使用與默認值不同的東西,但是其中的某些區域超出區域限制的信息仍然有意義 – Antonio
Matlab對內部行和邊界行計算不同的漸變(對於列當然也是如此)。在邊界,這是一個簡單的前向差異gradY(1) = row(2) - row(1)
。內部行的梯度由中心差gradY(2) = (row(3) - row(1))/2
計算。
我想你不能在OpenCV中的整個矩陣上運行單個卷積濾波器來獲得相同的結果。使用cv::Sobel()
和ksize = 1
,然後處理邊界(手動或通過應用[1 -1]過濾器)。
索貝爾只能計算圖像像素的二階導數,這不是我們想要的。
(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(這是我們想要的)。
關於邊界值,我沒有一個非常簡潔的答案。只要嘗試用手來計算一階導數...
哦,事實上,你可以使用copyMakeBorder()來擴展具有特定常數值的Mat的邊界。 –
裴的回答是部分正確的。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;
'CV ::索貝爾()'正是你想要的。如果您發佈您使用的代碼(以及您期望輸出的代碼),我們可以查看並查看您的問題。 – Aurelius