OpenCV-Python(21):轮廓特征及周长、面积凸包检测和形状近似

2. 轮廓特征

        轮廓特征是指由轮廓形状和结构衍生出来的一些特征参数。这些特征参数可以用于图像识别、目标检测和形状分析等应用中。常见的轮廓特征包括:

  1. 面积:轮廓所包围的区域的面积。
  2. 周长:轮廓的周长,即轮廓线的长度。
  3. 弧长:轮廓线的弧长,即轮廓的长度。
  4. 轮廓矩:轮廓的几何矩,用于描述轮廓的形状。
  5. 轮廓重心:轮廓所包围区域的重心坐标。
  6. 外接矩形:能够完全包围轮廓的矩形。
  7. 最小外接矩形:能够紧密包围轮廓的矩形,且角度与轮廓的方向一致。
  8. 外接圆:能够完全包围轮廓的圆。
  9. 最小外接圆:能够紧密包围轮廓的圆。
  10. 椭圆拟合:能够最好地拟合轮廓的椭圆。
  11. 凸包:能够包围轮廓的最小凸多边形。
  12. 轮廓层级:描述轮廓的嵌套关系。

这些轮廓特征可以通过OpenCV库的cv2.contourArea()cv2.arcLength()cv2.moments()cv2.boundingRect()cv2.minAreaRect()cv2.minEnclosingCircle()cv2.fitEllipse()cv2.convexHull()等函数来计算和获取,下面主要介绍一些常用的特征。

2.1 目标

  •  查找轮廓的不同特征,例如面积、周长、重心、边界框等。

  •  学习和掌握轮廓相关函数

2.2 矩特征

        图像矩是一种描述图像几何特征的数学工具,用于描述图像的形状、位置和分布等信息,以帮助我们计算图像的质心、面积等。图像矩可以用于图像识别、目标检测、形状分析等应用中。图像矩的计算是基于图像像素的灰度值进行的,常见的图像矩包括原点矩、中心矩和归一化矩。使用OpenCV库的cv2.moments()函数可以计算图像的矩。该函数接受一个二值化的图像作为输入,并返回一个包含各种矩的字典。可以通过字典的键来获取不同的矩。以下是一个示例代码,演示如何计算图像的矩:

import cv2

# 读取图像
image = cv2.imread("image.jpg")

# 灰度化
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 二值化
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

# 计算矩
moments = cv2.moments(thresh)

# 获取原点矩
m00 = moments["m00"]
m10 = moments["m10"]
m01 = moments["m01"]

# 获取中心矩
cx = int(m10 / m00)
cy = int(m01 / m00)

# 获取归一化矩
nu20 = moments["nu20"]
nu02 = moments["nu02"]
nu11 = moments["nu11"]

# 打印矩的值
print("m00:", m00)
print("m10:", m10)
print("m01:", m01)
print("cx:", cx)
print("cy:", cy)
print("nu20:", nu20)
print("nu02:", nu02)
print("nu11:", nu11)

上述代码中,首先读取了一张图像,并对其进行了灰度化和二值化处理。然后使用cv2.moments()函数计算了图像的矩。通过字典的键可以获取不同的矩的值。在示例代码中,获取了原点矩的值(m00、m10和m01)、中心矩的值(cx和cy)以及归一化矩的值(nu20、nu02和nu11)。最后打印了这些矩的值。需要注意的是,图像矩对图像的形状和位置非常敏感,因此在计算图像矩之前需要对图像进行预处理,如灰度化、二值化等。

注意:根据这些矩的值,我们可以计算出对象的重心,

cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])

2.3 轮廓面积

        轮廓面积是指闭合轮廓所包围的区域的面积,可以用来描述对象的大小。在OpenCV中,可以使用cv2.contourArea()函数计算轮廓的面积,也可以使用0阶矩(M['m00'])计算得到。

area = cv2.contourArea(cnt)

cv2.contourArea()函数接受一个轮廓作为输入,并返回轮廓的面积。该函数的语法如下:

area = cv2.contourArea(contour)

其中,contour是一个包含轮廓点的数组。可以通过cv2.findContours()函数找到图像中的轮廓,并提取其中的某个轮廓来计算面积。以下是一个示例代码,演示如何计算轮廓的面积:

import cv2

# 读取图像
image = cv2.imread("image.jpg")

# 灰度化
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 二值化
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

