轮廓计算画图(一)轮廓提取

38 阅读3分钟

思路概述

  • 使用pycv2提取轮廓
  • 使用turtle换图
  • 制作命令行工具
  • 使用tk制作图形化参数调节

轮廓提取部分

**重要的函数***Canny,findContours

Canny 边缘检测

基本概念

Canny 是一种多级边缘检测算法,由 John F. Canny 于 1986 年提出。它的目标是:

  • 最大化检测真正的边缘

  • 最小化误检(抑制噪声)

  • 精确地定位边缘位置

工作原理(4 个阶段)

# 典型调用
edges = cv2.Canny(image, threshold1, threshold2)
  1. 高斯滤波去噪:使用高斯滤波器平滑图像,去除噪声

  2. 计算梯度:用 Sobel 算子计算每个像素的梯度强度和方向

  3. 非极大值抑制(NMS):沿梯度方向保留局部最大值点,细化边缘

  4. 双阈值筛选与边缘连接

    • 强边缘:梯度 > threshold2(保留)

    • 弱边缘:threshold1 < 梯度 < threshold2(若与强边缘相连则保留)

输出二值图像(边缘为白色255,背景为黑色0)


findContours 轮廓提取

基本概念

findContours 是 OpenCV 中用于从二值图像中提取物体轮廓的函数。轮廓是连接连续白色像素的边界曲线。

# 典型调用
contours, hierarchy = cv2.findContours(binary_image, mode, method)

工作原理

  1. 扫描二值图像:寻找所有白色像素连通区域

  2. 提取边界:追踪每个连通区域的边界点

  3. 组织轮廓关系:建立轮廓间的层次结构(父子关系)

  4. 返回结果:轮廓点集列表和层次信息

输入要求:必须是二值图像(uint8 类型)


区别与联系

特性CannyfindContours
功能边缘检测轮廓提取
输入灰度图二值图(关键!)
输出二值边缘图轮廓点集列表
目的找出像素级边缘找出物体边界曲线
数学基础微分+优化拓扑分析

为什么先用 Canny 再用 findContours?

1. 输入要求强制

# ❌ 错误:findContours 不能直接处理灰度图
contours = cv2.findContours(gray_img, ...)

# ✅ 正确:必须先用 Canny 转为二值图
edges = cv2.Canny(gray_img, 50, 150)  # 输出二值图
contours = cv2.findContours(edges, ...)

API设计

作为画图模块的数据源

def analysis(  
        img_path: pathlib.Path,  
        json_path: pathlib.Path = None,  
        ksize: tuple[int, int] = (5, 5),  
        approx_ratio: float = 0.005,  
        thresh: int = 100,  
        min_area: int = 30  
) -> tuple[list[tuple[int, int]], int, int]:  
    """  
    解析图片生成点集路径,默认不保存为json文件  
    :param img_path: 路径  
    :param json_path: json保存路径  
    :param ksize: 高斯模糊,高斯核  
    :param approx_ratio: 轮廓转坐标点精细度,越小越精细  
    :param thresh: 轮廓识别阈值,越小轮廓越多  
    :param min_area: 剔除面积太小的轮廓  
    :return: 返回一个二维列表,包含轮廓,以及图片的长宽

作为轮廓提取的内核

def _get_contours(img: cv2.Mat | ndarray[Any, dtype[integer[Any] | floating[Any]]],  
                  ksize: tuple[int, int], thresh: int) -> \  
        tuple[Sequence[cv2.Mat | ndarray[Any, dtype[integer[Any] | floating[Any]]]], cv2.Mat | ndarray[  
            Any, dtype[integer[Any] | floating[Any]]]]:  
    """  
    提取轮廓  
    :param img: 处理的图片对象  
    :param ksize: 模糊的高斯核  
    :param thresh: 轮廓判定的阈值  
    :return: 轮廓,图片对象(不过这个对象其实是只读状态)  
    """