在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。

+0

minor edit:正确的调用是'conv2(A,B,'same')' – Amro 2012-04-26 10:00:52

如果使用卷积,矩阵的边缘会出现问题。卷积掩膜需要矩阵外的值。来自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 

为了让您预期的结果,你只需要删除第一列和行摆脱我们添加的边框引入的额外数据。

+0

谢谢。非常多... – aranga 2012-04-26 06:05:16

+4

+1请记住函数'cvFilter2D'执行相关性,而'conv2'执行卷积。对于上面的例子来说,这并不重要,但如果内核不对称,则需要将它旋转180度才能匹配结果。 – Amro 2012-04-26 10:00:29

数值计算环境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中继库的最新版本库。

+0

+1到目前为止最好的答案。代码片段很好,执行一些与MATLAB的'conv2'类似的东西。此外,提醒OpenCV的'filter2D'执行相关性而不是卷积是一件好事。 – 2014-01-27 22:55:24

+0

优秀的答案! – Itay 2014-12-13 15:55:06

+0

不应该翻转()至少需要两个参数?根据doc C++:void flip(InputArray src,OutputArray dst,int flipCode)。因此它应该是cv :: flip(kernel,kernel,0) – iqbalnaved 2018-02-20 16:03:02