OpenCV与Matlab均值滤波输出存在差异的原因探究
为什么OpenCV和Matlab的2x2均值滤波结果不一样?
咱们先从你给出的测试代码和输出入手,一步步拆解差异的原因:
测试代码与输出对比
OpenCV实现及结果
Mat P(Size(5,5),CV_64FC1,Scalar(0)); for(int i = 0; i < 5; i++) { for (int j = 0; j < 5 ; j++) P.at<double>(i,j) = i; } cout<<"Original Matrix is :"<<endl; cout<<P<<endl; Mat averageFilter(2,2,CV_64FC1,Scalar(0)),U; averageFilter = cv::Scalar::all(1.0/(2*2)); filter2D(P, U, -1 , averageFilter, Point( -1, -1 ), 0, BORDER_REPLICATE ); cout<<"Filtered Matrix is :"<<endl; cout<<U<<endl;
输出:
Original Matrix is : [0, 0, 0, 0, 0; 1, 1, 1, 1, 1; 2, 2, 2, 2, 2; 3, 3, 3, 3, 3; 4, 4, 4, 4, 4] Filtered Matrix is : [0, 0, 0, 0, 0; 0.5, 0.5, 0.5, 0.5, 0.5; 1.5, 1.5, 1.5, 1.5, 1.5; 2.5, 2.5, 2.5, 2.5, 2.5; 3.5, 3.5, 3.5, 3.5, 3.5]
Matlab实现及结果
ma = [0 0 0 0 0;1 1 1 1 1;2 2 2 2 2;3 3 3 3 3;4 4 4 4 4]; MEANF = fspecial('average',[2 2]); U = imfilter(ma, MEANF, 'replicate');
输出:
U = 0.5000 0.5000 0.5000 0.5000 0.5000 1.5000 1.5000 1.5000 1.5000 1.5000 2.5000 2.5000 2.5000 2.5000 2.5000 3.5000 3.5000 3.5000 3.5000 3.5000 4.0000 4.0000 4.0000 4.0000 4.0000
核心差异原因:卷积核的锚点位置不同
这俩工具输出不一样的根本原因,是默认的卷积核锚点(也就是核与输出像素对齐的基准点)位置不同,直接导致了滑动窗口的计算范围不一样:
1. OpenCV的默认锚点逻辑
当你给filter2D传Point(-1,-1)时,OpenCV会把锚点设为核的几何中心。但对于2x2这种偶数尺寸的核,几何中心是(0.5, 0.5)(0索引),而锚点必须是整数坐标,所以OpenCV会向下取整到(0,0)——也就是核的左上角像素位置。
这就意味着:
- 计算输出第一行时,滑动窗口的核会对齐到原始图像的第一行,由于边界模式是
BORDER_REPLICATE,核需要的下方像素会直接复制第一行的内容,所以计算的是(0+0+0+0)/4 = 0,输出第一行保持0; - 计算输出最后一行时,核需要的上方像素会复制第四行的内容,所以是
(3+3+4+4)/4 = 3.5,对应输出的最后一行。
2. Matlab的默认锚点逻辑
Matlab的imfilter对偶数尺寸的核,默认锚点是核的右下角(0索引下是(1,1))。也就是说,锚点会对齐到输出像素的位置,对应的输入窗口会覆盖当前输出位置的上方和左侧区域。
这就导致:
- 计算输出第一行时,滑动窗口会取原始图像的第一行和第二行的内容(边界模式
replicate不需要额外复制,因为第二行存在),计算(0+0+1+1)/4 = 0.5,输出第一行是0.5; - 计算输出最后一行时,滑动窗口需要的下方像素会复制第五行的内容,所以是
(4+4+4+4)/4 = 4.0,对应输出的最后一行。
如何让两者输出一致?
如果你想让OpenCV的结果和Matlab对齐,只需要手动把filter2D的锚点设为Point(1,1)(对应2x2核的右下角)就行,修改后的调用代码如下:
filter2D(P, U, -1 , averageFilter, Point(1, 1), 0, BORDER_REPLICATE );
此时OpenCV的输出就会和Matlab完全一样了。
内容的提问来源于stack exchange,提问作者Harjatin
相关产品推荐
相关产品推荐

