思路概述
- 使用pycv2提取轮廓
- 使用turtle换图
- 制作命令行工具
- 使用tk制作图形化参数调节
轮廓提取部分
**重要的函数***Canny,findContours
Canny 边缘检测
基本概念
Canny 是一种多级边缘检测算法,由 John F. Canny 于 1986 年提出。它的目标是:
-
最大化检测真正的边缘
-
最小化误检(抑制噪声)
-
精确地定位边缘位置
工作原理(4 个阶段)
# 典型调用
edges = cv2.Canny(image, threshold1, threshold2)
-
高斯滤波去噪:使用高斯滤波器平滑图像,去除噪声
-
计算梯度:用 Sobel 算子计算每个像素的梯度强度和方向
-
非极大值抑制(NMS):沿梯度方向保留局部最大值点,细化边缘
-
双阈值筛选与边缘连接:
-
强边缘:梯度 > threshold2(保留)
-
弱边缘:threshold1 < 梯度 < threshold2(若与强边缘相连则保留)
-
输出:二值图像(边缘为白色255,背景为黑色0)
findContours 轮廓提取
基本概念
findContours 是 OpenCV 中用于从二值图像中提取物体轮廓的函数。轮廓是连接连续白色像素的边界曲线。
# 典型调用
contours, hierarchy = cv2.findContours(binary_image, mode, method)
工作原理
-
扫描二值图像:寻找所有白色像素连通区域
-
提取边界:追踪每个连通区域的边界点
-
组织轮廓关系:建立轮廓间的层次结构(父子关系)
-
返回结果:轮廓点集列表和层次信息
输入要求:必须是二值图像(uint8 类型)
区别与联系
| 特性 | Canny | findContours |
|---|---|---|
| 功能 | 边缘检测 | 轮廓提取 |
| 输入 | 灰度图 | 二值图(关键!) |
| 输出 | 二值边缘图 | 轮廓点集列表 |
| 目的 | 找出像素级边缘 | 找出物体边界曲线 |
| 数学基础 | 微分+优化 | 拓扑分析 |
为什么先用 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: 轮廓,图片对象(不过这个对象其实是只读状态)
"""