百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

OpenCV-图像轮廓处理

bigegpt 2024-08-06 11:49 8 浏览

各位同学好,今天和大家分享一下opencv中如何获取图像轮廓,以及对轮廓的一些其他操作。内容有:

(1)轮廓检测:cv2.findContours();(2)轮廓绘制:cv2.drawContours();(3)轮廓近似:cv2.approxPolyDP();(4)面积计算:cv2.contourArea();(5)周长计算:cv2.arcLength();(6)外接矩形:cv2.rectangle();(7)外接圆:cv2.circle()


正文

在开始前,先导入需要用到的库文件以及图像数据,定义一个图像显示函数,方便后续绘图。

import cv2
import numpy as np
# 获取图片所在文件夹
filepath = 'C:\\...\\opencv\\img'
# 获取文件夹中的某一张图片
img = cv2.imread(filepath+'\\test2.png')
# 定义绘图函数
def cv_show(name,img):
    # 传入自定义图像名,即图像变量
    cv2.imshow(name,img) 
    # 图片不会自动消失
    cv2.waitKey(0)
    # 手动关闭窗口
    cv2.destroyWindow()

1. 图像轮廓

1.1 获取图像轮廓

方法: contours, hierarchy = cv2.findContours(img, mode, method)

参数:

  • img:输入的图像,最好是二值图
  • mode:轮廓检索模式,如下
  • RETR_EXTERNAL:只检索最外面的轮廓
  • RETR_LIST:检索所有的轮廓,并将其保存到一条链表中
  • RETR_CCOMP:检索所有的轮廓,并将它们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界
  • RETR_TREE:常用,检索所有的轮廓,并重构嵌套轮廓的整个层次。保存了所有的轮廓,用哪个调用哪个

method:轮廓逼近方法,如下

  • CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。正常画出所有轮廓
  • CHAIN_APPROX_SIMPLE:压缩水平的、垂直的、斜的部分,即函数只保留他们的终点坐标。压缩得到更精简的结果,例如一个矩形轮廓只需4个点来保存轮廓信息

返回值:

  • contours:列表,保存轮廓信息。每一个元素都是图像的轮廓
  • hierarchy:数组,分层保存轮廓信息。元素数和轮廓数一致

1.2 绘制图像轮廓

方法: cv2.drawContours(img, contours, contourIdx, color, thickness)

参数:

  • img:指明在哪幅图像上绘制轮廓;image为三通道才能显示轮廓
  • contours:图像轮廓信息,列表形式
  • contours:指定绘制轮廓列表中的哪条轮廓。如果是-1,则绘制其中的所有轮廓。
  • color:代表绘制轮廓的线条颜色,根据BGR调整,若为(0,0,255)则为红色。
  • thickness:线条粗细

1.3 代码演示

首先将读入的图像变成灰度图cv2.cvtColor(),再使用图像阈值处理方法将灰度图转换成二值图cv2.threshold(),像素值超过阈值127的变成255,低于127的像素值变成0,实现二值化。将二值化处理后的图像thresh传入轮廓检测函数。图像阈值处理方法见下文第4节:opencv 图像处理:边界填充、图像融合、图像阈值、数值计算

#(1)图像处理
# 将读入的图像变成灰度图 
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 图像数值超过127取255,小于127的变成0
ret,thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
# ret接收阈值,thresh接收处理后的图像
#(2)轮廓检测
# 输入图像最好是二值图
contours,hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 返回值:contours轮廓信息;hierarchy层级,把结果保存在一个层级中
#(3)绘制轮廓
# 注意要将原图(彩色图)复制一份,不然原图会在函数处理完之后改变
draw = img.copy()  #draw改变不会导致img改变
# 在draw画板上绘制轮廓;画第几个轮廓,-1代表所有轮廓;BGR分别对应(0,0,255),用红色线画轮廓;线条宽2
res = cv2.drawContours(draw, contours,-1, (0, 0, 255), 2)
# 展示图像
cv_show('res',res)

第1张为原始图像,第2张为contourIdx=-1时绘制轮廓后的图像 ,第3张为contourIdx=3时绘制的轮廓。contourIdx中保存了所有的轮廓信息。


2. 轮廓特征

2.1 轮廓计算

轮廓计算有非常多种方法,这里只介绍两个,计算轮廓周长和面积。

在图像轮廓获取函数中cv2.findContours(),我们获取了轮廓信息返回值contours,在计算时,不能将轮廓全部放进去计算,计算时需要选出其中一个。下面使用轮廓信息中的第0个轮廓计算它的面积和周长。

# 获取某一个轮廓用于计算
cnt = contours[0]
# ==1== 面积
cv2.contourArea(cnt)  # 8500.5
# ==2== 周长
cv2.arcLength(cnt,True)  # 437.948

