skimage与OpenCV原始矩计算不一致问题咨询
skimage与OpenCV矩计算的实现差异分析
skimage的measure.moments_coords和OpenCV的cv2.moments在矩计算逻辑上存在核心差异,直接导致了两者输出的原始矩(如m00)结果不同,具体差异及原因如下:
1. 计算对象与逻辑的本质区别
- OpenCV
cv2.moments:针对轮廓包围的区域计算矩,采用格林公式(Green's Theorem)通过多边形边界积分计算区域面积和矩,因此m00等价于轮廓包围的像素区域面积,和cv2.contourArea结果一致。 - skimage
measure.moments_coords:直接对输入的坐标点集合计算离散矩,将每个坐标点视为单位点累加,因此m00的数值等于输入轮廓点的总数量,而非区域面积。
这完全匹配你测试的结果:OpenCV输出的m00是区域面积(9231.5/14341364.5),而skimage的m00是轮廓点数量(513/15149)。
2. 轮廓表示的差异
measure.find_contours返回的是轮廓的亚像素级离散点序列,即使转换为int32,本质仍是独立点的集合;而OpenCV处理轮廓时,将其视为封闭多边形,通过边界的几何关系计算区域矩,而非单纯累加点坐标。
3. 质心结果相近的原因
质心由一阶矩除以零阶矩得到:
- OpenCV的一阶矩是对区域内所有像素坐标的加权积分
- skimage的一阶矩是对轮廓点坐标的直接累加
对于规则形状(如测试用的正方形),轮廓点的分布中心与区域质心高度重合,因此最终质心结果差异极小。
解决方案:用skimage获得区域矩
若要让skimage输出与OpenCV一致的区域矩,应使用measure.moments直接处理二值图像(而非坐标点),示例代码:
# 替换原skimage矩计算代码 sk_m = measure.moments(bi) print(sk_m[0, 0], sk_m[1, 0] / sk_m[0, 0], sk_m[0, 1] / sk_m[0, 0])
此时sk_m[0,0]会等价于OpenCV的m00(区域面积),质心结果也会完全对齐。
内容的提问来源于stack exchange,提问作者Michael Liao
相关产品推荐
相关产品推荐

