【OpenCV实现图像找到轮廓的不同特征,就像面积,周长,质心,边界框等等。】

文章目录

概要

OpenCV是一个流行的计算机视觉库,它提供了许多图像处理和分析功能,其中包括查找图像中物体的轮廓。通过查找轮廓,可以提取许多有用的特征,如面积、周长、质心、边界框等。

以下是几种使用OpenCV查找轮廓时常见的特征:

面积:可以使用 cv2.contourArea() 函数计算轮廓的面积。该函数将轮廓作为输入,并返回浮点数表示轮廓的面积。

周长:可以使用 cv2.arcLength() 函数计算轮廓的周长。该函数将轮廓作为输入,并返回浮点数表示轮廓的周长。

质心:可以使用 cv2.moments() 函数计算轮廓的质心。该函数将轮廓作为输入,并返回一个字典,其中包含轮廓的各种矩形,包括轮廓的质心。

边界框:使用 cv2.boundingRect() 函数可以计算轮廓的边界框。该函数将轮廓作为输入,并返回一个元组,其中包括边界框的x和y坐标以及宽度和高度。

最小区域矩形:使用 cv2.minAreaRect() 函数可以计算轮廓的最小区域矩形。该函数将轮廓作为输入,并返回一个元组,其中包括矩形的中心坐标、宽度和高度以及角度。

最小外接圆:使用 cv2.minEnclosingCircle() 函数可以计算轮廓的最小外接圆。该函数将轮廓作为输入,并返回一个元组,其中包括圆心坐标和半径。

这些特征可以用于描述轮廓并提取有用的信息。例如,面积和周长可以用于分类和识别物体,质心可以用于跟踪物体的运动,边界框和最小区域矩形可以用于确定物体的位置和方向,最小外接圆可以用于确定物体的大小。

图像矩

bash 复制代码
图像矩可以帮助您计算一些特征,如物体的质心、物体的面积等。函数 cv.moments() 提供了一个计算出所有矩值的字典。代码如下:

import numpy as np
import cv2 as cv

img = cv.imread('star.jpg', 0)
ret, thresh = cv.threshold(img, 127, 255, 0)
contours, hierarchy = cv.findContours(thresh, 1, 2)

cnt = contours[0]
M = cv.moments(cnt)
print(M)

在这个M中,你可以提取有用的数据,如面积,质心等等。质心由如下关系式给出:

代码如下:

bash 复制代码
cx = int(M['m10'] / M['m00'])
cy = int(M['m01'] / M['m00'])

轮廓面积

轮廓面积可以通过函数 cv.contourArea() 或者是 M['m00'] 得到。

bash 复制代码
area = cv.contourArea(cnt)

轮廓周长

它也被称为弧长。它可以由函数 cv.arcLength() 得到。第二个参数需要指名形状是否闭合,闭合传入 True,否则传入 False。

bash 复制代码
perimeter = cv.arcLength(cnt, True)

轮廓近似

OpenCV中的approxPolyDP()函数是一个实现了Douglas-Peucker算法的轮廓近似函数。该函数可以将一个轮廓形状近似为另一个顶点数量较少的形状,精度取决于我们指定的参数epsilon。

例如,如果我们想要在图像中找到一个正方形,但由于图像中的噪声或其他因素,我们无法得到完美的正方形轮廓。此时,我们可以使用approxPolyDP()函数来近似轮廓形状,从而得到更接近真实形状的结果。在这种情况下,我们需要选择一个合适的epsilon值来控制近似精度。通常建议将epsilon设置为原始轮廓周长的一定比例,例如0.1*cv.arcLength(cnt, True)。

使用approxPolyDP()函数可以减少轮廓的顶点数量,从而提高图像处理和分析的效率和准确性。

bash 复制代码
epsilon = 0.1*cv.arcLength(cnt, True)
approx = cv.approxPolyDP(cnt, epsilon, True)

凸包

bash 复制代码
hull = cv.convexHull(points[, hull[, clockwise[, returnPoints]]])

参数详细信息:

•points 是我们穿过的轮廓。

•clockwise:方向标志。如果为True,则输出凸包的方向为顺时针方向。否则,其方向为逆时针方向。

•returnPoints:默认情况下为True。它会返回外壳点的坐标。如果为False,则返回与外壳点相对应的轮廓点的索引。

所以要得到上图中的凸包,以下就足够了:

bash 复制代码
hull = cv.convexHull(cnt)

但是,如果要查找凸性缺陷,则需要传递returnPoints=False。为了理解它,我们将拍摄上面的矩形图像。首先我发现它的轮廓是cnt。现在我找到了它的凸包,returnPoints=True,我得到了以下值:[[234 202]],[[51 202]],[[51 79]],[[234 79]],它们是矩形的四个角点。现在,如果returnPoints=False也这样做,我得到以下结果:[[129],[67],[0],[142]]。这些是等高线中对应点的索引。例如,检查第一个值:cnt[129]=[[234202]],该值与第一个结果相同(其他值依此类推)。

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

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

其中,参数的详细信息如下:

• points:表示我们要找凸包的轮廓。

• clockwise:方向标志。如果为True,则输出凸包的方向为顺时针方向;否则,其方向为逆时针方向。

