OpenCV计算机视觉 06 图像轮廓检测(轮廓的查找、绘制、特征、近似及轮廓的最小外接圆外接矩形)

目录

图像轮廓检测

轮廓的查找

轮廓的绘制

轮廓的特征

面积

周长

根据面积显示特定轮廓

轮廓的近似

给定轮廓的最小外接圆、外接矩形

外接圆

外接矩形


图像轮廓检测

轮廓的查找

API函数

python 复制代码
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。

获取给定图像phone.png中物体的轮廓信息,包括轮廓的数量和层次结构,以便进行后续的图像处理。

python 复制代码
import cv2
​
# 读取原图
phone = cv2.imread('phone.png')
# 对原图进行灰度处理
phone_gray = cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)
# 对灰度图进行阈值处理,得到二值图像
ret, phone_binary = cv2.threshold(phone_gray, 120, 255, cv2.THRESH_BINARY)
# 查找二值图像中的轮廓
_,contours, hierarchy = cv2.findContours(phone_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 打印轮廓的层次结构
print(hierarchy)
# 打印轮廓的数量
print(len(contours))

输出信息解读

输出的 hierarchy 是一个包含了轮廓之间关系信息的数组。其中每个子数组 [6 -1 1 -1] 等代表了一个轮廓的相关信息:

  • 第一个数字(如 6、2、3 等)表示下一个同级轮廓的索引。

  • 第二个数字(如 -1)表示前一个同级轮廓的索引。

  • 第三个数字(如 1、-1 等)表示第一个子轮廓的索引。

  • 第四个数字(如 -1)表示父轮廓的索引。

输出的 9 表示检测到的轮廓数量。

轮廓的绘制

API函数

python 复制代码
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。

绘制出刚刚的phone.png图像中的轮廓

python 复制代码
# 读取原图
phone = cv2.imread('phone.png')
# 对原图进行灰度处理
phone_gray = cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)
# 对灰度图进行阈值处理,得到二值图像
ret, phone_binary = cv2.threshold(phone_gray, 120, 255, cv2.THRESH_BINARY)
# 查找二值图像中的轮廓
_,contours, hierarchy = cv2.findContours(phone_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 复制原始图像
image_copy = phone.copy()
# 在复制的图像上绘制轮廓
image_copy = cv2.drawContours(image=image_copy, contours=contours, contourIdx=-1, color=(0, 255, 0), thickness=3)
# 显示绘制了轮廓的图像,窗口标题为'Contours_show'
cv2.imshow('Contours_show', image_copy)
# 等待用户按键,参数 0 表示无限等待
cv2.waitKey(0)  
轮廓的特征
面积

API函数

python 复制代码
cv2.contourArea(contour[, oriented])

参数含义

contour:顶点构成的二维向量组(如轮廓列表contours中的一个轮廓)

oriented:定向区域标志,默认值为 False,返回面积的绝对值,

Ture 时则根据轮廓方向返回带符号的数值

周长

API函数

python 复制代码
arcLength(InputArray curve, bool closed)

参数含义

curve:输入的二维点集(轮廓顶点),可以是 vector 或 Mat 类型。

closed:用于指示曲线是否封闭。

问题:1. 求上述例子中 contours 列表中第一个和第二个轮廓的面积,并打印出这两个面积的值。

  1. 计算 contours 列表中第一个封闭的轮廓的周长并打印
python 复制代码
import cv2
# 读取原图
phone = cv2.imread('phone.png')
# 对原图进行灰度处理
phone_gray = cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)
# 对灰度图进行阈值处理,得到二值图像
ret, phone_binary = cv2.threshold(phone_gray, 120, 255, cv2.THRESH_BINARY)
# 查找二值图像中的轮廓
_,contours, hierarchy = cv2.findContours(phone_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 计算 contours 列表中第一个轮廓的面积,并将结果存储在 area_0 变量中
area_0 = cv2.contourArea(contours[0])  
# 计算 contours 列表中第二个轮廓的面积,并将结果存储在 area_1 变量中
area_1 = cv2.contourArea(contours[1])  
# 打印第一个和第二个轮廓的面积
print(area_0,area_1) 
# 计算 contours 列表中第一个轮廓的周长
length = cv2.arcLength(contours[0], closed=True)
# 打印第一个轮廓的周长
print(length)
根据面积显示特定轮廓

绘制出上述案例中面积大于10000的轮廓

python 复制代码
import cv2
# 读取原图
phone = cv2.imread('phone.png')
# 对原图进行灰度处理
phone_gray = cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)
# 对灰度图进行阈值处理,得到二值图像
ret, phone_binary = cv2.threshold(phone_gray, 120, 255, cv2.THRESH_BINARY)
# 查找二值图像中的轮廓
_,contours, hierarchy = cv2.findContours(phone_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 创建一个空列表用于存储面积大于 10000 的轮廓
a_list = []
# 遍历 contours 中的每个轮廓
for i in range(len(contours)):
    # 如果当前轮廓的面积大于 10000
    if cv2.contourArea(contours[i]) > 10000:
        # 将该轮廓添加到 a_list 列表中
        a_list.append(contours[i])
# 复制原始图像
image_copy = phone.copy()
# 在复制的图像上绘制面积大于 10000 的轮廓
image_copy = cv2.drawContours(image=image_copy, contours=a_list, contourIdx=-1, color=(0, 255, 0), thickness=3 )
# 显示绘制了特定轮廓的图像,窗口标题为'Contours_show_10000'
cv2.imshow('Contours_show_10000', image_copy)
# 等待用户按键
cv2.waitKey(0)
轮廓的近似

API函数

python 复制代码
approx = cv2.approxPolyDP(curve, epsilon, closed)

参数含义:

curve:输入轮廓。

epsilon:近似精度,即两个轮廓之间最大的欧式距离。该参数越小,得到的近似结果越接近实际轮廓;

反之,得到的近似结果会更加粗略。

closed:布尔类型的参数,表示是否封闭轮廓。

如果是 True,表示输入轮廓是封闭的,近似结果也会是封闭的;

否则表示输入轮廓不是封闭的,近似结果也不会是封闭的。

返回值:

approx:近似结果,是一个ndarray数组,为1个近似后的轮廓,包含了被近似出来的轮廓上的点的坐标

python 复制代码
import cv2
​
# 读取图像'phone.png'
phone = cv2.imread('phone.png')  
# 将图像转换为灰度图
phone_gray = cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY) 
# 对灰度图进行二值化处理
ret,phone_thresh = cv2.threshold(phone_gray,120,255,cv2.THRESH_BINARY) 
# 获取二值化图像的轮廓
_,contours, hierarchy = cv2.findContours(phone_thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)  
# 设置近似精度
epsilon = 0.01 * cv2.arcLength(contours[0],True)  
# 对第一个轮廓进行近似
approx = cv2.approxPolyDP(contours[0], epsilon, True)  
# 复制原始图像
phone_new = phone.copy()  
# 在复制的图像上绘制近似后的轮廓
image_contours = cv2.drawContours(phone_new,[approx],contourIdx=-1,color=(0,255,0),thickness=3) 
# 显示原始图像
cv2.imshow('phone',phone)  
cv2.waitKey(0)  
# 显示绘制了近似轮廓的图像
cv2.imshow('image_contours',image_contours)  
cv2.waitKey(0)  
给定轮廓的最小外接圆、外接矩形
外接圆

