matlab函数conv2有没有直接的opencv函数?我尝试使用cvFilter2D(),但似乎给我的结果与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
请帮助我。对我非常有用。谢谢。
此致
Arangarajan。
答案 0 :(得分:8)
数值计算环境Matlab(或者例如它的自由替代GNU Octave)提供了一个称为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 :(得分:5)
如果使用卷积,矩阵边缘会出现问题。卷积掩模需要在矩阵之外的值。 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
要获得预期结果,您只需删除第一列和第一行即可删除我们添加的边框引入的其他数据。