PythonOpenCV-边缘和轮廓-图像轮廓
0. 简介
图像轮廓是指由位于边缘、连续的、具有相同颜色和强度的点构成的曲线,它可用于形状分析以及对象检测和识别。
1. 查找轮廓
cv2.findContours()函数用于从二值图像中查找图像轮廓,其基本格式如下:
contours, hierarchy = cv2.findContours(image, mode, method[, offset])
参数说明:
contours:返回的轮廓
hierarchy:返回的轮廓的层次结构
image:原图像
mode:轮廓的检索模式
method:轮廓的近似方法
offset:每个轮廓点移动的可选偏移量
代码示例:
import cv2 as cv import numpy as np img_src = cv.imread('../Image/bee.png') cv.imshow('src', img_src) gray = cv.cvtColor(img_src, cv.COLOR_BGR2GRAY) # 转灰度图 ret, thresh = cv.threshold(gray, 100, 255, cv.THRESH_BINARY) # 二值化 c, h = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) # 查找轮廓 print('轮廓:', c) print('轮廓类型:', type(c)) print('轮廓个数:', len(c)) print('层次:', h) for n in (range(3)): img_bg = np.zeros(img_src.shape, np.uint8) + 255 # 与原图大小一致的白色图 cv.polylines(img_bg, [c[n]], True, (255, 0, 0), 2) # 绘制轮廓 cv.imshow('%s' % n, img_bg) # 显示轮廓 cv.waitKey(0) cv.destroyAllWindows()
运行结果:
输出结果:
轮廓: (array([[[ 0, 0]], [[ 0, 655]], [[1074, 655]], [[1074, 0]]], dtype=int32), array([[[136, 12]], [[138, 12]], [[139, 13]], ..., [[133, 17]], [[134, 16]], [[134, 14]]], dtype=int32), array([[[636, 528]], ..., [[595, 41]], [[589, 41]], [[588, 40]]], dtype=int32)) 轮廓类型: <class 'tuple'> 轮廓个数: 17 层次: [[[-1 -1 1 -1] [-1 -1 2 0] [ 3 -1 -1 1] [ 4 2 -1 1] [ 5 3 -1 1] [ 6 4 -1 1] [ 7 5 -1 1] [ 8 6 -1 1] [ 9 7 -1 1] [10 8 -1 1] [11 9 -1 1] [16 10 12 1] [14 -1 13 11] [-1 -1 -1 12] [15 12 -1 11] [-1 14 -1 11] [-1 11 -1 1]]]
1-1. cv2.findContours()函数返回结果
cv2.findContours()函数返回一个 list 对象,保存了轮廓数组。
轮廓数组的每个元素都是一个表示轮廓的 array 对象;返回的轮廓层次是一个 numpy.ndarray 对象。
1-2. 轮廓的层次
根据轮廓的嵌套关系,可将轮廓之间的层次关系分为父级和子级,外部的轮廓为父级,内部8轮廓为子级。
cv2.findContours()函数返回的轮廓层次中,numpy.ndarray 对象中的每个元素表示的层次系格式为:[下一个轮廓 前一个轮廓 第一个子级轮廓 父级轮廓]。例如,[-1 0 2 -1]中,-1表示存在对应的轮廓,前一个轮廓在轮廓数组中的序号为 0,第一个子级轮廓在轮廓数组中的序号为2。
1-3. 轮廓的检索模式
cv2.findContours()函数中的 mode 参数用于设置轮廓的检索模式,不同检索模式下函数返回的轮廓有所不同。mode 参数可设置为下列常数:
- cv2.RETR_LIST:仅检索所有轮廓,不创建任何父子关系
- cv2.RETR_EXTERNAL:仅检索所有的外部轮廓,不包含子级轮廓
- cv2.RETR_CCOMP:检索所有轮廓并将它们排列为 2级层次结构,所有的外部轮廓为1级,所有的子级轮廓为 2 级
- cv2.RETR_TREE:检索所有轮廓并创建完整的层次列表,如父级、子级、孙子级等
1-4. 轮廓的近似方法
cv2findContours()函数中的 method 参数用于设置轮廊的近似方法,它用于决定如何确定轮廓包含的像素点。method 参数可设置为下列常数:
- cv2.CHAIN_APPROX_NONE:存储所有轮廓点,轮廓的任意两个相邻点是水平、垂直或对角线上的邻居
- cv2.CHAIN_APPROX_SIMPLE:只保存水平、垂直和对角线的端点
- cv2.CHAIN APPROX_TC89_L1:应用 Teh-Chin 链逼近算法中的一种确定轮廓点
2. 绘制轮廓
cv2.drawContours0函数用于绘制轮廓,其基本格式如下:
image = cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]])
参数说明:
image:在其中绘制轮廓的图像
contours:要绘制的轮廓
contourldx:要绘制的轮廓的索引,大于或等于0 时绘制对应的轮廓,负数(通常为-1)表示绘制所有轮廓
color:轮廓颜色,颜色为 BGR 格式
thickness:可选参数,表示绘制轮廓时画笔的粗细
lineType:可选参数,表示绘制轮廓时使用的线型
hierarchy:可选参数,对应 cv2.findContours()函数返回的轮廓层次
maxLevel:可选参数,表示可绘制的最大轮廓层次深度
offset:可选参数,表示绘制轮廓的偏移位置
代码示例:
import cv2 as cv import numpy as np img_src = cv.imread('../Image/bee.png') cv.imshow('src', img_src) gray = cv.cvtColor(img_src, cv.COLOR_BGR2GRAY) # 转灰度图 ret, thresh = cv.threshold(gray, 100, 255, cv.THRESH_BINARY) # 二值化 c, h = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) # 查找轮廓 img_bg = np.zeros(img_src.shape, np.uint8) + 255 # 与原图大小一致的白色图 img_bg = cv.drawContours(img_bg, c, -1, (0, 0, 255), 2) # 绘制轮廓 cv.imshow('Contours', img_bg) # 显示轮廓 cv.waitKey(0) cv.destroyAllWindows()
运行结果:
3. 轮廓的特征
3-1. 轮廓的矩
轮廓的矩包含了轮廓的各种几何特征,如面积、位置、角度、形状等。
cv2.moments()函数用于返回轮廓的矩,其基本格式如下:
ret = cv2.moments(array[, binaryImage])
参数说明:image:在其中绘制轮廓的图像
ret:返回的轮廓矩,是一个字典对象。大多数矩的含义比较抽象,但其中的零阶矩(m00)表示轮廓的面积
array:表示轮廓的数组
binarylmage:值为 True 时,会将 array 对象中的所有非0值设置为 1
代码示例:
import cv2 as cv import numpy as np img_src = cv.imread('../Image/Contours.png') cv.imshow('src', img_src) gray = cv.cvtColor(img_src, cv.COLOR_BGR2GRAY) # 转灰度图 ret, thresh = cv.threshold(gray, 125, 255, cv.THRESH_BINARY) # 二值化 c, h = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) # 查找轮廓 img_bg = np.zeros(img_src.shape, np.uint8) + 255 # 与原图大小一致的白色图 img_bg = cv.drawContours(img_bg, c, -1, (0, 0, 255), 2) # 绘制轮廓 cv.imshow('Contours', img_bg) # 显示轮廓 for n in range(len(c)): m = cv.moments(c[n]) print('轮廓%s的矩:' % n, m) # 输出轮廓的矩 print('轮廓%s的面积:' % n, m['m00']) # 输出轮廓的面积 cv.waitKey(0) cv.destroyAllWindows()
运行结果:
输出结果:
轮廓0的矩: {'m00': 11319.0, 'm10': 8806329.5, 'm01': 3122173.0, 'm20': 6857653171.333333, 'm11': 2429083459.4166665, 'm02': 881146490.8333333, 'm30': 5345012668709.75, 'm21': 1891543683521.0833, 'm12': 685539297467.9166, 'm03': 254139291852.5, 'mu20': 6214063.411232948, 'mu11': -7820.201983451843, 'mu02': 19942829.56210792, 'mu30': -106566.1318359375, 'mu21': -22871859.291429996, 'mu12': 159381.50554847717, 'mu03': 86662580.53155518, 'nu20': 0.048501990346617556, 'nu11': -6.103821863554556e-05, 'nu02': 0.1556577174859694, 'nu30': -7.818060954342028e-06, 'nu21': -0.001677958906820639, 'nu12': 1.1692779909578997e-05, 'nu03': 0.006357867414192727} 轮廓0的面积: 11319.0 轮廓1的矩: {'m00': 80304.0, 'm10': 24251808.0, 'm01': 21722232.0, 'm20': 8079546048.0, 'm11': 6560114064.0, 'm02': 6258117488.0, 'm30': 2896344925824.0, 'm21': 2185517205984.0, 'm12': 1889951481376.0, 'm03': 1899620049516.0, 'mu20': 755500032.0, 'mu11': 0.0, 'mu02': 382253732.0, 'mu30': 0.0, 'mu21': 0.0, 'mu12': 0.0, 'mu03': 0.0, 'nu20': 0.11715481171548117, 'nu11': 0.0, 'nu02': 0.05927579365079365, 'nu30': 0.0, 'nu21': 0.0, 'nu12': 0.0, 'nu03': 0.0} 轮廓1的面积: 80304.0 轮廓2的矩: {'m00': 11036.0, 'm10': 3351527.0, 'm01': 3035172.0, 'm20': 1028652517.6666666, 'm11': 921752148.0, 'm02': 844253418.6666666, 'm30': 318965057547.5, 'm21': 282904630783.6667, 'm12': 256392781161.83334, 'm03': 237419310936.0, 'mu20': 10826019.684698582, 'mu11': -380.7825299501419, 'mu02': 9506311.962788343, 'mu30': -2329289.162536621, 'mu21': 66906.76282787323, 'mu12': 1351656.3339567184, 'mu03': -127359.28674316406, 'nu20': 0.08888846956484847, 'nu11': -3.126465433287411e-06, 'nu02': 0.07805283439236543, 'nu30': -0.00018205146433214188, 'nu21': 5.229266654584428e-06, 'nu12': 0.00010564210696908974, 'nu03': -9.954086002203531e-06} 轮廓2的面积: 11036.0
3-2. 轮廓的面积
cv2.contourArea()函数用于返回轮廓面积,其基本格式如下:
ret = cv2.contourArea(contour[, oriented])
参数说明:
ret:返回的面积
contour:轮廓
oriented:可选参数。其参数值为 True 时,返回值的正与负表示轮廓是顺时针还是逆时针;参数值为 False(默认值)时,函数返回值为绝对值。
代码示例:
import cv2 as cv import numpy as np img_src = cv.imread('../Image/Contours.png') cv.imshow('src', img_src) gray = cv.cvtColor(img_src, cv.COLOR_BGR2GRAY) # 转灰度图 ret, thresh = cv.threshold(gray, 125, 255, cv.THRESH_BINARY) # 二值化 c, h = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) # 查找轮廓 for n in range(len(c)): m = cv.contourArea(c[n]) # 计算轮廓面积 print('轮廓%s的面积:' % n, m) # 输出轮廓面积 cv.waitKey(0) cv.destroyAllWindows()
输出结果:
轮廓0的面积: 11319.0 轮廓1的面积: 80304.0 轮廓2的面积: 11036.0
3-3. 轮廓的长度
cv2.arcLength()函数用于返回轮廓的长度,其基本格式如下:
ret = cv2.arcLength(contour, closed)
参数说明:
ret:返回的长度
contour:轮廓
closed:bool值,表示轮廓是否封闭
代码示例:
import cv2 as cv import numpy as np img_src = cv.imread('../Image/Contours.png') # cv.imshow('src', img_src) gray = cv.cvtColor(img_src, cv.COLOR_BGR2GRAY) # 转灰度图 ret, thresh = cv.threshold(gray, 125, 255, cv.THRESH_BINARY) # 二值化 c, h = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) # 查找轮廓 for n in range(len(c)): m = cv.arcLength(c[n], True) # 计算轮廓长度 print('轮廓%s的长度:' % n, m) # 输出轮廓长度 cv.waitKey(0) cv.destroyAllWindows()
输出结果:
轮廓0的长度: 518.6761825084686 轮廓1的长度: 1150.0 轮廓2的长度: 421.97979640960693
3-4. 轮廓的近似多边形
cv2.approxPolyDP()函数用于返回轮廓的近似多边形,其基本格式如下:
ret = cv2.approxPolyDP(contour, epsilon, closed)
参数说明:
ret:返回的近似多边形
contour:轮廓
epsilon:精度,表示近似多边形接近轮廓的最大距离
closed:bool值,表示轮廓是否封闭
代码示例:
import cv2 as cv import numpy as np img_src = cv.imread('../Image/Contours.png') cv.imshow('src', img_src) gray = cv.cvtColor(img_src, cv.COLOR_BGR2GRAY) # 转灰度图 ret, thresh = cv.threshold(gray, 125, 255, cv.THRESH_BINARY) # 二值化 c, h = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) # 查找轮廓 ep = [0.1, 0.05, 0.01] arc1 = cv.arcLength(c[0], True) # 计算轮廓长度 print(arc1) img_bg = np.zeros(img_src.shape, np.uint8) + 255 # 与原图大小一致的白色图 img_bg = cv.drawContours(img_bg, c, -1, (0, 0, 255), 2) # 绘制轮廓 for n in range(3): eps = ep[n] * arc1 img_bg2 = img_bg.copy() app = cv.approxPolyDP(c[0], eps, True) # 获得近似多边形 img_bg2 = cv.drawContours(img_bg2, [app], -1, (255, 0, 0), 2) # 绘制近似轮廓 cv.imshow('appro %.2f' % ep[n], img_bg2) # 显示近似轮廓 cv.waitKey(0) cv.destroyAllWindows()
运行结果:
3-5. 轮廓的凸包
cv2.convexHull()函数用于返回轮廓的凸包,其基本格式如下:
hull = cv2.convexHull(contour[, clockwise[, returnPoints]])
参数说明:
ret:返回的凸包,是一个 numpy.ndarray 对象,包含了凸包的关键点
contour:轮廓
clockwise:方向标记,为 True 时,凸包为顺时针方向; 为 False(默认)时,凸包为逆时针方向
returnPoints:为True(默认值)时,返回的 hull 中包含的是凸包关键点的坐标;为 False时,返回的是凸包关键点在轮廓中的索引
代码示例:
import cv2 as cv import numpy as np img_src = cv.imread('../Image/Contours-Hull.png') cv.imshow('src', img_src) gray = cv.cvtColor(img_src, cv.COLOR_BGR2GRAY) # 转灰度图 ret, thresh = cv.threshold(gray, 125, 255, cv.THRESH_BINARY) # 二值化 c, h = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) # 查找轮廓 img_bg = np.zeros(img_src.shape, np.uint8) + 255 # 与原图大小一致的白色图 img_bg = cv.drawContours(img_bg, c, -1, (0, 0, 255), 2) # 绘制轮廓 hull1 = cv.convexHull(c[0]) # 计算凸包 print('returnPoints = True时的凸包:\n', hull1) hull2 = cv.convexHull(c[0], returnPoints=False) print('returnPoints = False时的凸包:\n', hull2) cv.polylines(img_bg, [hull1], True, (255, 0, 0), 2) # 绘制凸包 cv.imshow('Convex Hull', img_bg) # 显示凸包 cv.waitKey(0) cv.destroyAllWindows()
运行结果:
输出结果:
returnPoints = True时的凸包: [[[465 132]] [[465 276]] [[308 350]] [[150 276]] [[150 132]] [[308 58]]] returnPoints = False时的凸包: [[282] [193] [157] [123] [ 34] [ 0]]
3-6. 轮廓的直边界矩形
轮廓的直边界矩形是指可容纳轮廓的矩形,且矩形的两条边必须是水平的。直边界矩形不一定是面积最小的边界矩形。
cv2.boundingRect()函数用于返回轮廓的直边界矩形,其基本格式如下:
ret = cv2.boundingRect(contour)
参数说明:
ret:返回的直边界矩形,它是一个四元组,其格式为(矩形左上角x坐标, 矩形左上角 y坐标, 矩形的宽度, 矩形的高度)
contour:用于计算直边界矩形的轮廓
代码示例:
import cv2 as cv import numpy as np img_src = cv.imread('../Image/Contours-Bounding.png') cv.imshow('src', img_src) gray = cv.cvtColor(img_src, cv.COLOR_BGR2GRAY) # 转灰度图 ret, thresh = cv.threshold(gray, 125, 255, cv.THRESH_BINARY) # 二值化 c, h = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) # 查找轮廓 img_bg = np.zeros(img_src.shape, np.uint8) + 255 # 与原图大小一致的白色图 img_bg = cv.drawContours(img_bg, c, -1, (0, 0, 255), 2) # 绘制轮廓 ret = cv.boundingRect(c[0]) # 计算直边界矩形 print('直边界矩形:\n', ret) pt1 = (ret[0], ret[1]) pt2 = (ret[0] + ret[2], ret[1] + ret[3]) cv.rectangle(img_bg, pt1, pt2, (255, 0, 0), 2) # 绘制直边界矩形 cv.imshow('Rectangle', img_bg) # 显示直边界矩形 cv.waitKey(0) cv.destroyAllWindows()
运行结果:
输出结果:
直边界矩形: (439, 295, 137, 105)
3-7. 轮廓的旋转矩形
轮廓的旋转矩形是指可容纳轮廓的面积最小的矩形。
cv2.minAreaRect()函数用于返回轮廓的旋转矩形,其基本格式如下:
box = cv2.minAreaRect(contour)
参数说明:
box:返回的旋转矩形,它是一个三元组,其格式为((矩形中心点x坐标, 矩形中心点y坐标), (矩形的宽度, 矩形的高度), 矩形的旋转角度)
contour:用于计算矩形的轮廓
cv2.minAreaRect()函数的返回结果不能直接用于绘制旋转矩形,可用 cv2.boxPoints()函数将其转换为矩形的顶点坐标,其基本格式如下:
points = cv2.boxPoints(box)
参数说明:
points:返回的矩形顶点坐标,坐标数据为浮点数
box:cv2.minAreaRect()函数返回的矩形数据
代码示例:
import cv2 as cv import numpy as np img_src = cv.imread('../Image/Contours-Bounding.png') cv.imshow('src', img_src) gray = cv.cvtColor(img_src, cv.COLOR_BGR2GRAY) # 转灰度图 ret, thresh = cv.threshold(gray, 125, 255, cv.THRESH_BINARY) # 二值化 c, h = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) # 查找轮廓 img_bg = np.zeros(img_src.shape, np.uint8) + 255 # 与原图大小一致的白色图 img_bg = cv.drawContours(img_bg, c, -1, (0, 0, 255), 2) # 绘制轮廓 ret = cv.minAreaRect(c[0]) # 计算最小矩形 rect = cv.boxPoints(ret) # 计算矩形顶点 rect = np.intp(rect) # 转换为整型 cv.drawContours(img_bg, [rect], 0, (255, 0, 0), 2) # 绘制旋转矩形 cv.imshow('Rectangle', img_bg) # 显示旋转矩形 cv.waitKey(0) cv.destroyAllWindows()
运行结果:
3-8. 轮廓的最小外包圆
cv2.minEnclosingCircle()函数用于返回可容纳轮廓的最小外包圆,其基本格式如下:
center, radius = cv2.minEnclosingCircle(contour)
参数说明:
center 为圆心
radius 为半径
contour 为用于计算最小外包圆的轮廓
代码示例:
import cv2 as cv import numpy as np img_src = cv.imread('../Image/Contours-Bounding.png') cv.imshow('src', img_src) gray = cv.cvtColor(img_src, cv.COLOR_BGR2GRAY) # 转灰度图 ret, thresh = cv.threshold(gray, 125, 255, cv.THRESH_BINARY) # 二值化 c, h = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) # 查找轮廓 img_bg = np.zeros(img_src.shape, np.uint8) + 255 # 与原图大小一致的白色图 img_bg = cv.drawContours(img_bg, c, -1, (0, 0, 255), 2) # 绘制轮廓 (x, y), radius = cv.minEnclosingCircle(c[0]) # 计算最小外包圆 center = (int(x), int(y)) radius = int(radius) cv.circle(img_bg, center, radius, (255, 0, 0), 2) # 绘制最小外包圆 cv.imshow('Circle', img_bg) # 显示最小外包圆 cv.waitKey(0) cv.destroyAllWindows()
运行结果:
3-9. 轮廓的拟合椭圆
cv2.fitEllipse()函数用于返回轮廓的拟合椭圆,其基本格式如下:
ellipse = cv2.fitEllipse(contour)
参数说明:
ellipse:返回的圆
contour:用于计算拟合圆的轮廓
代码示例:
import cv2 as cv import numpy as np img_src = cv.imread('../Image/Contours-Bounding.png') cv.imshow('src', img_src) gray = cv.cvtColor(img_src, cv.COLOR_BGR2GRAY) # 转灰度图 ret, thresh = cv.threshold(gray, 125, 255, cv.THRESH_BINARY) # 二值化 c, h = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) # 查找轮廓 img_bg = np.zeros(img_src.shape, np.uint8) + 255 # 与原图大小一致的白色图 img_bg = cv.drawContours(img_bg, c, -1, (0, 0, 255), 2) # 绘制轮廓 ellipse = cv.fitEllipse(c[0]) # 计算拟合椭圆 cv.ellipse(img_bg, ellipse, (255, 0, 0), 2) # 绘制拟合椭圆 cv.imshow('ellipse', img_bg) # 显示拟合椭圆 cv.waitKey(0) cv.destroyAllWindows()
运行结果:
3-10. 轮廓的拟合直线
cv2.fitLine()函数用于返回轮廓的拟合直线,其基本格式如下:
line = cv2.fitLine(contour, distType, param, reps, aeps)
参数说明:line:返回的拟合直线
contour:用于计算拟合直线的轮廓
distType:距离类型参数,决定如何计算拟合直线,可设置为下列常量:
- cv2.DIST_USER:用户自定义距离。
- cv2.DIST_L1:用2个点的坐标计算距离,公式为|x1 - x2| + |y1 - y2|
- cv2.DIST_L2:欧氏距离( 两点间的直线距离 )
- cv2.DIST_C:用2个点的坐标计算距离,公式为 max(|x1 - x2|, |y1 - y2|)
- cv2.DIST_L12: 用1个点的坐标计算距离,公式为 2(sqrt(1 + x * x / 2) - 1)
- cv2.DIST_FAIR:用1个点的坐标计算距离,公式为 c^2(|x| // c - log(1 + |x| / c)), c =1.3998
- cv2.DIST_WELSCH:用1 个点的坐标计算距离,公式为 c^2 / 2(1 - exp(-(x / c)^2), c=2.9846
- cv2.DIST_HUBER:用 1个点的坐标计算距离,公式为|x| < c ? x^2 / 2 : c(|x| - c / 2), c=1.345
param:距离参数,与距离类型参数有关;其设置为 0时,函数将自动选择最优值
reps:计算拟合直线需要的径向精度,通常设置为 0.01。ez -le2
aeps:计算拟合直线需要的角度精度,通常设置为 0.01
代码示例:
import cv2 as cv import numpy as np img_src = cv.imread('../Image/Contours-Bounding.png') cv.imshow('src', img_src) gray = cv.cvtColor(img_src, cv.COLOR_BGR2GRAY) # 转灰度图 ret, thresh = cv.threshold(gray, 125, 255, cv.THRESH_BINARY) # 二值化 c, h = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) # 查找轮廓 img_bg = np.zeros(img_src.shape, np.uint8) + 255 # 与原图大小一致的白色图 img_bg = cv.drawContours(img_bg, c, -1, (0, 0, 255), 2) # 绘制轮廓 rows, cols = img_src.shape[:2] [vx, vy, x, y] = cv.fitLine(c[0], cv.DIST_L12, 0, 0.01, 0.01) # 计算拟合直线 left_y = int((-x * vy/vx) + y) right_y = int(((cols - x) * vy/vx) + y) cv.line(img_bg, (cols - 1, right_y), (0, left_y), (255, 0, 0), 2) # 绘制拟合直线 cv.imshow('fitLine', img_bg) # 显示拟合直线 cv.waitKey(0) cv.destroyAllWindows()
运行结果:
3-11. 轮廓的最小外包三角形
cv2.minEnclosingTriangle()函数用于返回可容纳轮廓的最小外包三角形,其基本格式如下:
retval, triangle = cv2.minEnclosingTriangle(contour)
参数说明:
retval:最小外包三角形的面积
triangle:最小外包三角形
contour:用于计算最小外包三角形的轮廓
代码示例:
import cv2 as cv import numpy as np img_src = cv.imread('../Image/Contours-Bounding.png') cv.imshow('src', img_src) gray = cv.cvtColor(img_src, cv.COLOR_BGR2GRAY) # 转灰度图 ret, thresh = cv.threshold(gray, 125, 255, cv.THRESH_BINARY) # 二值化 c, h = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) # 查找轮廓 img_bg = np.zeros(img_src.shape, np.uint8) + 255 # 与原图大小一致的白色图 img_bg = cv.drawContours(img_bg, c, -1, (0, 0, 255), 2) # 绘制轮廓 retval, triangle = cv.minEnclosingTriangle(c[0]) # 计算最小外包三角形 triangle = np.intp(triangle) # 可以写成:triangle = np.int0(triangle) cv.polylines(img_bg, [triangle], True, (255, 0, 0), 2) # 绘制最小外包三角形 cv.imshow('Triangle', img_bg) # 显示拟合椭圆 cv.waitKey(0) cv.destroyAllWindows()
运行结果:
注:以上代码在实现上可能会有偏差,与预想不大一致,可以通过参数调整。
/*-------------------------------------------------------------------------------------------------------
笔者说明:
该笔记来源于本人学习Python + OpenCv时的资料,
分享出来只是为了供大家学习,并且为了自己以后想要用的时候方便寻找。
时间:2023年8月23日
------------------------------------------------------------------------------------------------------------*/