别人没那么重要,我也没那么重要,好好活着,把能做的小事做好,够不到的东西就放弃,承认就好。做一个心情好能睡着的人,你所有事情都会在正轨上。

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日

------------------------------------------------------------------------------------------------------------*/

posted @ 2023-08-23 10:57  一路狂奔的乌龟  阅读(250)  评论(0)    收藏  举报
返回顶部