资讯动态

OpenCV Python 轮廓(Contours)实战:从 findContours 到轮廓层级、特征与形状匹配的完整教程

发布时间:2026/9/7 1:18:55 来源:尧图企业网站定制
OpenCV Python 轮廓Contours实战从 findContours 到轮廓层级、特征与形状匹配的完整教程【免费下载链接】opencvOpen Source Computer Vision Library项目地址: https://gitcode.com/GitHub_Trending/opencv31/opencv本文围绕 OpenCV Python 图像轮廓Contours教程系列的目录与全部内容展开你将学会如何用cv.findContours()从二值图中提取轮廓、用cv.drawContours()绘制轮廓进而掌握轮廓特征矩、面积、周长、凸包、外接矩形、椭圆与直线拟合、轮廓属性Solidity、Equivalent Diameter、平均灰度、极值点等、常用高级函数凸缺陷、pointPolygonTest、matchShapes以及轮廓层级RETR_LIST/EXTERNAL/CCOMP/TREE的完整原理与代码实操。学完后你可以独立完成形状分析、物体检测与识别所需的轮廓处理全流程。该教程系列在仓库中的目录骨架由 py_table_of_contents_contours.markdown 定义它把整章拆分为五个子页本文按同一脉络完整覆盖子页主题对应文档入门什么是轮廓、如何查找与绘制轮廓、近似方法py_contours_begin.markdown轮廓特征矩、面积、周长、多边形近似、凸包、凸性、外接矩形、最小外接圆、椭圆/直线拟合py_contour_features.markdown轮廓属性长宽比、Extent、Solidity、等效直径、方向、掩膜像素点、极值点py_contour_properties.markdown更多函数凸缺陷、点到多边形距离、形状匹配py_contours_more_functions.markdown轮廓层级父子关系、[Next, Previous, First_Child, Parent]表示法、四种检索模式py_contours_hierarchy.markdown一、轮廓入门什么是轮廓如何查找与绘制1.1 概念与使用前提轮廓Contour可以简单理解为连接所有具有相同颜色或灰度值的连续边界点所形成的曲线。它是形状分析和物体检测、识别中非常实用的工具。教程原文强调了三点使用前提为提高精度应使用二值图像。因此在查找轮廓之前应先做阈值处理threshold或 Canny 边缘检测自 OpenCV 3.2 起findContours()不再修改源图像——这意味着可以放心地复用同一张二值图在 OpenCV 中查找轮廓相当于在黑色背景中查找白色物体。务必记住要找的物体应为白色高灰度背景应为黑色。从源码结构看findContours在 imgproc 模块中存在多套实现contours_truco.cpp 是早期基于 Suzuki 方法的内核contours_new.cpp 与 contours_link.cpp 则是后续引入的新实现Suzuki 1993 轮廓提取算法的另一种工程实现由构建时选择启用对应的单元测试位于 test_contours.cpp 与 test_contours_new.cpp性能基准在 perf_contours.cpp。这也印证了文档所说查找轮廓是一个被反复验证和优化的核心能力。1.2 查找轮廓cv.findContours()从二值图中查找轮廓的完整示例继承自入门教程原文import numpy as np import cv2 as cv im cv.imread(test.jpg) assert im is not None, file could not be read, check with os.path.exists() imgray cv.cvtColor(im, cv.COLOR_BGR2GRAY) ret, thresh cv.threshold(imgray, 127, 255, 0) contours, hierarchy cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)cv.findContours()有三个参数、两个输出参数 1源图像二值图参数 2轮廓检索模式contour retrieval mode如cv.RETR_TREE参数 3轮廓近似方法contour approximation method如cv.CHAIN_APPROX_SIMPLE输出 1contours——一个 Python 列表包含图像中的所有轮廓。每个轮廓是一个 NumPy 数组存放物体边界点的 (x, y) 坐标输出 2hierarchy——层级信息数组其含义将在第五节详细拆解。教程提示在没弄懂第 2、3 个参数和 hierarchy 之前代码示例中给定的值RETR_TREECHAIN_APPROX_SIMPLE对绝大多数图像都适用。1.3 绘制轮廓cv.drawContours()cv.drawContours()不仅能画轮廓只要你有边界点也可以画任意形状。参数依次为源图像、轮廓列表Python list、轮廓索引画全部传-1、颜色、线宽等。# 绘制图中所有轮廓 cv.drawContours(img, contours, -1, (0,255,0), 3) # 绘制某一个个体轮廓比如第 4 个索引 3 cv.drawContours(img, contours, 3, (0,255,0), 3) # 更常用的写法先取出单个轮廓再包成列表、索引传 0 cnt contours[4] cv.drawContours(img, [cnt], 0, (0,255,0), 3)最后两种写法等价但教程特别指出后一种[cnt] 索引0在后续操作中更常用。1.4 轮廓近似方法第三参数第三个参数决定了轮廓存储哪些边界点。轮廓本质是形状边界的 (x,y) 坐标集合但并不总是需要全部点——例如一条直线只需两个端点即可完整表示。两种取值cv.CHAIN_APPROX_NONE存储全部边界点cv.CHAIN_APPROX_SIMPLE删除所有冗余点压缩轮廓以节省内存。以教程中的矩形为例用CHAIN_APPROX_NONE得到734 个点而CHAIN_APPROX_SIMPLE仅存4 个点矩形四角省内存效果显著。这也是为什么示例代码默认推荐CHAIN_APPROX_SIMPLE。二、轮廓特征矩、面积、周长、凸包与几何拟合这一节继承自 Contour Features共十个特征点是轮廓分析的主力工具箱。2.1 矩Moments图像矩可用于计算质心、面积等特征。cv.moments()返回一个包含所有矩值的字典import numpy as np import cv2 as cv img cv.imread(star.jpg, cv.IMREAD_GRAYSCALE) assert img is not None, file could not be read, check with os.path.exists() ret, thresh cv.threshold(img, 127, 255, 0) contours, hierarchy cv.findContours(thresh, 1, 2) cnt contours[0] M cv.moments(cnt) print(M)由矩可提取有用数据。质心centroid由关系式 $C_x \frac{M_{10}}{M_{00}}$、$C_y \frac{M_{01}}{M_{00}}$ 给出cx int(M[m10]/M[m00]) cy int(M[m01]/M[m00])2.2 轮廓面积与周长面积由cv.contourArea()给出也可直接取矩中的M[m00]area cv.contourArea(cnt)周长又称弧长由cv.arcLength()计算第二参数指定轮廓是否闭合True为闭合轮廓否则按曲线处理perimeter cv.arcLength(cnt, True)2.3 多边形近似Douglas-Peuckercv.approxPolyDP()按指定精度把轮廓近似为顶点更少的形状是Douglas-PeuckerRamer-Douglas-Peucker算法的实现。应用场景图像中的方形因噪声等原因变成了坏形状可用该函数将其近似还原为规整多边形。第二参数epsilon表示轮廓点到近似轮廓的最大允许距离是精度参数——需要恰当选择才能拿到正确结果epsilon 0.1 * cv.arcLength(cnt, True) approx cv.approxPolyDP(cnt, epsilon, True)教程给出的对比结果是epsilon取弧长的10%时近似较粗取1%时近似更贴合原轮廓第三参数指定曲线是否闭合。2.4 凸包Convex Hull凸包外观上类似轮廓近似但两者并不相同某些情况下可能结果一致。cv.convexHull()检查曲线的凸性缺陷并加以修正凸曲线始终向外凸出或至少是平的向内凹陷处称为凸性缺陷convexity defects即凸包相对轮廓的局部最大偏差。语法与参数说明hull cv.convexHull(points[, hull[, clockwise[, returnPoints]]])points传入的轮廓hull输出参数通常省略clockwise方向标志。True时输出顺时针方向的凸包否则为逆时针returnPoints默认True返回凸包点的坐标为False时返回凸包点对应轮廓点的索引。hull cv.convexHull(cnt)教程用矩形图验证了两种返回值returnPointsTrue得到四个角点坐标[[[234 202]], [[ 51 202]], [[ 51 79]], [[234 79]]]returnPointsFalse则得到对应索引[[129],[67],[0],[142]]且cnt[129] [[234, 202]]与坐标结果一致。要计算凸性缺陷必须传returnPointsFalse见第四节。2.5 判断凸性cv.isContourConvex()判断一条曲线是否凸直接返回True/Falsek cv.isContourConvex(cnt)2.6 外接矩形直矩形与旋转矩形OpenCV 提供两种外接矩形a. 直立外接矩形Straight Bounding Rectangle不考虑物体旋转面积不是最小由cv.boundingRect()计算。设 (x, y) 为左上角、(w, h) 为宽高x, y, w, h cv.boundingRect(cnt) cv.rectangle(img, (x, y), (xw, yh), (0, 255, 0), 2)b. 旋转外接矩形Rotated Rectangle以最小面积绘制因此考虑了旋转由cv.minAreaRect()计算。它返回一个 Box2D 结构含(center(x,y), (width, height), 旋转角度)要绘制它需要先由cv.boxPoints()取到四个角点rect cv.minAreaRect(cnt) box cv.boxPoints(rect) box np.int0(box) cv.drawContours(img, [box], 0, (0, 0, 255), 2)教程图中绿色为直立矩形、红色为旋转矩形可直观看到旋转矩形面积更小、更贴合倾斜物体。2.7 最小外接圆cv.minEnclosingCircle()求完全覆盖物体且面积最小的圆外接圆(x, y), radius cv.minEnclosingCircle(cnt) center (int(x), int(y)) radius int(radius) cv.circle(img, center, radius, (0, 255, 0), 2)2.8 椭圆拟合与直线拟合椭圆拟合返回椭圆内切所在的旋转矩形ellipse cv.fitEllipse(cnt) cv.ellipse(img, ellipse, (0, 255, 0), 2)直线拟合可用于一组点如图中一堆白色点集rows, cols img.shape[:2] [vx, vy, x, y] cv.fitLine(cnt, cv.DIST_L2, 0, 0.01, 0.01) lefty int((-x * vy / vx) y) righty int(((cols - x) * vy / vx) y) cv.line(img, (cols-1, righty), (0, lefty), (0, 255, 0), 2)cv.fitLine使用cv.DIST_L2距离度量后两参0.01, 0.01分别为距离与重离群值的精度阈值返回值是方向向量 (vx, vy) 与线上一点 (x, y)代码通过斜率把直线两端延伸到图像左右边界后画出。三、轮廓属性Solidity、等效直径、极值点等本节继承自 Contour Properties介绍九个常用物体属性质心、面积、周长等已在上一节见过。3.1 长宽比Aspect Ratio物体外接矩形的宽与高之比x, y, w, h cv.boundingRect(cnt) aspect_ratio float(w) / h3.2 Extent轮廓面积与外接矩形面积之比area cv.contourArea(cnt) x, y, w, h cv.boundingRect(cnt) rect_area w * h extent float(area) / rect_area3.3 Solidity轮廓面积与其凸包面积之比area cv.contourArea(cnt) hull cv.convexHull(cnt) hull_area cv.contourArea(hull) solidity float(area) / hull_areaSolidity 越接近 1形状越实心无凹陷明显小于 1 的形状往往带有凹口如月牙、C 形件。3.4 等效直径Equivalent Diameter与轮廓面积相等的圆的直径area cv.contourArea(cnt) equi_diameter np.sqrt(4 * area / np.pi)3.5 方向Orientation物体的指向角度同一方法还给出长轴Major Axis与短轴Minor Axis长度(x, y), (MA, ma), angle cv.fitEllipse(cnt)3.6 掩膜与像素点需要物体内部全部像素点时可先构造掩膜再取非零点mask np.zeros(imgray.shape, np.uint8) cv.drawContours(mask, [cnt], 0, 255, -1) pixelpoints np.transpose(np.nonzero(mask)) # 等价写法pixelpoints cv.findNonZero(mask)教程特别强调两种写法的坐标顺序差异NumPy 的nonzero返回(row, column)格式OpenCV 的findNonZero返回(x, y)格式且row y、column x即两组坐标互换。3.7 极值与极值位置用掩膜即可限定在物体范围内求灰度极值及其位置min_val, max_val, min_loc, max_loc cv.minMaxLoc(imgray, maskmask)3.8 平均颜色 / 平均灰度同样借助掩膜计算物体平均颜色彩色图或平均灰度灰度图mean_val cv.mean(im, maskmask)3.9 极值点Extreme Points物体最上、最下、最左、最右点leftmost tuple(cnt[cnt[:, :, 0].argmin()][0]) rightmost tuple(cnt[cnt[:, :, 0].argmax()][0]) topmost tuple(cnt[cnt[:, :, 1].argmin()][0]) bottommost tuple(cnt[cnt[:, :, 1].argmax()][0])原理是轮廓数组cnt的第二维第 0 列存 x、第 1 列存 yargmin/argmax分别给出最小/最大坐标的索引。教程给出的示例是把该方法用于一幅印度地图轮廓标出四个极值点效果类似于求图像的四向最远边界。四、更多函数凸缺陷、点到多边形距离、形状匹配本节继承自 More Functions。4.1 凸缺陷Convexity Defects物体相对凸包的任何偏離都可视为凸缺陷。cv.convexityDefects()是现成工具注意必须传returnPointsFalse的凸包hull cv.convexHull(cnt, returnPointsFalse) defects cv.convexityDefects(cnt, hull)返回值是一个数组每行包含[起点索引, 终点索引, 最远点索引, 到最远点的近似距离]。完整可视化示例对星形图import cv2 as cv import numpy as np img cv.imread(star.jpg) assert img is not None, file could not be read, check with os.path.exists() img_gray cv.cvtColor(img, cv.COLOR_BGR2GRAY) ret, thresh cv.threshold(img_gray, 127, 255, 0) contours, hierarchy cv.findContours(thresh, 2, 1) cnt contours[0] hull cv.convexHull(cnt, returnPointsFalse) defects cv.convexityDefects(cnt, hull) for i in range(defects.shape[0]): s, e, f, d defects[i, 0] start tuple(cnt[s][0]) end tuple(cnt[e][0]) far tuple(cnt[f][0]) cv.line(img, start, end, [0, 255, 0], 2) cv.circle(img, far, 5, [0, 0, 255], -1) cv.imshow(img, img) cv.waitKey(0) cv.destroyAllWindows()前三项是cnt的索引需要回查cnt取真实坐标可视化效果是绿色直线连接每个缺陷的起止点红色圆点标记最远点。星形的每个内凹夹角都会如此标出。4.2 点到多边形距离Point Polygon Testcv.pointPolygonTest()求图像中一点到轮廓的最短距离点在轮廓外返回负值内返回正值在轮廓上返回 0dist cv.pointPolygonTest(cnt, (50, 50), True)第三参数measureDistTrue时计算带符号距离False时只判断内/外/在边界上分别返回 1、-1、0。教程提示若不需要距离务必传False因为求距离是耗时操作传False可获得约2~3 倍加速。4.3 形状匹配Match Shapescv.matchShapes()比较两个轮廓的形状相似度并返回一个度量值——值越小匹配越好基于 Hu 矩计算import cv2 as cv import numpy as np img1 cv.imread(star.jpg, cv.IMREAD_GRAYSCALE) img2 cv.imread(star2.jpg, cv.IMREAD_GRAYSCALE) assert img1 is not None, file could not be read, check with os.path.exists() assert img2 is not None, file could not be read, check with os.path.exists() ret, thresh cv.threshold(img1, 127, 255, 0) ret, thresh2 cv.threshold(img2, 127, 255, 0) contours, hierarchy cv.findContours(thresh, 2, 1) cnt1 contours[0] contours, hierarchy cv.findContours(thresh2, 2, 1) cnt2 contours[0] ret cv.matchShapes(cnt1, cnt2, 1, 0.0) print(ret)教程给出的三组实测结果图 A 与自身匹配 0.0图 A 与图 B 匹配 0.001946图 A 与图 C 匹配 0.326911即使图像发生旋转对比较结果影响也不大。补充知识Hu 矩是七个对平移、旋转和缩放不变化的矩其中第七个还对倾斜不变可用cv.HuMoments()获取。五、轮廓层级父子关系与四种检索模式本节继承自 Contours Hierarchy回答两个此前被搁置的问题findContours()的第二参数Contour Retrieval Mode到底意味着什么以及第二个输出hierarchy是什么、怎么用。5.1 什么是层级嵌套图形中外层轮廓称为parent父内层轮廓称为child子轮廓之间因此存在关系。以教程中的编号示例图形状 0~52 与 2a 表示最外层框的外轮廓与内轮廓为例轮廓 0、1、2 是外部最外层轮廓处于hierarchy-0同一层级轮廓 2a 是轮廓 2 的子轮廓处于hierarchy-1轮廓 3 同为轮廓 2 的子轮廓轮廓 4、5 是轮廓 3a 的子轮廓位于最末层级。这一章的目标就是理解same hierarchy level同层、external contour外轮廓、child/parent contour、first child第一个子这些术语。5.2 OpenCV 中的层级表示[Next, Previous, First_Child, Parent]每条轮廓的层级信息是一个四元组数组分量含义Next同一层级中的下一个轮廓索引没有则为 -1Previous同一层级中的上一个轮廓索引没有则为 -1First_Child第一个子轮廓的索引没有则为 -1Parent父轮廓的索引没有则为 -1以示例图推演轮廓 0 的同层下一个是轮廓 1故Next1轮廓 2 没有同层后继Next-1轮廓 2 的First_Child是轮廓 2a轮廓 4、5 的Parent都是轮廓 3a。若没有子或父对应字段取-1。5.3 四种检索模式Contour Retrieval Mode1. RETR_LIST最简单的模式。取出所有轮廓但不建立任何父子关系——父与子在它看来地位平等全部视为同一层级。因此 hierarchy 数组的第 3、4 项恒为 -1Next/Previous 有对应值 hierarchy array([[[ 1, -1, -1, -1], [ 2, 0, -1, -1], [ 3, 1, -1, -1], [ 4, 2, -1, -1], [ 5, 3, -1, -1], [ 6, 4, -1, -1], [ 7, 5, -1, -1], [-1, 6, -1, -1]]])不使用任何层级特性时这是推荐的选择。2. RETR_EXTERNAL只返回最外层的轮廓所有子轮廓被丢弃教程原文比喻为每个家族只关照最年长的一位。示例图中 hierarchy-0 层只有 3 条轮廓0、1、2 hierarchy array([[[ 1, -1, -1, -1], [ 2, 0, -1, -1], [-1, 1, -1, -1]]])需要只提取外部轮廓时使用。3. RETR_CCOMP取出所有轮廓并排成两级层级物体的外部轮廓边界放在 hierarchy-1物体内部的孔洞放在 hierarchy-2若孔洞中又有物体其轮廓仍放 hierarchy-1其孔洞放 hierarchy-2依此类推。典型例子黑色背景上的大白 0外圈属于第一层内圈属于第二层。以教程的 CCOMP 示例图逐条推演轮廓编号为 OpenCV 检测顺序轮廓 0hierarchy-1有两个孔洞 1、2[3, -1, 1, -1]轮廓 1hierarchy-2父为 0[2, -1, -1, 0]轮廓 2hierarchy-2前一个同层为 1[-1, 1, -1, 0]轮廓 3[5, 0, 4, -1]轮廓 4hierarchy-2父为 3[-1, -1, -1, 3]完整结果 hierarchy array([[[ 3, -1, 1, -1], [ 2, -1, -1, 0], [-1, 1, -1, 0], [ 5, 0, 4, -1], [-1, -1, -1, 3], [ 7, 3, 6, -1], [-1, -1, -1, 5], [ 8, 5, -1, -1], [-1, 7, -1, -1]]])4. RETR_TREE最完整的模式——取出所有轮廓并构建完整的家族树能表达爷爷、父亲、儿子、孙辈乃至更深层级关系。对同一张图使用cv.RETR_TREE后按 OpenCV 给出的轮廓顺序重新编号分析轮廓 0hierarchy-0同层下一个是 7无前驱子为 1无父 →[7, -1, 1, -1]轮廓 2hierarchy-1无同层轮廓无前驱子为 3父为 1 →[-1, -1, 3, 1]完整结果 hierarchy array([[[ 7, -1, 1, -1], [-1, -1, 2, 0], [-1, -1, 3, 1], [-1, -1, 4, 2], [-1, -1, 5, 3], [ 6, -1, -1, 4], [-1, 5, -1, 4], [ 8, 0, -1, -1], [-1, 7, -1, -1]]])从这张层级表可以读出一整条嵌套链 0→1→2→3→4→5每个的 Parent 指向前者以及 4 的两个子 5、6Next/Previous互指这正是 RETR_TREE 完美模式的价值一条遍历hierarchy[:, 0]的链表 子节点指针即可重建任意复杂度的轮廓包含关系供后续递归处理如按层级渲染、逐层填充使用。5.4 模式选择建议只用轮廓本身、不管嵌套关系 →RETR_LIST只要最外圈如整体裁剪、最外物体检测→RETR_EXTERNAL只需区分物体边界与孔洞两级结构 →RETR_CCOMP需要完整的包含/嵌套树文字识别中的字框与洞、多层嵌套零件等→RETR_TREE。六、从文档到源码这条调用链在哪里落地把本文所有函数放回仓库看它们都是 imgproc 模块的公共 API声明在 imgproc.hpp 中底层 C 实现集中在 modules/imgproc/src 目录下轮廓提取内核有 contours_truco.cpp旧 Suzuki 实现与 contours_new.cpp、contours_link.cpp新实现两套测试覆盖在 test_contours.cpp、test_contours_new.cpp 与 test_contours_truco.cpp。文档示例中cv.findContours(thresh, 2, 1)这类整数写法2 ≈RETR_TREE、1 ≈CHAIN_APPROX_SIMPLE与本文使用的cv.RETR_TREE/cv.CHAIN_APPROX_SIMPLE常量完全等价阅读仓库内外旧代码时可放心对照。Python 绑定侧findContours的返回签名contours, hierarchy二元组自 OpenCV 3.2 起由绑定字典维护可参考 modules/imgproc/misc/python 目录下的生成配置教程文档本身的图片资源则位于各子页的images/目录例如 py_contour_features/images、py_contours_hierarchy/images可配合原文逐图对照实验结果。七、小结本教程系列从什么是轮廓出发给出了完整的实操闭环二值化 →findContours选对检索模式与近似方法→drawContours可视化 → 提取矩/面积/周长/凸包/外接几何等特征 → 计算 Solidity、等效直径、极值点等属性 → 用凸缺陷、pointPolygonTest、matchShapes做进一步分析 → 借助 hierarchy 四元组理解嵌套结构。五个子文档见开头目录表加上 imgproc 总目录 中的阈值、Canny、形态学等前置章节共同构成 Python 轮廓分析的完整知识链可直接作为形状分析与物体检测项目开发的参考手册。【免费下载链接】opencvOpen Source Computer Vision Library项目地址: https://gitcode.com/GitHub_Trending/opencv31/opencv创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价