opencv-python 4.9.2. 轮廓特征
2023/3/31 18:22:02
本文主要是介绍opencv-python 4.9.2. 轮廓特征,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
矩
图像的矩可帮助你计算某些特征,如对象的质心,对象的面积等特征。函数cv.moments()给出了计算的所有矩值的字典。
从这一刻起,你可以提取有用的数据,如面积,质心等。质心由关系给出,$$ C_{x}=\frac{M_{10}}{M_{00}} $$和 $$ C_{y}=\frac{M_{01}}{M_{00}} $$。
这可以按如下方式完成:
import cv2 as cv img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle.jpg') imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) ret, thresh = cv.threshold(imgray, 127, 255, 0) # 获取轮廓点 contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) print(99, len(contours)) # 找到最内层的元素, 这里是2是因为图像总共有三层 cnt = contours[2] # 标记选中的区域 res1 = cv.drawContours(img, cnt, -1, (0, 255, 0), 3) # 计算矩 M = cv.moments(cnt) # 计算质心 cx = int(M['m10'] / M['m00']) cy = int(M['m01'] / M['m00']) # 画出质心 cv.circle(img, (cx, cy), 5, (255, 0, 0), -1) cv.imshow('img', img) cv.waitKey(0)
轮廓面积
轮廓区域由函数cv.contourArea()或M['m00']给出。
import cv2 as cv img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle.jpg') imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) ret, thresh = cv.threshold(imgray, 127, 255, 0) # 获取轮廓点 contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) print(99, len(contours)) # 找到最内层的元素, 这里是2是因为图像总共有三层 cnt = contours[2] # 标记选中的区域 res1 = cv.drawContours(img, cnt, -1, (0, 255, 0), 3) # 计算矩 M = cv.moments(cnt) # 计算轮廓面积 area = cv.contourArea(cnt) print(111, area, M['m00'])
轮廓周长
轮廓周长也被称为弧长。可以使用cv.arcLength()函数找到它。第二个参数指定形状是闭合轮廓(如果传递为True),还是仅仅是曲线。
import cv2 as cv img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle.jpg') imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) ret, thresh = cv.threshold(imgray, 127, 255, 0) # 获取轮廓点 contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) print(99, len(contours)) # 找到最内层的元素, 这里是2是因为图像总共有三层 cnt = contours[2] # 标记选中的区域 res1 = cv.drawContours(img, cnt, -1, (0, 255, 0), 3) # 计算轮廓周长 perimeter = cv.arcLength(cnt, True) print(222, perimeter)
轮廓近似
它根据我们指定的精度将轮廓形状近似为具有较少顶点数的另一个形状。它是Douglas-Peucker算法的一种实现方式。 要理解这一点,可以假设你试图在图像中找到一个正方形,但是由于图像中的一些问题,你没有得到一个完美的正方形,而是一个“坏形状”(如下图第一张图所示)。现在你可以使用此功能来近似形状。在这里,第二个参数称为epsilon,它是从轮廓到近似轮廓的最大距离。这是一个准确度参数。需要选择适当的epsilon才能获得正确的输出。参数越小,两直线越接近。
epsilon = 0.01 * cv.arcLength(cnt, True) approx = cv.approxPolyDP(cnt, epsilon, True)
import cv2 as cv img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle1.jpg') imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) ret, thresh = cv.threshold(imgray, 127, 255, 0) # 获取轮廓点 contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) print(99, len(contours)) # 找到最内层的元素, 这里是2是因为图像总共有三层 cnt = contours[2] # 计算轮廓近似 epsilon=弧长的5%的近似曲线 epsilon = 0.05 * cv.arcLength(cnt, True) approx = cv.approxPolyDP(cnt, epsilon, True) # 绘制轮廓近似 res3 = cv.drawContours(img, [approx], -1, (0, 0, 255), 3) cv.imshow('img', img) cv.waitKey(0)
下边第一幅图是 epsilon=弧长的5%的近似曲线, 第二幅图是 epsilon=弧长的1%的近似曲线
凸包
凸包看起来类似于轮廓近似,但它不是(两者在某些情况下可能提供相同的结果)。这里,cv.convexHull()函数检查曲线的凸性缺陷并进行修正。一般而言,凸曲线是总是凸出或至少平坦的曲线。如果它在内部膨胀,则称为凸性缺陷。例如,检查下面的手形图像。红线表示手的凸包。双面箭头标记显示凸起缺陷,即船体与轮廓的局部最大偏差。
hull = cv.convexHull(points[, hull[, clockwise[, returnPoints]]
参数详情:
- points:是我们传入的轮廓。
- hull:是输出,通常我们忽略它。
- clocwise:方向标志。如果为True,则输出凸包顺时针方向。否则,它逆时针方向。
- reurnPoints:默认为True。然后它返回凸包点的坐标。如果为False,则返回与凸包点对应的轮廓点的索引。
import cv2 as cv img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle1.jpg') imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) ret, thresh = cv.threshold(imgray, 127, 255, 0) # 获取轮廓点 contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) print(99, len(contours)) # 找到最内层的元素, 这里是2是因为图像总共有三层 cnt = contours[2] # 凸包 hull = cv.convexHull(cnt) # 绘制凸包 res4 = cv.drawContours(img, [hull], -1, (0, 0, 0), 3) cv.imshow('img', img) cv.waitKey(0)
检查凸性
函数cv.isContourConvex()可以检查曲线是否凸的,它只返回True或False,没有什么理解上的问题。k = cv.isContourConvex(cnt)
边界矩形
有两种类型的边界矩形。
a.直边矩形
它是一个直的矩形,它不考虑对象的旋转。因此,边界矩形的面积不是最小的。它由函数cv.boundingRect()找到。
设(x,y)为矩形的左上角坐标,(w,h)为宽度和高度。
x,y,w,h = cv.boundingRect(cnt) cv.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
import cv2 as cv img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle1.jpg') imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) ret, thresh = cv.threshold(imgray, 127, 255, 0) # 获取轮廓点 contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) print(99, len(contours)) # 找到最内层的元素, 这里是2是因为图像总共有三层 cnt = contours[2] # 直边矩形 x, y, w, h = cv.boundingRect(cnt) cv.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2) cv.imshow('img', img) cv.waitKey(0)
b.旋转矩形
这里,以最小面积绘制边界矩形,因此它也考虑旋转。使用的函数是cv.minAreaRect()。它返回一个Box2D结构,其中包含以下detals - (center(x,y),(width,height),rotation of rotation)。但要画这个矩形,我们需要矩形的4个角。它是由函数cv.boxPoints()获得的。
rect = cv.minAreaRect(cnt) box = cv.boxPoints(rect) box = np.int0(box) cv.drawContours(img,[box],0,(0,0,255),2)
import cv2 as cv import numpy as np img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle1.jpg') imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) ret, thresh = cv.threshold(imgray, 127, 255, 0) # 获取轮廓点 contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) print(99, len(contours)) # 找到最内层的元素, 这里是2是因为图像总共有三层 cnt = contours[2] # 旋转矩形 rect = cv.minAreaRect(cnt) box = cv.boxPoints(rect) box = np.int0(box) cv.drawContours(img, [box], 0, (0, 0, 255), 2) cv.imshow('img', img) cv.waitKey(0)
最小外接圈
接下来,我们使用函数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)
import cv2 as cv import numpy as np img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle1.jpg') imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) ret, thresh = cv.threshold(imgray, 127, 255, 0) # 获取轮廓点 contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) print(99, len(contours)) # 找到最内层的元素, 这里是2是因为图像总共有三层 cnt = contours[2] # 最小外接圆 (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', img) cv.waitKey(0)
椭圆拟合
接下来是将椭圆拟合到一个对象上。它返回刻有椭圆的旋转矩形。
ellipse = cv.fitEllipse(cnt) cv.ellipse(img, ellipse, (0, 255, 0), 2)
import cv2 as cv import numpy as np img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle1.jpg') imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) ret, thresh = cv.threshold(imgray, 127, 255, 0) # 获取轮廓点 contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) print(99, len(contours)) # 找到最内层的元素, 这里是2是因为图像总共有三层 cnt = contours[2] # 拟合椭圆 ellipse = cv.fitEllipse(cnt) cv.ellipse(img, ellipse, (0, 255, 0), 2) cv.imshow('img', img) cv.waitKey(0)
拟合一条线
类似地,我们可以在一组点上拟合一条线。
rows,cols = img.shape[:2] [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)
import cv2 as cv import numpy as np img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle1.jpg') imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) ret, thresh = cv.threshold(imgray, 127, 255, 0) # 获取轮廓点 contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) print(99, len(contours)) # 找到最内层的元素, 这里是2是因为图像总共有三层 cnt = contours[2] # 拟合一条线 rows, cols = img.shape[:2] [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', img) cv.waitKey(0)
上边完整代码
点击查看代码
import cv2 as cv import numpy as np img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle1.jpg') imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) ret, thresh = cv.threshold(imgray, 127, 255, 0) # 获取轮廓点 contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) print(99, len(contours)) # 找到最内层的元素, 这里是2是因为图像总共有三层 cnt = contours[2] # 标记选中的区域 # res1 = cv.drawContours(img, cnt, -1, (0, 255, 0), 3) # 计算矩 M = cv.moments(cnt) # 计算质心 cx = int(M['m10'] / M['m00']) cy = int(M['m01'] / M['m00']) # 画出质心 cv.circle(img, (cx, cy), 5, (255, 0, 0), -1) # 计算轮廓面积 area = cv.contourArea(cnt) print(111, area, M['m00']) # 计算轮廓周长 perimeter = cv.arcLength(cnt, True) print(222, perimeter) # 计算轮廓近似 epsilon=弧长的5%的近似曲线 epsilon = 0.01 * cv.arcLength(cnt, True) approx = cv.approxPolyDP(cnt, epsilon, True) res3 = cv.drawContours(img, [approx], -1, (0, 0, 255), 3) # 凸包 hull = cv.convexHull(cnt) res4 = cv.drawContours(img, [hull], -1, (0, 0, 0), 3) # 检查凸性 k = cv.isContourConvex(cnt) print(333, k) # 直边矩形 x, y, w, h = cv.boundingRect(cnt) cv.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2) # 旋转矩形 rect = cv.minAreaRect(cnt) box = cv.boxPoints(rect) box = np.int0(box) cv.drawContours(img, [box], 0, (0, 0, 255), 2) # 最小外接圆 (x, y), radius = cv.minEnclosingCircle(cnt) center = (int(x), int(y)) radius = int(radius) cv.circle(img, center, radius, (0, 255, 0), 2) # 拟合椭圆 ellipse = cv.fitEllipse(cnt) cv.ellipse(img, ellipse, (0, 255, 0), 2) # 拟合一条线 rows, cols = img.shape[:2] [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', img) cv.waitKey(0)
这篇关于opencv-python 4.9.2. 轮廓特征的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-24Python编程基础:变量与数据类型
- 2024-12-23使用python部署一个usdt合约,部署自己的usdt稳定币
- 2024-12-20Python编程入门指南
- 2024-12-20Python编程基础与进阶
- 2024-12-19Python基础编程教程
- 2024-12-19python 文件的后缀名是什么 怎么运行一个python文件?-icode9专业技术文章分享
- 2024-12-19使用python 把docx转为pdf文件有哪些方法?-icode9专业技术文章分享
- 2024-12-19python怎么更换换pip的源镜像?-icode9专业技术文章分享
- 2024-12-19Python资料:新手入门的全面指南
- 2024-12-19Python股票自动化交易实战入门教程