Python+OpenCV玩转轮廓检测:从基础绘制到高级边界框显示
如果你已经能用Python写点小脚本,也对OpenCV的imread和imshow不陌生,那么恭喜你,你已经站在了图像处理世界的大门口。但很多时候,我们处理图像不只是为了“看看”,而是想让计算机“看懂”。比如,在一张杂乱的工作台上,让程序自动识别出螺丝刀、扳手的位置和角度;或者在监控画面里,精准框出每一个移动的物体。这时候,仅仅会显示图片是远远不够的,你需要掌握一项核心技能——轮廓检测。
轮廓检测,听起来有点学术,但你可以把它理解为“给图像中的物体描边”。它是从像素到“对象”理解的关键一步。无论是简单的物体计数、尺寸测量,还是复杂的姿态估计、缺陷检测,轮廓都是最基础也最强大的工具之一。网上教程很多,但往往只告诉你cv2.findContours()和cv2.drawContours()这两个函数怎么用,画个绿边就结束了。这就像只学会了汽车的油门和刹车,却不知道如何转弯和倒车。
这篇文章,我想和你分享的,远不止于“描边”。我们将从最基础的轮廓查找与绘制出发,一步步深入到如何为轮廓“穿上合身的衣服”——也就是绘制边界框。更重要的是,我会把我实际项目中踩过的坑、调试的经验,特别是处理那些“歪脖子”物体(非规则物体)时,如何用旋转矩形精准拟合的技巧,毫无保留地分享给你。我们的目标不是复现文档,而是让你能真正把这些技术用起来,解决实际问题。
1. 轮廓检测:从“看见”到“识别”的第一步
在OpenCV的世界里,轮廓(Contour)特指连接所有连续点(沿边界)的曲线,这些点具有相同的颜色或强度。它和边缘(Edge)不同,边缘是局部的、不连续的像素变化,而轮廓是一个完整的、封闭的(或开放的)边界。你可以把边缘检测(如Canny)看作“找茬”,找到所有明暗变化的地方;而轮廓检测是在此基础上,把属于同一个物体的“茬”连成线,形成一个有意义的整体。
1.1 核心函数深度解析:cv2.findContours()
几乎所有教程都会提到这个函数,但参数背后的选择逻辑才是实战的关键。它的输入必须是一个二值图像(黑白图),白色是前景(你要找的物体),黑色是背景。如果直接扔一张彩色或灰度图进去,结果会一团糟。
函数的返回值是两个:contours和hierarchy。contours是一个Python列表,列表里的每个元素都是一个轮廓,而每个轮廓本身又是一个由点坐标组成的NumPy数组(形状为(n, 1, 2),n是点的数量)。hierarchy则描述了轮廓之间的层级关系,比如哪个轮廓在哪个轮廓里面(父子关系)。
参数mode的选择,决定了你找到的轮廓是“全家福”还是“独照”:
cv2.RETR_EXTERNAL:只检测最外层的轮廓。如果你只关心最外面的物体边界,不关心物体内部的孔洞,用这个模式最快、最干净。比如检测一张白纸上的黑色文字。cv2.RETR_LIST:检测所有轮廓,但不建立任何层级关系。所有轮廓都是平等的,简单粗暴。当你不关心轮廓嵌套时(比如散落一地的硬币),用它。cv2.RETR_TREE:检测所有轮廓,并重建一个完整的嵌套层级树。这是信息最全的模式,能告诉你哪个轮廓是另一个轮廓的“爸爸”或“儿子”。在分析复杂结构,比如一个圆环套着另一个圆环,或者识别证件照中的人脸和五官轮廓时,非常有用。cv2.RETR_CCOMP:将所有轮廓组织为两级层次结构。所有轮廓要么是外层(第一级),要么是内层孔洞(第二级)。这是TREE的一个简化版,在大多数需要层级信息的场景下也够用。
参数method,决定了轮廓要“多精细”:
cv2.CHAIN_APPROX_NONE:存储轮廓上的每一个点。如果你的后续操作需要完整的边界信息(比如计算轮廓的周长、做精确的形状匹配),选这个。缺点是数据量大,轮廓点可能成千上万。cv2.CHAIN_APPROX_SIMPLE:压缩水平、垂直和对角线方向上的冗余点,只保留拐角处的端点。这是最常用的选项。例如,一个矩形的轮廓,用NONE会存储四条边上的所有像素点,而用SIMPLE只存储四个顶点的坐标。这极大地减少了内存占用和后续计算量,对于绘制边界框、计算最小外接矩形等操作完全足够。
注意:OpenCV不同版本中,
cv2.findContours()的返回值个数有变化。在OpenCV 3和4中,它返回两个值(contours, hierarchy);而在OpenCV 2中,它可能返回三个值(image, contours, hierarchy)。如果你遇到“too many values to unpack”的错误,很可能是版本问题。一个兼容性写法是:contours, _ = cv2.findContours(...)或根据版本调整。
1.2 绘制轮廓:让结果可视化
找到轮廓后,我们需要把它画出来看看。cv2.


19万+

被折叠的 条评论
为什么被折叠?



