opencv-轮廓检测
2026/8/8 16:36:25 网站建设 项目流程

轮廓检测(Contour Detection)是计算机视觉(特别是 OpenCV)中非常基础且核心的技术。简单来说,轮廓就是把图像中具有相同颜色或灰度值的连续边界点连成的一条曲线

为了更容易理解,我们可以分三个层面来看:它是什么、怎么用、以及常见的坑


1. 轮廓到底是什么?(通俗理解)

  • 不是边缘:“边缘”通常指的是图像中颜色突变的地方(比如黑白交界线),它是一堆散乱的点。而“轮廓”是将这些点按顺序连接起来形成的完整封闭曲线。

  • 数学定义:在 OpenCV 中,轮廓本质是一个Numpy 数组,里面存储了一组(x, y)坐标点,对应着图像中某个物体的边界。

2. 轮廓检测的“标准三部曲”

在 OpenCV 中进行轮廓检测,通常不是直接把原图扔进去,而是经过以下三步:

  1. 灰度化cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    • 原因:计算机找轮廓时,颜色信息(BGR三个通道)是干扰项,变成单通道的灰度图处理起来更快、更准确。

  2. 二值化(阈值处理)cv2.threshold()cv2.Canny()

    • 原因:轮廓检测必须基于黑底白图(或白底黑图)。二值化就是把背景完全变成黑色(0),目标物体变成白色(255),让物体和背景彻底分离。(你在上一个问题里的phone_binary就在做这个事)。

  3. 寻找轮廓cv2.findContours()

    • 这是核心函数。它会遍历二值化图像,把所有连在一起的白色区域的外围边界提取出来,放入一个列表中返回。

    • 这里的列表里,可能有无数个轮廓,比如花朵的轮廓,也包含你上一次遇到的那个“整张图片的最外层大框”。

3. 拿到轮廓后,我们常做什么?

得到轮廓点之后,我们可以计算很多几何特征,这是轮廓检测最大的价值:

  • 面积cv2.contourArea(轮廓)—— 判断物体大小。

  • 周长cv2.arcLength(轮廓, True)—— 测量物体边缘长度。

  • 外接矩形/圆cv2.boundingRect()cv2.minEnclosingCircle()—— 框出物体。

  • 形状匹配:通过计算轮廓的“矩(Moments)”,可以判断轮廓是圆的、方的还是三角形的。

查找轮廓的 API:

image, contours, hierarchy = cv2.findContours(img, mode, method)
参数:
img:需要实现轮廓检测的原图
mode:轮廓的检索模式,主要有四种方式:
-cv2.RETR_EXTERNAL:只检测外轮廓,所有子轮廓被忽略
-cv2.RETR_LIST:检测的轮廓不建立等级关系,所有轮廓属于同一等级
-cv2.RETR_CCOMP:返回所有的轮廓,只建立两个等级的轮廓。一个对象的外轮廓为第 1 级组织结构,而对象内部中空洞的轮廓为第 2 级组织结构,空洞中的任何对象的轮廓又是第 1 级组织结构。
-cv2.RETR_TREE:返回所有的轮廓,建立一个完整的组织结构的轮廓。
method:轮廓的近似方法,主要有以下两种:
-cv2.CHAIN_APPROX_NONE:存储所有的轮廓点。
-cv2.CHAIN_APPROX_SIMPLE:压缩模式,只保留该方向的终点坐标,例如一个矩形轮廓只需 4 个点来保存轮廓信息。
返回:
image:返回处理的原图
contours:包含图像中所有轮廓的 List 对象。其中每一个独立的轮廓信息以边界点坐标 (x, y) 的形式储存在 numpy 数组中。
hierarchy:轮廓的层次结构。一个包含 4 个值的数组:[Next, Previous, First_Child, Parent]
-Next:与当前轮廓处于同一层级的下一条轮廓
-Previous:与当前轮廓处于同一层级的上一条轮廓
-First_Child:当前轮廓的第一条子轮廓
-Parent:当前轮廓的父轮廓
注意:做轮廓检测前需要将图片读取为二值数据,即像素值只为 0 和 255。

具体代码示例:

1. 读取原图并把原图转换为灰度图,为什么要用灰度图:

因为“灰度图是寻找轮廓的最优解和最简化模型”

如果你直接用彩色图(BGR)去跑cv2.findContours(),程序不仅会报错,而且即便有办法处理,也会极其低效。

1. 数学维度:3个通道 vs 1个通道

  • 彩色图(BGR):每个像素点由3个数值(蓝、绿、红)组成。如果你要对彩色图找轮廓,计算机需要同时对比这3个数值的变化情况。这在数学上叫做“三维向量空间”,非常复杂。

  • 灰度图:每个像素点只有1个数值(0-255的亮度)。计算机只需要比较一维数据的大小。

  • 结论用灰度图,计算量瞬间减少了 2/3,处理速度极快,这对于视频流来说尤为重要。

import cv2 1. 读取图像并转换为灰度图 phone = cv2.imread('shouji.png') phone_gray = cv2.cvtColor(phone, cv2.COLOR_BGR2GRAY) 2. 二值化处理 ret, phone_binary = cv2.threshold(phone_gray, 120, 255, cv2.THRESH_BINARY) 3. 查找轮廓 contours = cv2.findContours(phone_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[-2] 4. 绘制轮廓 image_copy = phone.copy() cv2.drawContours(image=image_copy, contours=contours, contourIdx=-1, color=(0, 255, 0), thickness=2) 5. 显示结果 cv2.imshow('phone', phone_gray) cv2.imshow('phone_binary', phone_binary) cv2.imshow('Contours', image_copy) cv2.waitKey(0)

代码说明:

  1. 灰度化:将彩色图像转换为灰度图,减少计算维度。
  2. 二值化:使用阈值120将灰度图转换为黑白二值图像,背景变黑(0),目标变白(255)。
  3. 查找轮廓cv2.findContours()函数必须在二值图上运行,它会提取所有白色区域的边界。
  4. 绘制轮廓:在原图副本上绘制绿色轮廓线。
  5. 显示结果:分别显示灰度图、二值图和轮廓检测结果。

API参数详解:

cv2.drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None)

  • image:要在其上绘制轮廓的输入图像。
  • contours:轮廓列表,通常由cv2.findContours()函数返回。
  • contourIdx:要绘制的轮廓的索引。如果为-1,则绘制所有轮廓。
  • color:轮廓的颜色,以BGR格式表示。例如,(0, 255, 0)表示绿色。
  • thickness:轮廓线的粗细。默认值为1。
  • lineType:轮廓线的类型。默认值为cv2.LINE_8
  • hierarchy:轮廓层次结构。通常由cv2.findContours()函数返回。
  • maxLevel:绘制的最大轮廓层级。默认值为None,表示绘制所有层级。
  • offset:轮廓点的偏移量。默认值为None。

代码输出为:

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询