【菜菜的CV进阶之路-数据预处理-基础】Python轮廓检测、找出轮廓中心点、绘制最小矩形框并裁剪

简介: 【菜菜的CV进阶之路-数据预处理-基础】Python轮廓检测、找出轮廓中心点、绘制最小矩形框并裁剪

一、获取轮廓:

主要使用OpenCV的cv2.findContours()方法:

1. findContours( InputOutputArray image, OutputArrayOfArrays contours,
2.                               OutputArray hierarchy, int mode,
3.                               int method, Point offset=Point());
1. 第一个参数:image,单通道图像矩阵,可以是灰度图,但更常用的是二值图像,一般是经过Canny、拉普拉斯等边缘检测算子处理过的二值图像;
2. 
3. 第二个参数:contours,定义为“vector<vector<Point>> contours”,是一个向量,并且是一个双重向量,向量内每个元素保存了一组由连续的Point点构成的点的集合的向量,每一组Point点集就是一个轮廓。有多少轮廓,向量contours就有多少元素。
4. 
5. 第三个参数:hierarchy,定义为“vector<Vec4i> hierarchy”,先来看一下Vec4i的定义:
6.            typedef    Vec<int, 4>   Vec4i;                                                                                                                                       
7.            Vec4i是Vec<int,4>的别名,定义了一个“向量内每一个元素包含了4个int型变量”的向量。
8. 
9.            所以从定义上看,hierarchy也是一个向量,向量内每个元素保存了一个包含4个int整型的数组。
10. 
11.            向量hiararchy内的元素和轮廓向量contours内的元素是一一对应的,向量的容量相同。
12. 
13.            hierarchy向量内每一个元素的4个int型变量——hierarchy[i][0] ~hierarchy[i][3],分别表示第
14. 
15.         i个轮廓的后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号。如果当前轮廓没有对应的后一个
16. 
17.         轮廓、前一个轮廓、父轮廓或内嵌轮廓的话,则hierarchy[i][0] ~hierarchy[i][3]的相应位被设置为
18. 
19.         默认值-1。
20. 
21. 第四个参数:int型的mode,定义轮廓的检索模式:
22.            取值一:CV_RETR_EXTERNAL只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略
23.            取值二:CV_RETR_LIST   检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关
24.                   系,彼此之间独立,没有等级关系,这就意味着这个检索模式下不存在父轮廓或内嵌轮廓,
25.                   所以hierarchy向量内所有元素的第3、第4个分量都会被置为-1,具体下文会讲到
26.            取值三:CV_RETR_CCOMP  检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围
27.                   内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层
28.            取值四:CV_RETR_TREE, 检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓,内
29.                    层轮廓还可以继续包含内嵌轮廓。
30. 
31. 第五个参数:int型的method,定义轮廓的近似方法:
32.            取值一:CV_CHAIN_APPROX_NONE 保存物体边界上所有连续的轮廓点到contours向量内
33.            取值二:CV_CHAIN_APPROX_SIMPLE 仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours
34.                    向量内,拐点与拐点之间直线段上的信息点不予保留
35.            取值三和四:CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近
36.                    似算法
37. 第六个参数:Point偏移量,所有的轮廓信息相对于原始图像对应点的偏移量,相当于在每一个检测出的轮廓点上加
38.             上该偏移量,并且Point还可以是负值!
39. 
40.

返回值:image, contours, hierarchy

  • contour返回值
cv2.findContours()函数首先返回一个list,list中每个元素都是图像中的一个轮廓,用numpy中的ndarray表示。
  • hierarchy返回值
1. 该函数还可返回一个可选的hiararchy结果,这是一个ndarray,其中的元素个数和轮廓个数相同,每个轮廓contours[i]对应4个hierarchy元素
2. hierarchy[i][0] ~hierarchy[i][3],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,则该值为负数。

二、绘制轮廓:

cv2.drawContours()函数

cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset ]]]]])

  • 第一个参数是指明在哪幅图像上绘制轮廓;
  • 第二个参数是轮廓本身,在Python中是一个list。
  • 第三个参数指定绘制轮廓list中的哪条轮廓,如果是-1,则绘制其中的所有轮廓。后面的参数很简单。其中thickness表明轮廓线的宽度,如果是-1(cv2.FILLED),则为填充模式。绘制参数将在以后独立详细介绍。

为了看到自己画了哪些轮廓,可以使用 cv2.boundingRect()函数获取轮廓的范围,即左上角原点,以及他的高和宽。然后用cv2.rectangle()方法画出矩形轮廓

