Python----计算机视觉处理(Opencv:绘制图像轮廓:寻找轮廓,findContours()函数)

一、轮廓

轮廓是图像中目标物体或区域的外部边界线或边界区域,由一系列相连的像素构成封闭形状,代表了物体的基本外形。与边缘不同,轮廓是连续的,而边缘则不一定是连续的。

轮廓与边缘的区别:

轮廓是一组连续的点或线,而边缘不连续。并且边缘更多的是作为图像的特征使用,比如可以用边缘特征来区分脸和手,而轮廓主要用来分析物体的形态,比如物体的周长、面积等 。

轮廓的作用:

  1. 形状分析:通过轮廓,可以分析物体的形状,比如是圆形、矩形还是更复杂的形状。

  2. 目标识别:在识别特定物体时,轮廓可以作为物体的一个重要特征。

  3. 图像分割:利用轮廓,可以将图像分割成多个区域,每个区域代表一个物体或者物体的一个部分。

二、寻找轮廓

2.1、 RETR_LIST

表示列出所有的轮廓。并且在hierarchy里的轮廓关系中,每一个轮廓只有前一条轮廓与后一条轮廓的索 引,而没有父轮廓与子轮廓的索引。

2.2、 RETR_EXTERNAL

表示只列出最外层的轮廓。并且在hierarchy里的轮廓关系中,每一个轮廓只有前一条轮廓与后一条轮廓 的索引,而没有父轮廓与子轮廓的索引。

2.3、 RETR_CCOMP

表示列出所有的轮廓。并且在hierarchy里的轮廓关系中,轮廓会按照成对的方式显示。

2.4、 RETR_TREE

表示列出所有的轮廓。并且在hierarchy里的轮廓关系中,轮廓会按照树的方式显示,其中最外层的轮廓 作为树根,其子轮廓是一个个的树枝。

除此之外还有method参数,该参数有三个选项:

CHAIN_APPROX_NONE、

CHAIN_APPROX_SIMPLE、

CHAIN_APPROX_TC89_L1。

其中,CHAIN_APPROX_NONE表示将所有的轮廓点都进行存储;CHAIN_APPROX_SIMPLE表示只存储 有用的点,比如直线只存储起点和终点,四边形只存储四个顶点,默认使用这个方法; CHAIN_APPROX_TC89_L1表示使用Teh-Chin链逼近算法进行轮廓逼近。这种方法使用的是Teh-Chin链 码,它是一种边缘检测算法,可以对轮廓进行逼近,减少轮廓中的冗余点,从而更加准确地表示轮廓的 形状。CHAIN_APPROX_TC89_L1是一种较为精确的轮廓逼近方法,适用于需要较高精度的轮廓表示的情 况。

对于mode和method这两个参数来说,一般使用RETR_EXTERNAL和CHAIN_APPROX_SIMPLE这两个选 项。

三、findContours()函数

该函数所依据的算法论文名称是:

Topological structural analysis of digitized binary images by border following.

作者是:Satoshi Suzuki

在介绍该算法的实现步骤之前,需要先介绍一些该论文中所用到的符号:

frame:框架,一张图片的最上行、最下行、最左列、最右列。

0-pixel:灰度值为0的像素。(背景)

1-pixel:灰度值为1的像素。默认图像是以0-pixel填充,目标图像为1-pixel。(目标物体)

(i, j):表示图像中第i行,第j列的像素点。

表示像素点(i, j)的灰度值。那么一张图片就可以表示为

由1像素组成的连通域称为1-component(1连通域),由0像素组成的连通域称为0-component(0连通域)。如果0连通域S包含了frame,那么称S为background(背景),否则称为孔洞。

borderpoint(边界点):如果一个1像素周围的8连通区域内有0像素存在,那么这个1像素就是一个边界点。边界是由许多的边界点共同组成的。

环绕连通域:在一个二值图中有两个连通域S1和S2,如果S1中任何一个像素点从任何一个方向(4方向)到达frame的路径上都存在S2的像素点,那么就称为S2环绕S1,如果S1环绕S1且S2和S1之间存在边界点,就称为S2直接环绕S1。

外边界和孔边界:假设现有1连通域S1,0连通域S2,如果S2直接环绕S1,则S2和S1之间的边界称为外边界;如果S1直接环绕S2,则S2和S1之间的边缘称为孔边界。