# 查找轮廓
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 遍历轮廓
for contour in contours:
    # 计算轮廓面积
    area = cv2.contourArea(contour)
    
    # 打印轮廓面积
    print("Contour area:", area)

在上述代码中,首先读取了一张图像,并对其进行了灰度化和二值化处理。然后使用cv2.findContours()函数找到图像中的轮廓。返回的contours是一个包含所有轮廓的列表。接下来,遍历轮廓列表,并使用cv2.contourArea()函数计算每个轮廓的面积。最后打印了每个轮廓的面积。需要注意的是,cv2.contourArea()函数计算的是轮廓的面积,而不是对象的实际面积。因此,在使用该函数之前,需要对图像进行预处理,如灰度化、二值化等,以确保轮廓能够正确识别。

2.4 轮廓周长

        轮廓周长是指闭合轮廓的长度,可以用来描述对象的形状。在OpenCV中,可以使用cv2.arcLength()函数计算轮廓的周长。cv2.arcLength()函数接受一个轮廓作为输入,并返回轮廓的周长。该函数的语法如下:

perimeter = cv2.arcLength(contour, closed)

其中,contour是一个包含轮廓点的数组,closed是一个布尔值,指示轮廓是否是闭合的。如果轮廓是闭合的,则closedTrue;如果轮廓是开放的,则closedFalse。以下是一个示例代码,演示如何计算轮廓的周长:

import cv2

# 读取图像
image = cv2.imread("image.jpg")

# 灰度化
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 二值化
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

# 查找轮廓
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 遍历轮廓
for contour in contours:
    # 计算轮廓周长
    perimeter = cv2.arcLength(contour, True)
    
    # 打印轮廓周长
    print("Contour perimeter:", perimeter)

在上述代码中,首先读取了一张图像,并对其进行了灰度化和二值化处理。然后使用cv2.findContours()函数找到图像中的轮廓。返回的contours是一个包含所有轮廓的列表。接下来,遍历轮廓列表,并使用cv2.arcLength()函数计算每个轮廓的周长。最后打印了每个轮廓的周长。需要注意的是,cv2.arcLength()函数计算的是轮廓的周长,而不是对象的周长。因此,在使用该函数之前,需要对图像进行预处理,如灰度化、二值化等,以确保轮廓能够正确识别。

2.5 轮廓近似

        在OpenCV中,可以使用cv2.approxPolyDP()函数对轮廓进行近似处理。轮廓近似可以将复杂的轮廓形状简化为更简单的几何形状,如直线或曲线。cv2.approxPolyDP()函数接受一个轮廓作为输入,并返回一个近似的轮廓。该函数的语法如下:

approx = cv2.approxPolyDP(curve, epsilon, closed)

其中,curve是一个包含轮廓点的数组,epsilon是指定近似精度的参数,closed是一个布尔值,指示轮廓是否是闭合的。如果轮廓是闭合的,则closedTrue;如果轮廓是开放的,则closedFalse。将轮廓形状近似到另外一种由更少点组成的轮廓形状,新轮廓的点的数目由我们设定的准确度来决定。实现这一功能主要使用的是Douglas-Peucker算法(你可以到维基百科获得更多此算法的细节)。为了帮助理解,假设我们需要在一幅图像中查找一个矩形,但是由于图像的种种原因,我们不能得到一个完美的矩形,而是一个(坏形状),如下图所示:

现在就可以使用这个函数来近似这个形状了。这个函数的第二个参数叫epsilon,它是从原始轮廓到近似轮廓的最大距离。它是一个准确度参数。选择一个好的epsilon 对于得到满意结果非常重要。

epsilon = 0.1*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)

下面第二幅图中的绿线是当epsilon = 10% 时得到近似轮廓,第三幅图是当epsilon = 1% 时得到的近似轮廓。第三个参数设定弧线是否闭合。

以下是一个示例代码,演示如何对轮廓进行近似处理:

import cv2

# 读取图像
image = cv2.imread("image.jpg")

# 灰度化
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 二值化
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

# 查找轮廓
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 遍历轮廓
for contour in contours:
    # 近似轮廓
    epsilon = 0.01 * cv2.arcLength(contour, True)
    approx = cv2.approxPolyDP(contour, epsilon, True)
    
    # 绘制近似轮廓
    cv2.drawContours(image, [approx], 0, (0, 255, 0), 2)

