Matlab和OpenCV对同一幅图像计算不同的图像矩m00

Matlab and OpenCV calculate different image moment m00 for the same image

对于完全相同的图像

Opencv代码:

img = imread("testImg.png",0);
threshold(img, img_bw, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
Mat tmp;
img_bwR.copyTo(tmp);
findContours(tmp, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);

// Get the moment
vector<Moments> mu(contours.size() );
for( int i = 0; i < contours.size(); i++ )
 { mu[i] = moments( contours[i], false ); 

 }

// Display area (m00)
for( int i = 0; i < contours.size(); i++ )
 { 
     cout<<mu[i].m00 <<endl;
     // I also tried the code 
     //cout<<contourArea(contours.at(i))<<endl;  
     // But the result is the same
 }

Matlab代码:

Img = imread('testImg.png');
lvl = graythresh(Img);
bw = im2bw(Img,lvl);
stats = regionprops(bw,'Area');
for k = 1:length(stats)
    Area = stats(k).Area; %m00
end

有人想过吗?如何统一它们?我认为他们使用不同的方法来寻找轮廓。

我在下面的link上传了测试图片,以便对此感兴趣的人可以重现该过程

这是一个 100 x 100 的小 8 位灰度图像,只有 0 和 255 像素强度。为简单起见,它上面只有一个斑点。 对于 OpenCV,轮廓面积(图像矩 m00)为 609.5(非常奇怪的值) 对于Matlab,contour的面积(image moment m00)为763.

谢谢

对于如何从二值图像中提取轮廓存在许多不同的定义。例如,它可以是二值图像中白色对象周长的多边形。如果 OpenCV 使用此定义,则等高线的面积将与 Matlab 找到的连通分量的面积相同。但这种情况并非如此。 findContour() 函数找到的轮廓是连接邻居 "edge pixels" 中心的多边形。边缘像素是在 N4 邻域中有黑色邻居的白色像素。

示例:假设您有一张尺寸为 100x100 像素的图像。对角线上方的每个像素都是黑色的。对角线下方或对角线上的每个像素都是白色的(黑色三角形和白色三角形)。精确分离多边形在 1 个像素的距离处将有近 200 个顶点:(0,0), (1,0), (1,1), (2,1), (2,2),.... (100 ,99), (100,100), (0,100).如您所见,从实用的角度来看,这个定义并不是很好。 OpenCV 返回的多边形正好有定义三角形所需的 3 个顶点:(0,0)、(99,99)、(0,99)。它的面积是 (99 x 99 / 2) 像素。它不等于白色像素的数量。它甚至不是一个整数。但是这个多边形比上一个更实用。

这些并不是多边形提取的唯一可能定义。存在许多其他定义。其中一些(在我看来)可能比 OpenCV 使用的更好。但这是被很多人实施和使用的。

目前没有针对您的问题的有效解决方法。如果你想从 MATLAB 和 OpenCV 中得到完全相同的数字,你将不得不在一些黑色图像上绘制由 foundContours 找到的轮廓,并在图像上使用函数 moments() 。我知道即将推出的 OpenCV 3 具有查找连通分量的功能,但我自己没有尝试过。