1. """
2. x, y, w, h = cv2.boundingRect(img)   
3.     参数:
4.     img  是一个二值图
5.     x,y 是矩阵左上点的坐标,
6.     w,h 是矩阵的宽和高
7. 
8. cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)
9.     img:       原图
10.     (x,y):   矩阵的左上点坐标
11.     (x+w,y+h):是矩阵的右下点坐标
12.     (0,255,0): 是画线对应的rgb颜色
13.     2:         线宽
14. """
15. for i in range(0,len(contours)):  
16.     x, y, w, h = cv2.boundingRect(contours[i])   
17.     cv2.rectangle(image, (x,y), (x+w,y+h), (153,153,0), 5)

实例:

1. import cv2
2. 
3. img = cv2.imread('wujiaoxing.png')
4. gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
5. ret,binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
6. 
7. _,contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
8. 
9. draw_img0 = cv2.drawContours(img.copy(),contours,0,(0,255,255),3)
10. draw_img1 = cv2.drawContours(img.copy(),contours,1,(255,0,255),3)
11. draw_img2 = cv2.drawContours(img.copy(),contours,2,(255,255,0),3)
12. draw_img3 = cv2.drawContours(img.copy(), contours, -1, (0, 0, 255), 3)
13. 
14. 
15. print ("contours:类型:",type(contours))
16. print ("第0 个contours:",type(contours[0]))
17. print ("contours 数量:",len(contours))
18. 
19. print ("contours[0]点的个数:",len(contours[0]))
20. print ("contours[1]点的个数:",len(contours[1]))
21. 
22. cv2.imshow("img", img)
23. cv2.imshow("draw_img0", draw_img0)
24. cv2.imshow("draw_img1", draw_img1)
25. cv2.imshow("draw_img2", draw_img2)
26. cv2.imshow("draw_img3", draw_img3)
27. 
28. cv2.waitKey(0)
29. cv2.destroyAllWindows()
30. 
31. 输出:
32. contours:类型: <class 'list'>
33. 第0 个contours: <class 'numpy.ndarray'>
34. contours 数量: 3
35. contours[0]点的个数: 6
36. contours[1]点的个数: 74

三、获取中心点、最小外接矩形:

使用 cv2.minAreaRect(cnt) ,返回点集cnt的最小外接矩形,cnt是所要求最小外接矩形的点集数组或向量,这个点集不定个数。

其中:cnt = np.array([[x1,y1],[x2,y2],[x3,y3],[x4,y4]]) # 必须是array数组的形式

rect = cv2.minAreaRect(cnt) # 得到最小外接矩形的(中心(x,y), (宽,高), 旋转角度)

box = np.int0(cv2.boxPoints(rect)) #通过box会出矩形框

这只是针对某一个轮廓获取最小外接矩形,如果想要获取图像所有轮廓的最小外接矩形则需要将所有轮廓的点集合合并到一个np.array中:

1.     allarea = np.concatenate(contours)#合并所有轮廓点集合
2.     rect = cv2.minAreaRect(allarea)
3.     box = np.int0(cv2.boxPoints(rect))

np.concatenate()函数:

concatenate((a1, a2, …), axis=0)官方文档详解:

1. concatenate(...)
2.     concatenate((a1, a2, ...), axis=0)
3. 
4.     Join a sequence of arrays along an existing axis.
5. 
6.     Parameters
7.     ----------
8.     a1, a2, ... : sequence of array_like
9.         The arrays must have the same shape, except in the dimension
10.         corresponding to `axis` (the first, by default).
11.     axis : int, optional
12.         The axis along which the arrays will be joined.  Default is 0.
13. 
14.     Returns
15.     -------
16.     res : ndarray
17.         The concatenated array.
18. 
19.     See Also
20.     --------
21.     ma.concatenate : Concatenate function that preserves input masks.
22.     array_split : Split an array into multiple sub-arrays of equal or
23.                   near-equal size.
24.     split : Split array into a list of multiple sub-arrays of equal size.
25.     hsplit : Split array into multiple sub-arrays horizontally (column wise)
26.     vsplit : Split array into multiple sub-arrays vertically (row wise)
27.     dsplit : Split array into multiple sub-arrays along the 3rd axis (depth).
28.     stack : Stack a sequence of arrays along a new axis.
29.     hstack : Stack arrays in sequence horizontally (column wise)
30.     vstack : Stack arrays in sequence vertically (row wise)
31.     dstack : Stack arrays in sequence depth wise (along third dimension)

Parameters参数

  • 传入的参数必须是一个多个数组的元组或者列表
  • 另外需要指定拼接的方向,默认是 axis = 0,也就是说对0轴的数组对象进行纵向的拼接(纵向的拼接沿着axis= 1方向);注:一般axis = 0,就是对该轴向的数组进行操作,操作方向是另外一个轴,即axis=1。
