网站菜单

OpenCV学习笔记(7)——图像轮廓

什么是轮廓?

  • 边缘检测能够检测出边缘,但是边缘是不连续的。
  • 将边缘连接为一个整体,构成轮廓。

如何寻找轮廓?

  • 寻找轮廓的操作一般用于二值化图,所以通常会使用阈值分割或Canny边缘检测先得到二值图。
  • 查找轮廓需要更改原始图像。因此通常使用原始图像的副本进行操作。
  • 在OpenCV中,是从黑色背景中查找白色图像。因此对象必须是白色的,背景必须是黑色的。

1.1 寻找轮廓

#binary, contours, hierarchy = cv2.findContours(img1, mode, method)
#contours:轮廓
#hierarchy;图像的拓扑信息(轮廓层次)
#mode:轮廓检索模式
#method:轮廓的近似方法

binary, contours, hierarchy = cv2.findContours(binary_img1, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

mode:

  • cv2.RETR_EXTERNAL:只检测外轮廓
  • cv2.RETR_LIST:检测的轮廓不建立等级关系
  • cv2.RETR_CCOMP:建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果孔内还有一个连通物体,这个物体的边界也在顶层。
  • cv2.RETR_TREE:建立一个等级树结构的轮廓

method:

  • cv2.CHAIN_APPROX_NONE:储存所有轮廓点,相邻的两个点的像素位置差不超过1。max(abs(x1 – x2), abs(y2 – y1)) == 1
  • cv2.CHAIN_APPROX_SIMPLE:压缩水平方向,垂直方向,对角线方向的像素。只保留该方向的终点坐标,例如一个矩形轮廓只需要4个点来保存轮廓信息。
  • cv2.CHAIN_APPROX_TC89_L1:使用teh_Chinl chain近似算法。
  • cv2.CHAIN_APPROX_TC89_KCOS:使用teh_Chinl chain近似算法。

1.2 绘制轮廓

#img2 = cv2.drawContours(img1, contours, contourldx, color[, thickness])
#contours:需要绘制的边缘数组
#contourldx:需要绘制的边缘索引(索引序号,从0开始),如果全部绘制则为-1
#color:绘制的颜色,为BGR格式的Scalar。如(255,255,255)
#thicknedd:可选,绘制的密度,即描绘轮廓时所用到的画笔粗细

img2 = cv2.drawContours(img1, contours, -1, (0, 0, 255), 1)
https://zhuanlan.zhihu.com/p/61328775

图中总共有8条轮廓,2和2a分别表示外层和里层的轮廓,3和3a也是一样。从图中看得出来:

  • 轮廓0/1/2是最外层的轮廓,我们可以说它们处于同一轮廓等级:0级
  • 轮廓2a是轮廓2的子轮廓,反过来说2是2a的父轮廓,轮廓2a算一个等级:1级
  • 同样3是2a的子轮廓,轮廓3处于一个等级:2级
  • 类似的,3a是3的子轮廓,等等…………

1.3 完整流程如下:

#第一步,BGR转灰度图
gray_img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)

#第二部,灰度图转二值图
#ret, binary_img1 = cv2.threshold(gray_img1, 127, 255, cv2.THRESH_BINARY)
#*上文链接中的转二值方法,效果更好
ret, binary_img1= cv2.threshold(gray_img1, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

#第三步,获得轮廓
binary, contours, hierarchy = cv2.findContours(binary_img1, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

#第四步,绘制轮廓
# *保留原始图像,在副本上绘制轮廓
img1_copy = img1.copy()
#绘制轮廓
img2 = cv2.drawContours(img1_copy , contours, -1, (0, 255, 0), 1)

轮廓的其他属性:

#轮廓面积
area = cv2.contourArea(contours[0])

#轮廓周常
perimeter = cv2.arcLength(contours[0], True)

#画第[0]轮廓的最小外接矩形
rect = cv2.minAreaRect(contours[0])
box = np.int0(cv2.boxPoints(rect))#把x取整,如266.66变成266
img2 = cv2.drawContours(img1_copy , [box], 0, (0, 255, 0), 2)
img2 = cv2.drawContours(img2 , contours, 100, (0, 255, 0), 1)

#画第[0]轮廓的最小外接圆
(x, y), radius = cv2.minEnclosingCircle(contours[1])
(x, y, radius) = np.int0((x, y, radius))
img2 = cv2.circle(img1_copy, (x,y), radius, (0, 0, 255), 2)
img2 = cv2.drawContours(img2 , contours, 100, (0, 255, 0), 1)

最小外接圆样例:

显示评论 (0)

文章评论

相关推荐

Yolov5_Seg输出解析

通过矩阵乘法(在代码中称为“matmul”)来计算分割掩码的原因,主要与实例分割网络(例如 YOLOv5 Segmentation)的实现方式有关。这种方法实际上是一种高效的特征图与目标分割系数组合的…

Ubuntu交叉编译Python

在 Ubuntu 上交叉编译 Python 的流程通常用于为不同平台生成可执行文件(如 ARM、MIPS 等)。以下是一般的操作步骤: 1. 安装必要的依赖工具 首先,确保已经安装了编译所需的工具和依…