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 参数迭代集合。

相关推荐
绝顶大聪明4 分钟前
【图像轮廓特征查找】图像处理(OpenCV) -part8
图像处理·人工智能·opencv
liruiqiang055 分钟前
神经网络优化 - 小批量梯度下降之批量大小的选择
人工智能·深度学习·神经网络·机器学习·梯度下降
朴拙数科5 分钟前
Stable Diffusion秋叶整合包V4独立版Python本地API连接指南
开发语言·python·stable diffusion
AI大模型顾潇5 分钟前
[特殊字符] Prompt如何驱动大模型对本地文件实现自主变更:Cline技术深度解析
前端·人工智能·llm·微调·prompt·编程·ai大模型
Blossom.11814 分钟前
量子计算与经典计算融合:开启计算新时代
人工智能·深度学习·opencv·物联网·生活·边缘计算·量子计算
AI技术学长28 分钟前
深度学习-python猫狗识别tensorflow2.0
人工智能·深度学习·计算机视觉·图像识别·计算机技术·tensorflow2·猫狗识别
6confim31 分钟前
掌握 Cursor:AI 编程助手的高效使用技巧
前端·人工智能·后端
offerwa31 分钟前
LLM多模态能力应用实战指南
人工智能
offerwa33 分钟前
知识图谱与大模型结合实践指南
人工智能
offerwa33 分钟前
大模型Agent系统设计与实现指南
人工智能