当前位置:   article > 正文

使用opencv实现图像中几何图形检测_opencv几何图形

opencv几何图形

1 几何图形检测介绍

1.1 轮廓(contours)

什么是轮廓,简单说轮廓就是一些列点相连组成形状、它们拥有同样的颜色、轮廓发现在图像的对象分析、对象检测等方面是非常有用的工具,在OpenCV
中使用轮廓发现相关函数时候要求输入图像是二值图像,这样便于轮廓提取、边缘提取等操作。轮廓发现的函数与参数解释如下:

函数原型:

findContours(image, mode, method, contours=None, hierarchy=None, offset=None)

参数:

  • image输入/输出的二值图像
  • mode 迒回轮廓的结构、可以是List、Tree、External
  • method 轮廓点的编码方式,基本是基于链式编码
  • contours 迒回的轮廓集合
  • hieracrchy 迒回的轮廓层次关系
  • offset 点是否有位移

1.2 多边形逼近

多边形逼近,是通过对轮廓外形无限逼近,删除非关键点、得到轮廓的关键点,不断逼近轮廓真实形状的方法,OpenCV中多边形逼近的函数与参数解释如下:

函数原型:

approxPolyDP(curve, epsilon, closed, approxCurve=None)

参数:

  • curve 表示输入的轮廓点集合
  • epsilon 表示逼近曲率,越小表示相似逼近越厉害
  • close 是否闭合

1.3 几何距计算

图像几何距是图像的几何特征,高阶几何距中心化之后具有特征不变性,可以产生Hu距输出,用于形状匹配等操作,这里我们通过计算一阶几何距得到指定轮廓的中心位置,计算几何距的函数与参数解释如下:

函数原型:

moments(array, binaryImage=None)

参数:

  • array表示指定输入轮廓
  • binaryImage默认为None

2 基于opencv实现几何图形检测

整个代码实现分为如下几步完成

  • 加载图像,
  • 图像二值化
  • 轮廓发现
  • 几何形状识别
  • 测量周长、面积、计算中心
  • 颜色提取

2.1 加载图像并进行二值化处理

的二值化,就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的只有黑和白的视觉效果。

一幅图像包括目标物体、背景还有噪声,要想从多值的数字图像中直接提取出目标物体,常用的方法就是设定一个阈值T,用T将图像的数据分成两部分:大于T的像素群和小于T的像素群。这是研究灰度变换的最特殊的方法,称为图像的二值化(Binarization)。

函数原型:

def threshold(src: Any,thresh: Any,maxval: Any,type: Any,dst: Any = None) -> None

src:源图像,可以为8位的灰度图,也可以为32位的彩色图像。(两者由区别)

dst:输出图像

thresh:阈值

maxval:dst图像中最大值

type:阈值类型,可以具体类型如下:

           enum ThresholdTypes {THRESH_BINARY     = 0,            //黑白

                                                 THRESH_BINARY_INV = 1,        //黑白反转

                                                 THRESH_TRUNC      = 2,        //得到图像多像素值

                                                 THRESH_TOZERO     = 3,        //当前点值大于阈值时,不改

                                                                                                    变,否则设置为0

                                                 THRESH_TOZERO_INV = 4,        //当前点值大于阈值时,

                                                                                                    设置为0,否则不改变

                                                  THRESH_MASK       = 7,

                                                  THRESH_OTSU       = 8,        //自适应阈值

                                                  THRESH_TRIANGLE   = 16
             };

具体实现代码:

  1. frame = cv.imread("./data/jihe2.png")
  2. # 二值化图像
  3. gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
  4. ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU)
  5. cv.imshow("input image", frame)

2.2 轮廓检测与逼近

当需要对图像进行形状分析时,需要使用多边形逼近一个轮廓,使得顶点数目变少,算法原理比较简单,核心就是不断找多边形最远的点加入形成新的多边形,直到最短距离小于指定的精度。OpenCV里面用函数approxPolyDP()实现。approxPolyDP()用另一条顶点较少的曲线来逼近一条曲线或者一个多边形,这样两条曲线之间的距离小于或等于指定的精度。同时也有使闭合逼近曲线的选项(那就是说,起始点和终止点相同)。

findContours后的轮廓信息contours可能过于复杂不平滑,可以用approxPolyDP函数对该多边形曲线做适当近似,approxPolyDP 主要功能是把一个连续光滑曲线折线化,对图像轮廓点进行多边形拟合。

具体实现代码:

  1. contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
  2. for cnt in range(len(contours)):
  3. # 提取与绘制轮廓
  4. cv.drawContours(result, contours, cnt, (0, 255, 0), 2)
  5. # 轮廓逼近
  6. epsilon = 0.01 * cv.arcLength(contours[cnt], True)
  7. approx = cv.approxPolyDP(contours[cnt], epsilon, True)

2.3 几何形状判断

根据corners数量对形状进行判断。

  1. approx = cv.approxPolyDP(contours[cnt], epsilon, True)
  2. # 分析几何形状
  3. corners = len(approx)
  4. shape_type = ""
  5. if corners < 3:
  6. continue
  7. if corners == 3:
  8. count = self.shapes['triangle']
  9. count = count + 1
  10. self.shapes['triangle'] = count
  11. shape_type = "三角形"
  12. if corners == 4:
  13. count = self.shapes['rectangle']
  14. count = count + 1
  15. self.shapes['rectangle'] = count
  16. shape_type = "矩形"
  17. if corners >= 10:
  18. count = self.shapes['circles']
  19. count = count + 1
  20. self.shapes['circles'] = count
  21. shape_type = "圆形"
  22. if 4 < corners < 10:
  23. count = self.shapes['polygons']
  24. count = count + 1
  25. self.shapes['polygons'] = count
  26. shape_type = "多边形"

