在opencv中是否有与matlab conv2相同的函数?
matlab函数conv2是否有直接的opencv函数?我尝试使用cvFilter2D(),但它似乎给了我不同于conv2()的结果。在opencv中是否有与matlab conv2相同的函数?
例如:
CvMat * Aa = cvCreateMat(2, 2, CV_32FC1);
CvMat * Bb = cvCreateMat(2, 2, CV_32FC1);
CvMat * Cc = cvCreateMat(2, 2, CV_32FC1);
cvSetReal2D(Aa, 0, 0, 1);
cvSetReal2D(Aa, 0, 1, 2);
cvSetReal2D(Aa, 1, 0, 3);
cvSetReal2D(Aa, 1, 1, 4);
cvSetReal2D(Bb, 0, 0, 5);
cvSetReal2D(Bb, 0, 1, 5);
cvSetReal2D(Bb, 1, 0, 5);
cvSetReal2D(Bb, 1, 1, 5);
cvFilter2D(Aa, Cc, Bb);
This produces the matrix [20 30; 40 50]
In MATLAB:
>> A=[1 2; 3 4]
A =
1 2
3 4
>> B=[5 5; 5 5]
B =
5 5
5 5
>> conv2(A,B,'shape')
ans =
50 30
35 20
请帮助me.its非常有用me.Thank你。
Regards
Arangarajan。
如果使用卷积,矩阵的边缘会出现问题。卷积掩膜需要矩阵外的值。来自OpenCV和matlab的算法使用不同的策略来解决这个问题。 OpenCV只是复制边界的像素,而matlab只是假设所有这些像素都为零。
所以,如果你想在OpenCV中模拟matlab的行为,你可以手动添加这个零填充。甚至还有专门的功能。让我给你的你的代码是如何可以修改一个例子:
CvMat * Ccb = cvCreateMat(3, 3, CV_32FC1);
CvMat * Aab = cvCreateMat(3, 3, CV_32FC1);
cvCopyMakeBorder(Aa,Aab, cvPoint(0,0),IPL_BORDER_CONSTANT, cvScalarAll(0));
cvFilter2D(Aab, Ccb, Bb);
这给其结果是:
20.000 30.000 20.000
40.000 50.000 30.000
30.000 35.000 20.000
为了让您预期的结果,你只需要删除第一列和行摆脱我们添加的边框引入的额外数据。
数值计算环境Matlab(或例如其自由替代GNU倍频程)提供称为conv2的函数,用于给定矩阵与卷积核的二维卷积。在编写基于免费图像处理库OpenCV的C++代码时,我发现OpenCV目前不提供等效的方法。
尽管有一个filter2D()方法实现了二维相关性,并且可以用来对给定内核的图像进行卷积处理(通过翻转内核并将锚点移动到正确的位置,相应的OpenCV文档页面),那么有一种方法可以提供与Matlab相同的边界处理选项(“完整”,“有效”或“相同”卷积),例如用于比较使用OpenCV在Matlab和C++中实现的相同算法的结果。
这里是我想出了:
enum ConvolutionType {
/* Return the full convolution, including border */
CONVOLUTION_FULL,
/* Return only the part that corresponds to the original image */
CONVOLUTION_SAME,
/* Return only the submatrix containing elements that were not influenced by the border
*/
CONVOLUTION_VALID
};
void conv2(const Mat &img, const Mat& kernel, ConvolutionType type, Mat& dest) {
Mat source = img;
if(CONVOLUTION_FULL == type) {
source = Mat();
const int additionalRows = kernel.rows-1, additionalCols = kernel.cols-1;
copyMakeBorder(img, source, (additionalRows+1)/2, additionalRows/2,
(additionalCols+1)/2, additionalCols/2, BORDER_CONSTANT, Scalar(0));
}
Point anchor(kernel.cols - kernel.cols/2 - 1, kernel.rows - kernel.rows/2 - 1);
int borderMode = BORDER_CONSTANT;
filter2D(source, dest, img.depth(), flip(kernel), anchor, 0, borderMode);
if(CONVOLUTION_VALID == type) {
dest = dest.colRange((kernel.cols-1)/2, dest.cols - kernel.cols/2)
.rowRange((kernel.rows-1)/2, dest.rows - kernel.rows/2);
}
}
在我的单元测试,这种实现产生了那名与Matlab的实现几乎相同的结果。请注意,如果内核足够大,OpenCV和Matlab都会在傅立叶空间中进行卷积。 “大”的定义在两个实现中都有所不同,但结果应该仍然非常相似,即使对于大内核也是如此。
另外,由于需要复制整个源矩阵以在其周围添加边框,因此此方法的性能可能会成为“完整”卷积情况的一个问题。最后,如果您在filter2D()调用中收到异常,并且您仅使用一列内核,则可能是由于此错误导致的。在这种情况下,将borderMode变量设置为改为BORDER_REPLICATE,或者使用OpenCV中继库的最新版本库。
+1到目前为止最好的答案。代码片段很好,执行一些与MATLAB的'conv2'类似的东西。此外,提醒OpenCV的'filter2D'执行相关性而不是卷积是一件好事。 – 2014-01-27 22:55:24
优秀的答案! – Itay 2014-12-13 15:55:06
不应该翻转()至少需要两个参数?根据doc C++:void flip(InputArray src,OutputArray dst,int flipCode)。因此它应该是cv :: flip(kernel,kernel,0) – iqbalnaved 2018-02-20 16:03:02
minor edit:正确的调用是'conv2(A,B,'same')' – Amro 2012-04-26 10:00:52