python - cv2.findContours + cv2.contourArea 意外结果
问题描述
概括
cv.findContours
+此图像的cv2.contourArea
回报总和。0.0
重现步骤
# Create sample image
import numpy as np
a = np.array([
[0, 0],
[0, 255]
])
img = np.vstack([np.hstack([a]*100)]*100)
# Show image
from PIL import Image
Image.fromarray(img).show()
import cv2
cv2.__version__
>>> 4.3.0
cnts, hierachy = cv2.findContours(img.astype(np.uint8),
mode=cv2.RETR_LIST,
method=cv2.CHAIN_APPROX_NONE)
len(cnts)
>>> 10000
sum(cv2.contourArea(cnt) for cnt in cnts)
>>> 0.0
实时调频
cnts[-1]
>>> array([[[1,1]]], dtype=int32)
轮廓是根据文档使用边界遵循算法[1] 计算的,这导致轮廓描述轮廓的内部多边形。意想不到的部分是,计算面积需要轮廓的外部或封闭多边形。
上面的极端情况是有 10000 个非常小的对象,每个对象的面积为 1px。1px 的内部多边形的面积为 0。所有轮廓面积的总和仍为 0,而预期为 10000。
github issue上有一个讨论,这实际上是所需的行为,1px 的对象应该有区域 0。对于缺陷分析,这是不可接受的。
在一般情况下如何找到一致的面积计算?
废弃的解决方案
像素值求和:对整个图像中的渲染像素值求和将给出非常准确的总面积,但不是单个组件的面积。将轮廓渲染成单独的图像并在那里求和具有低性能。
在 findContours 之前扩张轮廓:扩张会弄乱细粒度的轮廓边界。此外,必须分别绘制和扩展每个轮廓,以免将多个轮廓聚集成一个。这再次提供了低性能。
改用 connectedCompontens:connectedComponentsWithStats 只会返回组件的像素数,这是一个很好的面积近似值,但不如计算多边形面积准确。例如,尝试用很多非常小的三角形/圆形进行试验。
使用 skimage.measure.find_contours:此函数将返回轮廓的行进正方形近似值。对于从 1px 对象构造的多边形,这种近似方法将产生 2px 的面积。
到目前为止,我们已经进行了数十年的图像处理,我确信必须存在一个干净、高性能的解决方案来返回一致的正确多边形 + 面积计算。我期待着您的建议。
[1] 铃木聪等。边界跟随数字化二值图像的拓扑结构分析 计算机视觉、图形和图像处理,30(1):32–46, 1985。
解决方案
推荐阅读
- pytorch - pytorch 模型与其可执行版本有什么区别?
- android - 更新后 Google Ads SDK 不推荐使用 InterstitialAd,如何解决?
- javascript - HTML 加载 jQuery 函数
- c++ - 运行 cpp 程序时未定义对“WinMain@16”的引用
- html - 如何根据值改变背景颜色
- asp.net-core - 如何访问类库.Net Core 5中的会话
- makefile - 库在命令“make”处未正确链接
- flutter - 一个flutter中有两个材质应用程序可以吗?
- mongoose - MongooseError: Callback must be a function, got [object Object]
- sql - 如何在 SQL 中使用 count('condition') over(partition by xx)