计算API函数

python 复制代码
(x,y),r = cv2.minEnclosingCircle(cnt) 

输入参数含义:

cnt 指定的轮廓

返回值:

(x,y) 是外接圆的圆心坐标

r 是外接圆的半径。

外接矩形

计算API函数

python 复制代码
x,y,w,h = cv2.boundingRect(cnt) 

输入参数含义:

cnt 指定的轮廓

返回值:

(x,y) 外接矩形的左上角坐标

w 矩形的宽度

h 矩形的高度

绘制出上述案例中第七个轮廓的最小外接圆与外接矩形

python 复制代码
import cv2
​
# 读取原图
phone = cv2.imread('phone.png')
# 对原图进行灰度处理
phone_gray = cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)
# 对灰度图进行阈值处理,得到二值图像
ret, phone_binary = cv2.threshold(phone_gray, 120, 255, cv2.THRESH_BINARY)
# 查找二值图像中的轮廓
_,contours, hierarchy = cv2.findContours(phone_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 获取第 7 个轮廓
cnt = contours[6]  
# 计算轮廓的外接圆
(x,y),r = cv2.minEnclosingCircle(cnt)  
# 绘制外接圆
phone_circle = cv2.circle(phone.copy(),(int(x),int(y)),int(r),(0,255,0),2)  
# 显示绘制了外接圆的图像
cv2.imshow('phone_circle',phone_circle)
cv2.waitKey(0)
​
# 计算轮廓的最小外接矩形
x,y,w,h = cv2.boundingRect(cnt)  
# 绘制矩形
phone_rectangle = cv2.rectangle(phone.copy(),(x,y),(x+w,y+h),(0,255,0),2)  
# 显示绘制了矩形的图像
cv2.imshow('phone_rectangle',phone_rectangle)
cv2.waitKey(0)
相关推荐
董董灿是个攻城狮18 分钟前
009:传统计算机视觉之边缘检测
人工智能·计算机视觉·cnn
视频砖家19 分钟前
Midjourney 应用:框架总结
人工智能·midjourney
Quz22 分钟前
OpenCV在现代社会中的应用
人工智能·opencv·计算机视觉
2401_8975796526 分钟前
AI赋能房地产:利用AI前端技术提升VR/AR浏览体验
前端·人工智能·vr
nuise_27 分钟前
李宏毅机器学习课程笔记02 | 机器学习任务攻略General Guide
人工智能·笔记·机器学习
代码小鬼才28 分钟前
关于量子神经网络的思考
人工智能·深度学习·神经网络
南方财富1 小时前
影视投资人项亮月考察临汾腾讯视频精品微短剧基地
大数据·人工智能
Schwertlilien1 小时前
模式识别-Ch2-分类错误率
人工智能·分类·数据挖掘
Kai HVZ2 小时前
《机器学习》——逻辑回归基本介绍
人工智能·机器学习
我爱一根柴哈2 小时前
人工智能机器学习从入门到高级学习资料(含资料下载地址)
人工智能·深度学习·机器学习