2.2 轮廓近似

方法: cv2.approxPolyDP(curve, epsilon, closed)

参数:

  • curve: 需要进行近似的轮廓
  • epsilon: 判断点到相对应的线段的距离的阈值,这是原始曲线与其近似值之间的最大距离。阈值越小,折线的形状越接近曲线。
  • closed: 若为true,曲线第一个点与最后一个点连接形成闭合曲线,若为false,曲线不闭合。

下面使用的阈值是cv2.arcLength(cnt,True),即轮廓的周长。取轮廓周长的0.1倍来作为contours[0]轮廓的近似。

# 获取图像
img = cv2.imread(filepath+'\\test1.png')  # 获取一张图像
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)  # 灰度图
ret,thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 二值化
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)  # 轮廓提取
cnt = contours[0]  # 获取其中一层轮廓
draw = img.copy()  # 绘制轮廓
res = cv2.drawContours(draw, [cnt], -1, (0,0,255), 2)  # 在draw图像中绘制cnt轮廓
cv_show('res',res)  # 绘图
# 轮廓近似
epsilon = 0.1*cv2.arcLength(cnt,True)  # 以周长的百分比作为阈值,指定的越小,得到的轮廓和原来的区别较小
approx = cv2.approxPolyDP(cnt, epsilon, True)  # 近似函数,cnt为轮廓,epsilon阈值。返回近似后的轮廓
# 绘图展示
draw = img.copy()
res = cv2.drawContours(draw, [approx], -1, (255,0,0), 2)  # 将近似后的轮廓approx画在原图上,用蓝色表示,线条粗2
cv_show('res',res)

第一张图为图像轮廓,第二张图为轮廓近似后的结果


2.3 轮廓的外接矩形

首先在轮廓提取函数的返回值contours中,选取一个轮廓信息用于求它的外接矩形。

计算轮廓的垂直边界最小矩形,矩形是与图像上下边界平行的

x, y, w, h = cv2.boundingRect(轮廓信息)

返回四个值。x,y是矩阵左上点的坐标;w,h是矩阵的宽和高。

外接矩形绘制函数

cv2.rectangle(img, pt1, pt2, color, thickness)

参数:

  • img: 原始图片作为画板
  • pt1: 长方形框左上角坐标 (x, y)
  • pt2: 长方形框右下角坐标 (x+w, y+h)
  • color: 线条颜色(B, G, R)
  • thickness: 线条粗细

在图片img上画长方形,坐标原点是图片左上角,向右为x轴正方向,向下为y轴正方向。


# 获取轮廓信息
img = cv2.imread(filepath+'\\test1.png')  # 读取图像
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)  # 灰度处理
ret,thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)  # 二值化处理
contours,hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)  # 获取轮廓信息
cnt = contours[0]  # 指定某一层轮廓
# 轮廓的外接矩形
x,y,w,h = cv2.boundingRect(cnt)  # 计算外接矩形,返回矩形的左上坐标点,和一长一宽
rectangle = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)  # 根据坐标绘制矩形,绿色线条
cv_show('rectangle',rectangle)

得到矩形的宽和高,接下来就可以计算轮廓面积和外接矩形面积的比值。

area = cv2.contourArea(cnt)  # 轮廓面积计算函数
x,y,w,h = cv2.boundingRect(cnt)  # 获取坐标点和边长
rect_area = w*h  # 计算外接矩形面积
extent = area/rect_area  # 计算比值
print('轮廓面积和外接矩形面积之比:',extent)

2.4 轮廓的外接圆

获取轮廓的圆心坐标和半径

(x,y), radius = cv2.minEnclosingCircle(轮廓信息)

轮廓外接圆函数

cv2.circle(img, center, radius, color, thickness, shift)

  • img: 输入的图片作为画板
  • center: 圆心位置
  • radius: 圆的半径
  • color: 圆的颜色
  • thickness: 正数表示圆形轮廓的粗细。负数表示要绘制实心圆。
  • shift: 圆心坐标点和半径值的小数点位数
# 轮廓外接圆
# 返回圆心坐标和半径
(x,y),radius = cv2.minEnclosingCircle(cnt)
# 圆心坐标
center = (int(x),int(y))
# 半径
radius = int(radius)
# 绘制外接圆,输入整型
circle = cv2.circle(img,center,radius,(255,0,0),2)
cv_show('circle',circle)

最后有惊喜(别错过哦)

跻身大厂是每一个程序员的梦想,也希望有机会可以大放异彩,成绩斐然。不过,不积跬步无以至千里,理想和现实的距离是需要努力来不断缩短的。

所以这里我准备了一些礼包,希望能够帮助到各位小伙伴。

