supervision 多边形工具详解:filter_polygons_by_area 与 approximate_polygon 的原理、用法与源码解析
supervision 多边形工具详解filter_polygons_by_area 与 approximate_polygon 的原理、用法与源码解析【免费下载链接】supervisionWe write your reusable computer vision tools. 项目地址: https://gitcode.com/GitHub_Trending/su/supervision在计算机视觉检测流程中多边形标注polygon annotation常用于实例分割数据集导出、掩码矢量化和标注精简等场景。supervision 在supervision.detection.utils.polygons模块中提供了两个多边形核心工具函数按面积过滤多边形列表的filter_polygons_by_area以及基于 Ramer-Douglas-PeuckerRDP算法按点数预算简化多边形顶点的approximate_polygon。读完本文你将掌握这两个函数的完整参数语义、典型调用示例、边界行为以及它们背后基于 OpenCV 与纯 NumPy 双后端的实现机制并了解它们如何被内置到 supervision 数据集导出流程如 COCO 格式转换中。多边形在 supervision 中的数据表示两个函数对多边形的约定完全一致每个多边形是一个形状为(N, 2)的 NumPy 数组每行存储一个顶点的x, y坐标输入可以是单个这样的数组approximate_polygon也可以是多个多边形的列表filter_polygons_by_area。这一约定与sv.Detections中mask矢量化后的多边形数据一致因此可直接处理分割模型输出的轮廓结果。两个函数通过顶层命名空间直接导出位于 src/supervision/init.py 的__all__列表中因此既可以用sv.filter_polygons_by_area(...)/sv.approximate_polygon(...)调用也可以从supervision.detection.utils.polygons子模块导入。函数实现集中在 src/supervision/detection/utils/polygons.py对应的 API 参考页为 docs/detection/utils/polygons.md。filter_polygons_by_area按面积阈值过滤多边形列表函数签名与参数filter_polygons_by_area( polygons: list[npt.NDArray[np.number]], min_area: float | None None, max_area: float | None None, ) - list[npt.NDArray[np.number]]参数说明如下参数说明polygons多边形列表每个多边形为形状(N, 2)的 NumPy 数组包含顶点的x, y坐标min_area最小面积阈值。仅保留面积 min_area的多边形为None时不启用下界约束max_area最大面积阈值。仅保留面积 max_area的多边形为None时不启用上界约束函数返回一个新列表其中只包含面积落在[min_area, max_area]区间内的多边形边界值采用闭区间比较。注意两个阈值均为可选只传min_area只过滤过小目标只传max_area只过滤过大目标两者都不传时直接原样返回输入。典型示例官方 docstring 中给出的示例可直接运行import numpy as np import supervision as sv small np.array([[0, 0], [2, 0], [2, 2], [0, 2]]) # 面积为 4 big np.array([[0, 0], [10, 0], [10, 10], [0, 10]]) # 面积为 100 sv.filter_polygons_by_area([small, big], min_area50) # [array([[ 0, 0], [10, 0], [10, 10], [ 0, 10]])]只有大正方形被保留实现细节面积如何计算从源码看函数对每个多边形调用cv2.contourArea(polygon)计算面积其中cv2是 supervision 的私有 OpenCV 兼容层supervision._cv2见 src/supervision/detection/utils/polygons.pyif min_area is None and max_area is None: return polygons ares [cv2.contourArea(polygon) for polygon in polygons] return [ polygon for polygon, area in zip(polygons, ares) if (min_area is None or area min_area) and (max_area is None or area max_area) ]contourArea的面积本质是鞋带公式shoelace formula计算出的绝对面积。在没有安装 OpenCV 的纯 NumPy 回退后端中对应实现_contour_area直接使用向量化的鞋带公式见 src/supervision/_cv2/_geometry.pyarea 0.5 * float(np.dot(x, np.roll(y, -1)) - np.dot(y, np.roll(x, -1))) return abs(area)顶点数不足 3 时返回0.0因此退化多边形会天然地被最小面积约束过滤掉。测试覆盖的边界情形tests/detection/utils/test_polygons.py 用参数化用例覆盖了单/双多边形、仅min_area、仅max_area、双阈值以及阈值恰等于多边形面积的临界场景例如两个正方形面积分别为 100 和 400传入min_area200, max_area200时结果为空严格区间外而min_area100, max_area100时恰好保留面积为 100 的多边形——验证了闭区间的比较语义。approximate_polygon按点数预算简化多边形函数签名与参数approximate_polygon( polygon: npt.NDArray[np.number], percentage: float, epsilon_step: float 0.05, ) - npt.NDArray[np.number]参数说明polygon形状(N, 2)的 2D NumPy 数组输入多边形的顶点坐标percentage需要删除的顶点比例取值范围[0, 1)超出范围抛出ValueErrorepsilon_stepRDP 逼近精度的递增步长必须为正数默认0.05每轮以该步长增大 epsilon 直到满足点数预算函数目标是把多边形从N个顶点简化到至多floor(N * (1 - percentage))个顶点最少 3 个同时尽量保持原有轮廓形状。官方 docstring 的示例如下import numpy as np from supervision.detection.utils.polygons import approximate_polygon polygon np.array([[0, 0], [10, 0], [10, 10], [0, 10], [5, 10], [5, 5], [3, 7], [1, 9]]) result approximate_polygon(polygon, percentage0.5) len(result) max(int(len(polygon) * 0.5), 3) # True # 顶点数已不超过目标预算时原样返回同一对象 tiny np.array([[0, 0], [5, 0], [2, 4]]) approximate_polygon(tiny, percentage0.5) is tiny # True核心机制epsilon 递增 RDP 逼近从源码看src/supervision/detection/utils/polygons.py实现分四步参数校验percentage不在[0, 1)或epsilon_step 0时抛出ValueError计算点数预算target_points max(int(len(polygon) * (1 - percentage)), 3)若当前顶点数已不超过预算直接返回原多边形对象循环增大 epsilonepsilon从 0 开始每轮加上epsilon_step调用cv2.approxPolyDP(polygon, epsilon, closedTrue)做一次 RDP 逼近并对结果执行np.squeeze(..., axis1)把 OpenCV 的(M, 1, 2)形状压回(M, 2)防坍缩保护如果某次逼近的结果顶点数少于 3多边形已退化立即跳出循环并返回上一个仍保持至少 3 个顶点的近似结果。target_points max(int(len(polygon) * (1 - percentage)), 3) if len(polygon) target_points: return polygon epsilon: float 0 approximated_points polygon while len(approximated_points) target_points: epsilon epsilon_step candidate np.squeeze(cv2.approxPolyDP(polygon, epsilon, closedTrue), axis1) if len(candidate) 3: break approximated_points candidate return approximated_points这一设计带来两个值得注意的边界行为docstring 与测试均明确说明epsilon 是按离散步长前进的因此结果点数可能明显小于预算一步就跨过目标带但不会超出预算3 顶点下限优先于预算当继续简化会把多边形压到 3 个顶点以下时函数返回最后一个仍然有效的近似此时结果点数可能超过预算。测试用例 tests/detection/utils/test_polygons.py 正是据此断言的只有当target_points 3时才要求len(result) target_points。另外percentage0时预算不小于原点数函数原样保留全部顶点对应测试test_zero_percentage_keeps_polygon参数越界行为由test_raises_on_out_of_range_percentage与test_raises_on_non_positive_epsilon_step两个用例锁定错误信息分别为 Percentage must be in the range [0, 1). 与 epsilon_step must be positive.。底层依赖supervision._cv2 的 OpenCV / NumPy 双后端两个函数都不直接import cv2而是通过from supervision import _cv2 as cv2获取能力见 src/supervision/_cv2/init.py。该模块的行为是若环境中安装了opencv-python直接转发到cv2.contourArea、cv2.approxPolyDP等原生实现BACKEND_NAME为opencv若 OpenCV 不可用则切换到纯 NumPy 回退实现contourArea _contour_area、approxPolyDP _approx_poly_dpBACKEND_NAME为fallback并发出警告提示部分操作可能更慢或行为略有差异。回退版 RDP 实现在 src/supervision/_cv2/_geometry.py 中用显式栈模拟 OpenCVapproxPolyDP的分段简化流程再叠加一次清理近共线点的后处理_cleanup_approximation并保持closedTrue的闭环多边形契约与(M, 1, 2)输出形状使上层调用方无需感知后端差异。这意味着本文的两个多边形函数在未安装 OpenCV 的极简环境里同样可运行。实战场景数据集导出中的掩码多边形化流程这两个函数并非孤立工具而是 supervision 数据集处理管线的组成部分。src/supervision/dataset/utils.py 中的approximate_mask_with_polygons将它们串成一条布尔掩码 → 多边形流水线def approximate_mask_with_polygons( mask, min_image_area_percentage: float 0.0, max_image_area_percentage: float 1.0, approximation_percentage: float 0.0, ): height, width mask.shape image_area height * width minimum_detection_area min_image_area_percentage * image_area maximum_detection_area max_image_area_percentage * image_area polygons mask_to_polygons(maskmask) if len(polygons) 1: polygons filter_polygons_by_area( polygonspolygons, min_areaNone, max_areamaximum_detection_area ) else: polygons filter_polygons_by_area( polygonspolygons, min_areaminimum_detection_area, max_areamaximum_detection_area, ) return [ approximate_polygon(polygonpolygon, percentageapproximation_percentage) for polygon in polygons ]可以推断出其设计意图mask_to_polygons先用轮廓提取把掩码转成一组(N, 2)多边形filter_polygons_by_area负责剔除碎片噪点面积过小或超大面积的异常轮廓approximate_polygon则按需压缩顶点数以减小标注体积。细节上单多边形时只启用上界过滤避免唯一的轮廓因小于min_image_area_percentage而被误删多边形时才同时启用上下界。该函数被 COCO 格式转换器直接复用src/supervision/dataset/formats/coco.py 中的convert_annotations_to_coco默认approximation_percentage0.75即最多保留 25% 的顶点而 src/supervision/dataset/core.py 的DetectionDataset序列化接口同样暴露了min_image_area_percentage、max_image_area_percentage、approximation_percentage三个参数并在校验中说明当is_obbTrue导出旋转框时这三个参数不生效。因此当你用 supervision 将分割检测结果导出为 COCO 标注时本质上就是在调用本文讲解的这两个多边形函数。快速上手与验证方式安装 supervision 后即可在本地验证OpenCV 可选缺失时自动回退到 NumPy 后端pip install supervisionimport numpy as np import supervision as sv # 面积过滤保留面积在 [50, 500] 内的多边形 sq [np.array([[0, 0], [a, 0], [a, a], [0, a]], dtypenp.float32) for a in (2, 10, 40)] kept sv.filter_polygons_by_area(sq, min_area50, max_area500) print(len(kept)) # 2边长 2 的小正方形被过滤 # 顶点简化把 100 顶点多边形压缩到最多约 20 个顶点 import math pts np.array( [[50 40 * math.cos(t), 50 40 * math.sin(t)] for t in [2 * math.pi * i / 100 for i in range(100)]], dtypenp.float32) simplified sv.approximate_polygon(pts, percentage0.8) print(pts.shape[0], -, simplified.shape[0])完整的行为边界点数预算、3 顶点下限、异常抛出可参考 tests/detection/utils/test_polygons.py 与 tests/dataset/test_utils.py 中的测试用例它们以参数化形式覆盖了 20/50/100/200 顶点 × 10%/50%/75%/90% 删除比例的矩阵。小结supervision 的多边形工具模块围绕两个函数构建了一条清晰的能力链filter_polygons_by_area以contourArea的绝对面积为判据用可选的min_area/max_area闭区间过滤多边形列表适合剔除碎片化噪点轮廓approximate_polygon以 RDP 算法approxPolyDP为内核通过epsilon_step逐轮增大精度参数逼近点数预算floor(N * (1 - percentage))并内置至少 3 个顶点的防坍缩保护二者均通过supervision._cv2兼容层实现 OpenCV / 纯 NumPy 双后端在 src/supervision/detection/utils/polygons.py 中仅约百行代码即可提供生产级行为在数据集导出场景如DetectionDataset的 COCO 序列化中这两个函数被approximate_mask_with_polygons组合复用构成掩码 → 过滤 → 简化 → 标注的完整矢量化流程。理解这两个函数后你可以既把它们作为独立工具用于自定义的轮廓后处理也可以透过数据集导出的参数min_image_area_percentage、max_image_area_percentage、approximation_percentage间接控制标注的粒度与体积。【免费下载链接】supervisionWe write your reusable computer vision tools. 项目地址: https://gitcode.com/GitHub_Trending/su/supervision创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考