在上述代码中,首先读取了一张图像,并对其进行了灰度化和二值化处理。然后使用cv2.findContours()函数找到图像中的轮廓。返回的contours是一个包含所有轮廓的列表。接下来,遍历轮廓列表,并使用cv2.arcLength()函数计算每个轮廓的周长。然后根据周长计算一个近似精度epsilon,并使用cv2.approxPolyDP()函数对轮廓近似处理。最后使用cv2.drawContours()函数绘制近似轮廓。需要注意的是,轮廓近似处理是一种对轮廓进行简化的方法,可以减少轮廓点的数量,从而降低计算的复杂性。但近似精度epsilon的选择需要根据具体情况进行调整,过大的epsilon会导致近似结果不准确,而过小的epsilon会导致近似结果过于复杂。因此,在使用cv2.approxPolyDP()函数进行轮廓近似处理时,需要根据实际情况选择合适的epsilon值。

2.6 凸包

        在计算机视觉中,凸包(Convex Hull)是指一个包围一组点的最小凸多边形。凸多边形是一个所有内角均小于180度的多边形。凸包与轮廓近似相似,但不同,然有些情况下它们给出的结果是一样的。OpenCV中提供了cv2.convexHull()函数来计算给定点集的凸包,同时检测一个曲线是否具有凸性缺陷并能纠正缺陷。一般来说,凸性曲线总是凸出来的或者至少是平的。如果有地方凹下去了,就叫做凸性缺陷。例如下图中的手。红色曲线显示了手的凸包,凸性缺陷被双箭头标出来了。


关该cv2.convexHull()函数的语法如下:

hull = cv2.convexHull(points, clockwise, returnPoints)

其中,points是一个包含点集的数组,clockwise是一个布尔值,用于指定凸包的顺序,如果为True,则返回的凸包按顺时针方向排序;如果为False,则返回的凸包按逆时针方向排序;returnPoints是一个布尔值,用于指定返回的凸包是点的坐标还是索引,默认为True,表示返回点的坐标。

要获得上图的凸包,下面的命令就够了:

hull = cv2.convexHull(cnt)

但是如果你想获得凸性缺陷,需要把returnPoints 设置为False。以上面的矩形为例,首先我们找到他的轮廓cnt。现在我把returnPoints 设置为True 查找凸包,我得到下列值:

[[[234 202]], [[ 51 202]], [[ 51 79]], [[234 79]]],其实就是矩形的四个角点。现在把returnPoints 设置为False,我得到的结果是[[129],[ 67],[ 0],[142]],他们是轮廓点的索引。例如cnt[129] = [[234, 202]]这与前面我们得到结果的第一个值是一样的。

以下是一个示例代码,演示如何使用cv2.convexHull()函数计算凸包:

import cv2
import numpy as np

# 创建一组点
points = np.array([[10, 10], [10, 100], [100, 10], [100, 100], [50, 50]])

# 计算凸包
hull = cv2.convexHull(points)

# 绘制凸包
image = np.zeros((200, 200, 3), dtype=np.uint8)
cv2.polylines(image, [hull], True, (0, 255, 0), 2)

# 显示图像
cv2.imshow("Convex Hull", image)
cv2.waitKey(0)
cv2.destroyAllWindows()

在上述代码中,首先创建了一个包含5个点的数组points。然后使用cv2.convexHull()函数计算凸包,并将结果保存在hull中。接下来,创建一个空白图像image,并使用cv2.polylines()函数绘制凸包。最后,显示图像。

需要注意的是,cv2.convexHull()函数返回的凸包是一个包含点的数组,可以通过cv2.polylines()函数绘制凸包。另外,可以使用cv2.isContourConvex()函数检查一个轮廓是否是凸的。如果返回True,则表示轮廓是凸的;如果返回False,则表示轮廓是非凸的。凸包在计算机视觉中有广泛的应用,如图像分割、形状匹配等。凸包可以帮助我们简化复杂的形状,并提取出形状的关键特征。

2.7 凸性检测

        函数cv2.isContourConvex() 可以可以用来检测一个曲线是不是凸的。它只能返回True 或False。没什么大不了的。

k = cv2.isContourConvex(cnt)

2.8 边界矩形

        通常有两类边界矩形:直边界矩形、旋转边界矩形

直边界矩形 

        一个直矩形(就是没有旋转的矩形)。它不会考虑对象是否旋转。所以直边界矩形的面积不是最小的。可以使用函数cv2.boundingRect() 查找得到。(x,y)为矩形左上角的坐标,(w,h)是矩形的宽和高。

