contribute上次修改:2026-09-29

3.5 多边形逼近与形状识别

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

← 上一节:3.4 轮廓几何特征 | 下一节:3.6 外接矩形与透视变换 →


3.5 多边形逼近与形状识别

轮廓沿着像素边界走,哪怕是一条直线也可能保存很多点。多边形逼近会把这些点压缩成“足以描述形状的几个拐角”。

一、为什么要把轮廓简化成多边形

原始轮廓:很多细碎像素点
      ↓ approxPolyDP
逼近轮廓:少量关键顶点

顶点变少后,我们可以粗略判断三角形、四边形等,也能减少后续点排序和透视变换的计算。

二、approxPolyDP 与 epsilon

perimeter = cv2.arcLength(contour, True)
epsilon = 0.02 * perimeter
approx = cv2.approxPolyDP(contour, epsilon, True)
  • curve:原轮廓;
  • epsilon:允许逼近曲线与原曲线之间的最大距离;
  • closed=True:按闭合形状处理。
epsilon 小 → 更贴近原轮廓 → 顶点更多
epsilon 大 → 简化更强       → 顶点更少

0.02 * perimeter 是常见起点,不是固定答案。边缘抖动大时先改善二值图和轮廓,不要一味增大 epsilon 把错误“压平”。

三、顶点数只能做初步判断

vertices = len(approx)

最简单的规则:

3 个点 → 可能是三角形
4 个点 → 可能是四边形
更多点 → 可能是圆、星形或复杂轮廓

“大于 4 就当圆”只适合非常干净的教学图。一个五角星、一块锯齿噪声、一个六边形都能轻松骗过它。

四、矩形、圆形和凹形怎样区分

四边形

先确认:

  • 4 个顶点;
  • cv2.isContourConvex(approx) 为真;
  • 面积足够大;
  • 角度或边长关系大致合理。

正方形与长方形可以用旋转外接矩形的长宽比初筛,比轴对齐框更不怕旋转:

rect = cv2.minAreaRect(approx)
w, h = rect[1]
ratio = max(w, h) / min(w, h) if min(w, h) > 0 else float("inf")

ratio 接近 1 时像正方形,但透视会让真实正方形变成一般四边形。

圆形

圆形优先看 圆度,不要只数顶点:

circularity = 4 * np.pi * area / (perimeter ** 2)

凹形

is_convex = cv2.isContourConvex(approx)

五角星、十字形等会出现凹陷。进一步区别见 3.7 凸包凸缺陷与Solidity。

五、一个更稳妥的分类函数

下面仍是教学级规则,但比“只看顶点数”完整:

import cv2
import numpy as np

def classify_contour(contour):
    area = cv2.contourArea(contour)
    if area < 500:
        return "noise"

    perimeter = cv2.arcLength(contour, True)
    if perimeter <= 0:
        return "degenerate"

    approx = cv2.approxPolyDP(contour, 0.02 * perimeter, True)
    vertices = len(approx)
    convex = cv2.isContourConvex(approx)
    circularity = 4 * np.pi * area / (perimeter ** 2)

    if vertices == 3 and convex:
        return "triangle"

    if vertices == 4 and convex:
        _, (w, h), _ = cv2.minAreaRect(approx)
        if min(w, h) == 0:
            return "quadrilateral"
        ratio = max(w, h) / min(w, h)
        return "square" if ratio < 1.12 else "rectangle"

    if circularity > 0.80:
        return "circle"

    if not convex:
        return "concave"

    return "polygon"

这里的 500、1.12、0.80 都是需要用自己数据验证的经验阈值。

3.5-image-0033.5-image-004

原图与输出图可以留下来当结果示意,但原笔记里大量重复的函数截图已经改成正文代码。

分类失败时先查什么

顶点乱跳 → 二值边缘抖动、epsilon 太小
矩形变圆 → epsilon 太大或轮廓本来就糊
圆被当多边形 → 圆度阈值太高、轮廓破损
星形被当圆 → 只看顶点数,没有检查凸性/solidity

← 上一节:3.4 轮廓几何特征 | 下一节:3.6 外接矩形与透视变换 →

留言区

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