★礼包1

如果对学习没有自制力或者没有一起学习交流的动力,欢迎私信或者评论区留言,我会拉你进学习交流群,我们一起交流学习,报团打卡,群内更有众多福利等你来解锁哟,赶快加入我们吧!

★礼包2

?Python全套电子书,200本总共6个G电子书资料,囊括Python各大领域。

?Python练手项目,包括爬虫、数据分析、机器学习、人工智能、小游戏开发。

相关推荐

最全的MySQL总结,助你向阿里“开炮”(面试题+笔记+思维图)

前言作为一名编程人员,对MySQL一定不会陌生,尤其是互联网行业,对MySQL的使用是比较多的。对于求职者来说,MySQL又是面试中一定会问到的重点,很多人拥有大厂梦,却因为MySQL败下阵来。实际上...

Redis数据库从入门到精通(redis数据库设计)

目录一、常见的非关系型数据库NOSQL分类二、了解Redis三、Redis的单节点安装教程四、Redis的常用命令1、Help帮助命令2、SET命令3、过期命令4、查找键命令5、操作键命令6、GET命...

netcore 急速接入第三方登录,不看后悔

新年新气象,趁着新年的喜庆,肝了十来天,终于发了第一版,希望大家喜欢。如果有不喜欢看文字的童鞋,可以直接看下面的地址体验一下:https://oauthlogin.net/前言此次带来得这个小项目是...

精选 30 个 C++ 面试题(含解析)(c++面试题和答案汇总)

大家好,我是柠檬哥,专注编程知识分享。欢迎关注@程序员柠檬橙,编程路上不迷路,私信发送以下关键字获取编程资源:发送1024打包下载10个G编程资源学习资料发送001获取阿里大神LeetCode...

Oracle 12c系列(一)|多租户容器数据库

作者杨禹航出品沃趣技术Oracle12.1发布至今已有多年,但国内Oracle12C的用户并不多,随着12.2在去年的发布,选择安装Oracle12c的客户量明显增加,在接下来的几年中,Or...

flutter系列之:UI layout简介(flutter-ui-nice)

简介对于一个前端框架来说,除了各个组件之外,最重要的就是将这些组件进行连接的布局了。布局的英文名叫做layout,就是用来描述如何将组件进行摆放的一个约束。在flutter中,基本上所有的对象都是wi...

Flutter 分页功能表格控件(flutter 列表)

老孟导读:前2天有读者问到是否有带分页功能的表格控件,今天分页功能的表格控件详细解析来来。PaginatedDataTablePaginatedDataTable是一个带分页功能的DataTable,...

Flutter | 使用BottomNavigationBar快速构建底部导航

平时我们在使用app时经常会看到底部导航栏,而在flutter中它的实现也较为简单.需要用到的组件:BottomNavigationBar导航栏的主体BottomNavigationBarI...

Android中的数据库和本地存储在Flutter中是怎样实现的

如何使用SharedPreferences?在Android中,你可以使用SharedPreferencesAPI来存储少量的键值对。在Flutter中,使用Shared_Pref...

Flet,一个Flutter应用的实用Python库!

▼Flet:用Python轻松构建跨平台应用!在纷繁复杂的Python框架中,Flet宛如一缕清风,为开发者带来极致的跨平台应用开发体验。它用最简单的Python代码,帮你实现移动端、桌面端...

flutter系列之:做一个图像滤镜(flutter photo)

简介很多时候,我们需要一些特效功能,比如给图片做个滤镜什么的,如果是h5页面,那么我们可以很容易的通过css滤镜来实现这个功能。那么如果在flutter中,如果要实现这样的滤镜功能应该怎么处理呢?一起...

flutter软件开发笔记20-flutter web开发

flutterweb开发优势比较多,采用统一的语言,就能开发不同类型的软件,在web开发中,特别是后台式软件中,相比传统的html5开发,更高效,有点像c++编程的方式,把web设计出来了。一...

Flutter实战-请求封装(五)之设置抓包Proxy

用了两年的flutter,有了一些心得,不虚头巴脑,只求实战有用,以供学习或使用flutter的小伙伴参考,学习尚浅,如有不正确的地方还望各路大神指正,以免误人子弟,在此拜谢~(原创不易,转发请标注来...

为什么不在 Flutter 中使用全局变量来管理状态

我相信没有人用全局变量来管理Flutter应用程序的状态。毫无疑问,我们的Flutter应用程序需要状态管理包或Flutter的基本小部件(例如InheritedWidget或St...

Flutter 攻略(Dart基本数据类型,变量 整理 2)

代码运行从main方法开始voidmain(){print("hellodart");}变量与常量var声明变量未初始化变量为nullvarc;//未初始化print(c)...