contribute上次修改:2026-09-29

3.7 凸包、凸缺陷与 Solidity

总目录:1.1 OpenCV介绍与学习路线 | 第三章:边缘、轮廓与几何 | 编号:3.7

← 上一节:3.6 外接矩形与透视变换 | 下一节:4.1 完整的形状检测流程 →


3.7 凸包、凸缺陷与 Solidity

想象用一根橡皮筋把五角星紧紧套住。橡皮筋不会钻进星星的凹口,而是直接跨过去。绷紧后的外轮廓就是凸包,星星与橡皮筋之间的凹口就是凸缺陷。

一、凸包:用橡皮筋包住轮廓

3.7-image-001
hull_points = cv2.convexHull(contour)
cv2.drawContours(result, [hull_points], 0, (0, 255, 0), 2)

凸图形的凸包大致就是自己;凹图形的凸包会跨过凹陷。

二、凸缺陷:原轮廓凹进去的地方

3.7-image-003

每个凸缺陷由:

  • 起点索引;
  • 终点索引;
  • 最远凹点索引;
  • 最远点到凸包边的近似深度;

组成。手势识别中,手指之间的凹口就是经典例子。

三、convexHull 的两种返回形式

返回凸包点:

hull_points = cv2.convexHull(contour, returnPoints=True)

返回凸包点在原轮廓里的索引:

hull_indices = cv2.convexHull(contour, returnPoints=False)

画凸包需要点;计算凸缺陷需要索引。两个不要拿反。

四、convexityDefects 的四个值

hull_indices = cv2.convexHull(contour, returnPoints=False)

if hull_indices is not None and len(hull_indices) >= 3:
    defects = cv2.convexityDefects(contour, hull_indices)
else:
    defects = None

遍历:

if defects is not None:
    for defect in defects[:, 0, :]:
        start_i, end_i, far_i, depth_fixed = defect

        start = tuple(contour[start_i, 0])
        end = tuple(contour[end_i, 0])
        far = tuple(contour[far_i, 0])
        depth = depth_fixed / 256.0

        if depth > 10:
            cv2.line(result, start, end, (0, 255, 0), 2)
            cv2.circle(result, far, 4, (0, 0, 255), -1)

深度除以 256,是因为 OpenCV 用带 8 位小数部分的定点表示保存它。

五、Solidity:轮廓把凸包装满了多少

Solidity 常定义为:

轮廓面积 / 凸包面积
area = cv2.contourArea(contour)
hull = cv2.convexHull(contour)
hull_area = cv2.contourArea(hull)

solidity = area / hull_area if hull_area > 0 else 0.0
  • 接近 1:轮廓很凸、很饱满;
  • 较小:凹陷多或凹陷深。

矩形、圆、三角形理论上都比较接近 1;五角星通常更低。但具体数值受分辨率、边缘噪声、旋转和二值化影响,原笔记中的经验区间不能当通用标准。

六、这些特征适合怎样使用

判断是不是凹形

is_convex = cv2.isContourConvex(contour)

区分十字形与五角星

可以组合:

  • isContourConvex;
  • solidity;
  • 深凸缺陷数量;
  • 多边形逼近顶点;
  • 旋转归一化后的形状匹配。
def concavity_features(contour):
    area = cv2.contourArea(contour)
    hull_points = cv2.convexHull(contour)
    hull_area = cv2.contourArea(hull_points)

    return {
        "convex": cv2.isContourConvex(contour),
        "solidity": area / hull_area if hull_area > 0 else 0.0,
    }

调参原则

先过滤小轮廓
  ↓
再计算凸包与缺陷
  ↓
按“相对尺寸”设深度阈值,而不是只写固定 10 像素
  ↓
用自己的样本统计 solidity 分布

相对深度示例:

x, y, w, h = cv2.boundingRect(contour)
scale = max(w, h)
deep = depth / scale > 0.05 if scale > 0 else False

七、参考


← 上一节:3.6 外接矩形与透视变换 | 下一节:4.1 完整的形状检测流程 →

留言区

不收集任何个人信息;昵称只绑定浏览器里的随机 Cookie。