1. In [23]: a = np.array([[1, 2], [3, 4]])
2. In [24]: b = np.array([[5, 6]])
3. In [25]: np.concatenate((a, b), axis=0)
4. Out[25]:
5. array([[1, 2],
6.        [3, 4],
7.        [5, 6]])

传入的数组必须具有相同的形状,这里的相同的形状可以满足在拼接方向axis轴上数组间的形状一致即可

如果对数组对象进行 axis= 1 轴的拼接,方向是横向0轴,a是一个2*2维数组,axis= 0轴为2,b是一个1*2维数组,axis= 0 是1,两者的形状不等,这时会报错

1. In [27]: np.concatenate((a,b),axis = 1)
2. ---------------------------------------------------------------------------
3. ValueError                                Traceback (most recent call last)
4. <ipython-input-27-aa1228decc36> in <module>()
5. ----> 1 np.concatenate((a,b),axis = 1)
6. 
7. ValueError: all the input array dimensions except for the concatenation axis must match exactly

将b进行转置,得到b为2*1维数组:

1. In [28]: np.concatenate((a,b.T),axis = 1)
2. Out[28]:
3. array([[1, 2, 5],
4.        [3, 4, 6]])

来源:

[437]numpy库数组拼接np.concatenate()函数_周小董的博客-CSDN博客

findContours函数参数详解_-牧野-的博客-CSDN博客_findcontours函数

OpenCV—Python 轮廓检测 绘出矩形框(findContours\ boundingRect\rectangle)_SongpingWang的博客-CSDN博客_opencv 轮廓分类

python用opencv批量截取图像指定区域_大力挥拳的博客-CSDN博客


AIEarth是一个由众多领域内专家博主共同打造的学术平台,旨在建设一个拥抱智慧未来的学术殿堂!【平台地址:https://devpress.csdn.net/aiearth】 很高兴认识你!加入我们共同进步!

目录
相关文章
|
25天前
|
Python
【10月更文挑战第10天】「Mac上学Python 19」小学奥数篇5 - 圆和矩形的面积计算
本篇将通过 Python 和 Cangjie 双语解决简单的几何问题:计算圆的面积和矩形的面积。通过这道题,学生将掌握如何使用公式解决几何问题,并学会用编程实现数学公式。
153 60
|
3月前
|
机器学习/深度学习 监控 TensorFlow
使用Python实现深度学习模型:智能农业病虫害检测与防治
使用Python实现深度学习模型:智能农业病虫害检测与防治
247 65
|
2月前
|
机器学习/深度学习 数据采集 算法
时间序列结构变化分析:Python实现时间序列变化点检测
在时间序列分析和预测中,准确检测结构变化至关重要。新出现的分布模式往往会导致历史数据失去代表性,进而影响基于这些数据训练的模型的有效性。
151 1
|
27天前
|
机器学习/深度学习 TensorFlow 算法框架/工具
使用Python实现深度学习模型:智能质量检测与控制
使用Python实现深度学习模型:智能质量检测与控制 【10月更文挑战第8天】
160 62
使用Python实现深度学习模型:智能质量检测与控制
|
6天前
|
机器学习/深度学习 PyTorch TensorFlow
使用Python实现智能食品质量检测的深度学习模型
使用Python实现智能食品质量检测的深度学习模型
36 1
|
2月前
|
Docker Python 容器
python检测docker compose文件是否正确
python检测docker compose文件是否正确
|
2月前
|
机器学习/深度学习 数据采集 网络安全
使用Python实现深度学习模型:智能网络安全威胁检测
使用Python实现深度学习模型:智能网络安全威胁检测
180 5
|
23天前
|
机器学习/深度学习 数据采集 算法
一个 python + 数据预处理+随机森林模型 (案列)
本文介绍了一个使用Python进行数据预处理和构建随机森林模型的实际案例。首先,作者通过删除不必要的列和特征编码对数据进行了预处理,然后应用随机森林算法进行模型训练,通过GridSearchCV优化参数,最后展示了模型的评估结果。
38 0
|
2月前
|
编解码 Python Windows
python有没有包 可以检测 这个视频是否可以播放
python有没有包 可以检测 这个视频是否可以播放
|
26天前
|
运维 安全 网络协议
Python 网络编程:端口检测与IP解析
本文介绍了使用Python进行网络编程的两个重要技能:检查端口状态和根据IP地址解析主机名。通过`socket`库实现端口扫描和主机名解析的功能,并提供了详细的示例代码。文章最后还展示了如何整合这两部分代码,实现一个简单的命令行端口扫描器,适用于网络故障排查和安全审计。

热门文章

最新文章