2.4 面积周长计算

  1. # 计算面积与周长
  2. p = cv.arcLength(contours[cnt], True)
  3. area = cv.contourArea(contours[cnt])
  4. print("周长: %.3f, 面积: %.3f 颜色: %s 形状: %s " % (p, area, color_str,

2.5 完整代码:

  1. import cv2 as cv
  2. import numpy as np
  3. class ShapeAnalysis:
  4. def __init__(self):
  5. self.shapes = {'triangle': 0, 'rectangle': 0, 'polygons': 0, 'circles': 0}
  6. def analysis(self, frame):
  7. h, w, ch = frame.shape
  8. result = np.zeros((h, w, ch), dtype=np.uint8)
  9. # 二值化图像
  10. print("start to detect lines...\n")
  11. gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
  12. ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU)
  13. cv.imshow("input image", frame)
  14. contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
  15. for cnt in range(len(contours)):
  16. # 提取与绘制轮廓
  17. cv.drawContours(result, contours, cnt, (0, 255, 0), 2)
  18. # 轮廓逼近
  19. epsilon = 0.01 * cv.arcLength(contours[cnt], True)
  20. approx = cv.approxPolyDP(contours[cnt], epsilon, True)
  21. # 分析几何形状
  22. corners = len(approx)
  23. shape_type = ""
  24. if corners < 3:
  25. continue
  26. if corners == 3:
  27. count = self.shapes['triangle']
  28. count = count + 1
  29. self.shapes['triangle'] = count
  30. shape_type = "三角形"
  31. if corners == 4:
  32. count = self.shapes['rectangle']
  33. count = count + 1
  34. self.shapes['rectangle'] = count
  35. shape_type = "矩形"
  36. if corners >= 10:
  37. count = self.shapes['circles']
  38. count = count + 1
  39. self.shapes['circles'] = count
  40. shape_type = "圆形"
  41. if 4 < corners < 10:
  42. count = self.shapes['polygons']
  43. count = count + 1
  44. self.shapes['polygons'] = count
  45. shape_type = "多边形"
  46. # 求解中心位置
  47. mm = cv.moments(contours[cnt])
  48. if mm['m00'] == 0:
  49. continue
  50. cx = int(mm['m10'] / mm['m00'])
  51. cy = int(mm['m01'] / mm['m00'])
  52. cv.circle(result, (cx, cy), 3, (0, 0, 255), -1)
  53. # 颜色分析
  54. color = frame[cy][cx]
  55. color_str = "(" + str(color[0]) + ", " + str(color[1]) + ", " + str(color[2]) + ")"
  56. # 计算面积与周长
  57. p = cv.arcLength(contours[cnt], True)
  58. area = cv.contourArea(contours[cnt])
  59. print("周长: %.3f, 面积: %.3f 颜色: %s 形状: %s " % (p, area, color_str, shape_type))
  60. cv.imshow("Analysis Result", result)
  61. print("triangle: ", self.shapes['triangle'])
  62. print("rectangle: ", self.shapes['rectangle'])
  63. print("polygons: ", self.shapes['polygons'])
  64. print("circles: ", self.shapes['circles'])
  65. return self.shapes
  66. if __name__ == "__main__":
  67. src = cv.imread("./data/jihe2.png")
  68. ld = ShapeAnalysis()
  69. ld.analysis(src)
  70. cv.waitKey(0)
  71. cv.destroyAllWindows()

原始图像:

运行结果显示:

  1. 周长: 553.973, 面积: 11687.500 颜色: (190, 146, 112) 形状: 矩形
  2. 周长: 479.556, 面积: 14743.500 颜色: (232, 162, 0) 形状: 矩形
  3. 周长: 543.144, 面积: 18333.500 颜色: (21, 0, 136) 形状: 多边形
  4. 周长: 341.421, 面积: 7593.000 颜色: (164, 73, 163) 形状: 多边形
  5. 周长: 761.796, 面积: 13221.500 颜色: (87, 122, 185) 形状: 圆形
  6. 周长: 594.257, 面积: 24703.500 颜色: (39, 127, 255) 形状: 圆形
  7. 周长: 592.000, 面积: 14508.000 颜色: (36, 28, 237) 形状: 矩形
  8. 周长: 432.291, 面积: 11939.500 颜色: (204, 72, 63) 形状: 多边形
  9. 周长: 280.451, 面积: 4917.000 颜色: (190, 146, 112) 形状: 多边形
  10. 周长: 531.588, 面积: 10587.000 颜色: (164, 73, 163) 形状: 矩形
  11. 周长: 405.262, 面积: 4172.500 颜色: (76, 177, 34) 形状: 圆形
  12. 周长: 370.191, 面积: 9746.000 颜色: (232, 162, 0) 形状: 圆形
  13. 周长: 486.000, 面积: 14762.000 颜色: (232, 162, 0) 形状: 矩形
  14. triangle: 0
  15. rectangle: 5
  16. polygons: 4
  17. circles: 4

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/264058
推荐阅读
相关标签
  

闽ICP备14008679号