父边界:假设现有1连通域S1和S3,0连通域S2,S2直接环绕S1,S3直接环绕S2,S1与S2之间的边界为B1,S2与S3之间的边界为B2,则B2为B1的父边界。如果S2是background,那么B1的父边界是frame。

光栅扫描(RasterScan):是指从左往右,由上往下,先扫描完一行,再移至下一行起始位置继续扫描。

NBD:从边界开始点以边界跟踪算法可以得到一条边界,为每条新找到的边界B赋予一个新的唯一的编号,NBD表示当前跟踪的边界的编号。

LNBD:在光栅扫描的过程中,我们也保存最近遇到(上一个)的边界B'的编号,记为LNBD。

经过上面的定义后,对于一个二值化图像来说,可以表示为:

四 、绘制图像轮廓

导入模块

python 复制代码
import cv2

输入图像

python 复制代码
img = cv2.imread('img.png')

灰度化

python 复制代码
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

二值化

python 复制代码
ret, img_threshold = cv2.threshold(img_gray, 127, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY)

寻找轮廓

python 复制代码
contours, hierarch = cv2.findContours(img_threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

绘制轮廓

python 复制代码
img_contours = cv2.drawContours(img, contours, -1, (0, 0, 255), thickness=2)

输出图像

python 复制代码
cv2.imshow('img', img)
cv2.waitKey(0)

完整代码

python 复制代码
import cv2  

img = cv2.imread('img.png')  

# 将图像从 BGR(蓝绿红)色彩空间转换为灰度。  
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  

# 使用 Otsu 的二值化方法对灰度图像进行二值化处理。  
# ret 返回使用的阈值。  
# img_threshold 是二值化后的图像。  
ret, img_threshold = cv2.threshold(img_gray, 127, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY)  

# 在二值化图像中寻找轮廓。  
# contours 是一个轮廓列表。  
# hierarch 是轮廓的层级结构。  
contours, hierarch = cv2.findContours(img_threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)  

# 在原始图像上绘制轮廓。  
# img 是要绘制轮廓的图像。  
# contours 是要绘制的轮廓列表。  
# -1 表示绘制所有轮廓。  
# (0, 0, 255) 是轮廓的颜色(红色)。  
# thickness=2 是轮廓的粗细。  
img_contours = cv2.drawContours(img, contours, -1, (0, 0, 255), thickness=2)  

# 显示带有轮廓的图像。  
cv2.imshow('img', img)  

# 等待用户按下按键。  
cv2.waitKey(0)  

五、库函数

5.1、findContours()

python 复制代码
cv.findContours(	image, mode, method[, contours[, hierarchy[, offset]]]	) ->	contours, hierarchy
方法 描述
image 源,一个 8 位单通道图像。非零像素被视为 1。零像素仍为 0,因此图像被视为 binary 。您可以使用 compareinRangethresholdadaptiveThresholdCanny 等创建灰度或彩色图像的二进制图像。如果 mode 等于 RETR_CCOMPRETR_FLOODFILL,则输入也可以是标签的 32 位整数图像 (CV_32SC1)。
contours 检测到的轮廓。每个轮廓都存储为点向量(例如 std::vector<std::vector<cv::P oint> >)。
hierarchy 可选的输出向量(例如 std::vector<cv::Vec4i>),包含有关图像拓扑的信息。它的单元数与等值线的数量一样多。对于每个第 i 个轮廓轮廓[i],元素 hierarchy[i][0] 、hierarchy[i][1] 、hierarchy[i][2] 和 hierarchy[i][3] 在同一层次结构级别的下一个和上一个轮廓的轮廓中分别设置为从 0 开始的索引,即第一个子轮廓和父轮廓。如果轮廓 i 没有 next、previous 、parent 或 nested 等值线,则 hierarchy[i] 的相应元素将为负数。
mode 等值线检索模式,参见 RetrievalModes
method 等值线近似方法,请参阅 ContourApproximationModes
offset 每个等值线点移动的可选偏移量。如果轮廓是从图像 ROI 中提取的,然后应该在整个图像上下文中对其进行分析,这将非常有用。

|-----------------------------------------|----------------------------------------------------------------------------|
| RETR_EXTERNAL Python:cv.RETR_EXTERNAL | 仅检索极端外轮廓。它为所有轮廓设置。hierarchy[i][2]=hierarchy[i][3]=-1 |
| RETR_LIST Python:cv.RETR_LIST | 检索所有等值线,而不建立任何分层关系。 |
| RETR_CCOMP Python:cv.RETR_CCOMP | 检索所有等值线并将它们组织到一个两级层次结构中。在顶层,有组件的外部边界。在第二层,有孔的边界。如果已连接零部件的孔内有其他轮廓,则仍将其置于顶层。 |
| RETR_TREE Python:cv.RETR_TREE | 检索所有等值线并重新构建嵌套等值线的完整层次结构。 |
| RETR_FLOODFILL Python:cv.RETR_FLOODFILL |

|---------------------------------------------------------|------------------------------------------------------------------------------------------------------------------|
| CHAIN_APPROX_NONE Python:cv.CHAIN_APPROX_NONE | 绝对存储所有等高线点。也就是说,等值线的任意 2 个后续点 (x1,y1) 和 (x2,y2) 将是水平、垂直或对角线相邻点,即 max(abs(x1-x2),abs(y2-y1))==1。 |
| CHAIN_APPROX_SIMPLE Python:cv.CHAIN_APPROX_SIMPLE | 压缩水平、垂直和对角线段,仅保留其端点。例如,一个直立的矩形轮廓用 4 个点编码。 |
| CHAIN_APPROX_TC89_L1 Python:cv.CHAIN_APPROX_TC89_L1 | 应用了 Teh-Chin 链近似算法的一种风格 [266] |
| CHAIN_APPROX_TC89_KCOS Python:cv.CHAIN_APPROX_TC89_KCOS | 应用了 Teh-Chin 链近似算法的一种风格 [266] |

5.2、drawContours()

python 复制代码
cv.drawContours(	image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]]	) ->	image
方法 描述
image 目标图像。
contours 所有输入等值线。每个等值线都存储为点向量。
contourIdx 指示要绘制的轮廓的参数。如果为负数,则绘制所有等值线。
color 等值线的颜色。
thickness 绘制等高线时使用的线条粗细。如果为负数(例如, thickness=FILLED ),则绘制等值线内部
lineType 线路连接。请参阅线型
hierarchy 有关层次结构的可选信息。仅当您只想绘制部分等值线时才需要它(请参阅 maxLevel )。
maxLevel 绘制轮廓的最大级别。如果为 0,则仅绘制指定的轮廓。如果为 1,则函数绘制 contour 和所有嵌套 contour。如果为 2,则函数绘制等值线、所有嵌套等值线、所有嵌套到嵌套的等值线,依此类推。仅当有可用的层次结构时,才会考虑此参数。
offset 可选的轮廓偏移参数。将所有绘制的轮廓移动指定