x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
旋转边界矩形

        这个边界矩形是积最小的,因为它考虑了对象的旋转。用到的函数为cv2.minAreaRect()。返回的是一个Box2D 结构,其中包含矩形左上角角点的坐标(x,y),矩形的宽和高(w,h)以及旋转角度。但是要绘制这个矩形需要矩形的4 个顶点,可以通过函数cv2.boxPoints() 获得。

x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)

把这两中边界矩形显示在下图中,其中绿色的为直矩形,红的为旋转矩形。

2.9 最小外接圆

        函数cv2.minEnclosingCircle() 可以帮我们找到一个对象的外接圆。它是所有能够包括对象的圆中面积最小的一个。

(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
img = cv2.circle(img,center,radius,(0,255,0),2)

2.10 椭圆拟合

        使用的函数为cv2.ellipse(),返回值其实就是旋转边界矩形的内切圆。

ellipse = cv2.fitEllipse(cnt)
im = cv2.ellipse(im,ellipse,(0,255,0),2)

2.11 直线拟合

        我们可以根据一组点拟合出一条直线,同样我们也可以为图像中的白色点拟合出一条直线。

rows,cols = img.shape[:2]
[vx,vy,x,y] = cv2.fitLine(cnt, cv2.DIST_L2,0,0.01,0.01)
lefty = int((-x*vy/vx) + y)
righty = int(((cols-x)*vy/vx)+y)
img = cv2.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/276804.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

idea 插件开发之 HelloWorld

前言 本文使用的 idea 2023.3 版本进行插件入门开发,首先要说明的是 idea 2023 版本及以后的 idea,对插件开发进行了一定程度的变动: 1、创建项目时不再支持 maven 选项 2、必须是 jdk17 及以后版本(点击查看官网版本对应关系&…

阿里云数据库PolarDB费用价格_MySQL版_PolarDB_分布式版

阿里云数据库PolarDB租用价格表,云数据库PolarDB MySQL版2核4GB(通用)、2个节点、60 GB存储空间55元5天,云数据库 PolarDB 分布式版标准版2核16G(通用)57.6元3天,阿里云百科aliyunbaike.com分享…

留言板(Mybatis连接数据库版)

目录 1.添加Mybatis和SQL的依赖 2.建立数据库和需要的表 3.对应表中的字段,补充Java对象 4.对代码进行逻辑分层 5.后端逻辑代码 之前的项目实例【基于Spring MVC的前后端交互案例及应用分层的实现】https://blog.csdn.net/weixin_67793092/article/details/134…

Q-Tester:适用于开发、生产和售后的诊断测试软件

Q-Tester.Expert是一款基于ODX(ASAM MCD-2D / ISO 22901-1)国际标准的工程诊断仪。通过此诊断仪可实现与ECU控制器之间的数据交互。这一基于ODX国际标准的解决方案,其优势在于:ODX数据库不仅可在开发部门交互,而且可在…

力扣刷题记录(20)LeetCode:198、213、337

198. 打家劫舍 我们从第一个开始分析: dp[i]:i表示索引,dp表示当前索引可以拿到的最高金额 索引为0时,可以拿到的最高金额为1; 索引为1时,可以拿到的最高金额就是在索引[0,1]之间取,为2 索引为2时&…

网络通信连接器

网络通信连接器 常用电子元器件类型 19S101-40ML5 射频连接器 SMD贴片 RF同轴连接器 \GS72V3SO-R SOP8 GS72V3 文章目录 网络通信连接器前言一、网络通信连接器二、19S101-40ML5 射频连接器 SMD贴片 RF同轴连接器三、GS72V3SO-R SOP8 GS72V3总结前言 网络通信连接器是用于在…

ChatGPT在地学、GIS、气象、农业、生态、环境等领域中的高级应用

以ChatGPT、LLaMA、Gemini、DALLE、Midjourney、Stable Diffusion、星火大模型、文心一言、千问为代表AI大语言模型带来了新一波人工智能浪潮,可以面向科研选题、思维导图、数据清洗、统计分析、高级编程、代码调试、算法学习、论文检索、写作、翻译、润色、文献辅助…

GPT分区格式

GPT分区格式 [rootlocalhost ~]# gdisk /dev/sdb -bash: gdisk: 未找到命令 [rootlocalhost ~]# yum -y install gdisk- gdisk命令用于查看磁盘使用情况和磁盘分区(GPT分区格式) - 命令格式:gdisk [选项...] [设备路径] - 常用选项&…

算法练习Day23 (Leetcode/Python-回溯算法)

46. Permutations Given an array nums of distinct integers, return all the possible permutations. You can return the answer in any order. Example 1: Input: nums [1,2,3] Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]思路:此题可用回溯…

作为铭文跨链赛道龙头,SoBit 有何突出之处?

跨链桥赛道将是铭文市场长期的发展的刚需 在比特币网络中,Ordinals 铭文铸造的铭文总量已经超过了 5100 万枚,并累计费用收入超 5028 BTC。同时,仅 BRC-20 叙事方向的市值,就已经超过了 30 亿美元,并且随着铭文资产种类…

Apache DolphinScheduler 3.1.9 版本发布:提升系统的稳定性和性能

🚀我们很高兴宣布,Apache DolphinScheduler 的最新版本 3.1.9 已正式发布!此版本在 3.1.8 的基础上进行了关键的 bug 修复和文档更新,共计修复了 14 个 bug 和改进了 3 个文档。 主要更新亮点 本次更新重点解决了以下几个关键问题…

3D游戏角色建模纹理贴图处理

在线工具推荐: 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 在本文中,我们将介绍 3D 纹理的基础知识,并讨…

15-网络安全框架及模型-BLP机密性模型

目录 BLP机密性模型 1 背景概述 2 模型原理 3 主要特性 4 优势和局限性 5 困难和挑战 6 应用场景 7 应用案例 BLP机密性模型 1 背景概述 BLP模型,全称为Bell-LaPadula模型,是在1973年由D.Bell和J.LaPadula在《Mathematical foundations and mod…

web渗透安全学习笔记:1、入门基础知识/ XXS漏洞

前言 自编写python渗透工具编写学习笔记专栏以来,笔者便发现了一个较为严重的问题:我们大多数文章都是学习如何用python编写扫描与利用漏洞的渗透工具,却没有真正解析漏洞的形成原因,长此以往我们的学习就只会浮于表面&#xff0c…

C#中创建包含括号的数据表字段的处理方法

在C#中创建数据表时,有时我们会遇到需要在字段名称中包含括号的情况。这种需求可能出现在字段名称包含特殊字符、关键字或空格的情况下。本文将探讨如何处理这种情况,并介绍一些常用的方法。 一、为什么需要处理包含括号的数据表字段 1. 避免与C#语言保…

Spark RDD操作性能优化技巧

Apache Spark是一个强大的分布式计算框架,用于处理大规模数据。然而,在处理大数据集时,性能优化成为一个关键问题。本文将介绍一些Spark RDD操作的性能优化技巧,帮助大家充分利用Spark的潜力,并获得更快的处理速度。 …

【UE5.1】程序化生成Nanite植被

目录 效果 步骤 一、下载Gaea软件和树林资产 二、使用Gaea生成贴图 三、 生成地形 四、生成草地 五、生成树林 六、生成湖泊 七、其它功能介绍 7.1 调整树林生成的面积 7.2 让植物随风飘动 7.3 玩家和植物互动 7.4 雪中树林 7.5 环境音效 效果 步骤 一、下载Ga…

svn外网打不开url地址怎么解决

在家或者出差在外经常会有连接到公司内部SVN服务器的需求, 但是 svn外网打不开url地址怎么解决?如何才能连接到公司内部SVN服务器?今天小编教你一招,在本地SVN服务的内网IP端口用快解析软件添加映射,一步就可以提供让公…

Spring AOP—深入动态代理 万字详解(通俗易懂)

目录 一、前言 二、动态代理快速入门 1.为什么需要动态代理? : 2.动态代理使用案例: 3.动态代理的灵活性 : 三、深入动态代理 1.需求 : 2.实现 : 2.1 接口和实现类 2.2 提供代理对象的类 2.3 测试类 3.引出AOP : 四、总结 一、前言 第四节内容&…

中文版大模型 Token 成本计算器

分享一个轻量的小工具,10MB 左右,能够帮助你直观的了解大模型 Token 的计算方法。 希望能够帮助到想了解或者正在规划模型 API 使用成本的你。 写在前面 之所以折腾这个小工具,是因为有朋友和我提问,大模型 API 的 Token 到底是…