• returnPoints:默认情况下为True。它会返回外壳点的坐标。如果为False,则返回与外壳点相对应的轮廓点的索引。

因此,如果我们只需要得到轮廓的凸包,则可以使用以下代码:

hull = cv2.convexHull(cnt)

但是,如果需要查找凸性缺陷,则需要将returnPoints设置为False。为了更好地理解其含义,考虑以下矩形图像。首先,我们找到了矩形的轮廓cnt。接着,我们使用returnPoints=True选项来计算其凸包,得到以下四个点的坐标值:[[234 202]],[[51 202]],[[51 79]],[[234 79]]。这些坐标值是矩形四个角的点。现在,如果我们将returnPoints设置为False,得到的将是以下四个点的索引值:[[129], [67], [0], [142]]。这些是轮廓数组中对应点的索引值。例如,第一个值129表示cnt[129]=[[234 202]],该值与前面求得的第一个凸包点的坐标值相同(其他索引值也类似)。

检查凸性

有一个函数可以检查曲线是否是凸的,cv.isContourConvex()。它只返回True或False。

bash 复制代码
k = cv.isContourConvex(cnt)

边界矩形

边界矩形是用于包围对象或轮廓的矩形形状。有两种类型的边界矩形:

7.a. 直边界矩形:

直边界矩形是一个简单的矩形,不考虑对象的旋转。它可以通过使用cv2.boundingRect()函数来找到。该函数返回一个四元组(x,y,w,h),其中(x,y)表示矩形左上角的坐标,(w,h)表示矩形的宽度和高度。

bash 复制代码
x, y, w, h = cv2.boundingRect(cnt)
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)

以上代码将在图像img上绘制一个矩形,框住了轮廓cnt所代表的对象。

7.b. 旋转矩形:

旋转矩形是根据对象的最小面积绘制的矩形,并考虑了对象的旋转。要获得旋转矩形,可以使用cv2.minAreaRect()函数。该函数返回一个Box2D结构,其中包含矩形的中心坐标(x,y)、宽度和高度(w,h),以及旋转角度。

要绘制旋转矩形,我们需要得到矩形的四个角点。可以使用cv2.boxPoints()函数获得这些角点,该函数将旋转矩形作为参数,并返回一个数组包含四个角点的坐标。

bash 复制代码
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(img, [box], 0, (0, 0, 255), 2)

以上代码将在图像img上绘制一个红色边界框,该边界框是根据轮廓cnt的最小面积旋转矩形计算而来。

最小外接圆

bash 复制代码
# 导入OpenCV库
import cv2 as cv

# 使用cv.minEnclosingCircle()找到最小外接圆
(x, y), radius = cv.minEnclosingCircle(cnt)
center = (int(x), int(y))
radius = int(radius)

# 在图像上绘制最小外接圆
cv.circle(img, center, radius, (0, 255, 0), 2)

# 显示图像
cv.imshow('最小外接圆', img)

拟合椭圆

bash 复制代码
# 使用cv.fitEllipse()将椭圆拟合到对象上
ellipse = cv.fitEllipse(cnt)

# 在图像上绘制拟合的椭圆
cv.ellipse(img, ellipse, (0, 255, 0), 2)

# 显示图像
cv.imshow('拟合椭圆', img)

直线拟合

bash 复制代码
# 获取图像的行和列数
rows, cols = img.shape[:2]

# 使用cv.fitLine()将直线拟合到一组点上
[vx, vy, x, y] = cv.fitLine(cnt, cv.DIST_L2, 0, 0.01, 0.01)
lefty = int((-x * vy / vx) + y)
righty = int(((cols - x) * vy / vx) + y)

# 在图像上绘制拟合的直线
cv.line(img, (cols - 1, righty), (0, lefty), (0, 255, 0), 2)

# 显示图像
cv.imshow('直线拟合', img)
相关推荐
Abladol-aj1 小时前
并发和并行的基础知识
java·linux·windows
HPC_fac130520678161 小时前
科研深度学习:如何精选GPU以优化服务器性能
服务器·人工智能·深度学习·神经网络·机器学习·数据挖掘·gpu算力
猎嘤一号2 小时前
个人笔记本安装CUDA并配合Pytorch使用NVIDIA GPU训练神经网络的计算以及CPUvsGPU计算时间的测试代码
人工智能·pytorch·神经网络
天润融通2 小时前
天润融通携手挚达科技:AI技术重塑客户服务体验
人工智能
Elastic 中国社区官方博客4 小时前
使用 Elastic AI Assistant for Search 和 Azure OpenAI 实现从 0 到 60 的转变
大数据·人工智能·elasticsearch·microsoft·搜索引擎·ai·azure
江_小_白5 小时前
自动驾驶之激光雷达
人工智能·机器学习·自动驾驶
JunLan~6 小时前
Rocky Linux 系统安装/部署 Docker
linux·docker·容器
yusaisai大鱼6 小时前
TensorFlow如何调用GPU?
人工智能·tensorflow
方竞7 小时前
Linux空口抓包方法
linux·空口抓包
湫ccc7 小时前
《Python基础》之字符串格式化输出
开发语言·python