注意

当 thickness=FILLED 时,该函数旨在正确处理具有孔的连通零部件,即使未提供层次结构数据也是如此。这是通过使用奇偶规则一起分析所有轮廓来完成的。如果您有单独检索的轮廓的联合集合,这可能会产生不正确的结果。为了解决这个问题,你需要为每个 contour 的子组单独调用 drawContours,或者使用 contourIdx 参数迭代集合。

相关推荐
taoqick2 小时前
PyTorch DDP流程和SyncBN、ShuffleBN
人工智能·pytorch·python
Shockang2 小时前
机器学习的一百个概念(1)单位归一化
人工智能·机器学习
Eiceblue2 小时前
Python 在Word中查找并替换文本
vscode·python·word·pip
网络风云3 小时前
Flask(六)数据库与模型操作
数据库·python·flask
啊阿狸不会拉杆3 小时前
第十五章:Python的Pandas库详解及常见用法
开发语言·python·数据分析·pandas
金融小师妹4 小时前
DeepSeek分析:汽车关税政策对黄金市场的影响评估
大数据·人工智能·汽车
p186848058104 小时前
ICFEEIE 2025 WS4:计算机视觉和自然语言处理中的深度学习模型和算法
深度学习·计算机视觉·自然语言处理
仙尊方媛4 小时前
计算机视觉准备八股中
人工智能·深度学习·计算机视觉·视觉检测
MUTA️4 小时前
《Fusion-Mamba for Cross-modality Object Detection》论文精读笔记
人工智能·深度学习·目标检测·计算机视觉·多模态融合
qp5 小时前
18.OpenCV图像卷积及其模糊滤波应用详解
人工智能·opencv·计算机视觉