✨博客主页:米开朗琪罗~🎈
✨博主爱好:羽毛球🏸
✨年轻人要:Living for the moment(活在当下)!💪
🏆推荐专栏:【图像处理】【千锤百炼Python】【深度学习】【排序算法】
目录
- 😺一、查找并绘制物体轮廓
-
- 🐶1.1 查找轮廓
-
- 🦄1.1.1 函数API
- 🦄1.1.2 程序设计
- 🐶1.2 绘制轮廓
-
- 🦄1.2.1 函数API
- 🦄1.2.2 全部轮廓绘制程序设计及结果可视化
- 🦄1.2.2 逐个轮廓绘制程序设计及结果可视化
- 🐶1.3 统计轮廓信息
-
- 🦄1.3.1 函数API
- 🦄1.3.2 程序设计
😺一、查找并绘制物体轮廓
🐶1.1 查找轮廓
🦄1.1.1 函数API
函数:img, contours, hierarchy = cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]])
参数介绍:
- 参数image:寻找轮廓的图像;
- 参数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,CV_CHAIN_APPROX_TC89_KCOS:用teh-Chinl chain 近似算法
- 返回值img:返回原图的灰度图;
- 返回值contour:返回一个列表,列表中包含了检测到的所有轮廓,每个轮廓用ndarray表示;
- 返回值hierarchy:这是一个ndarray,其中的元素个数和轮廓个数相同,每个轮廓contours[i]对应4个hierarchy元素,分别为hierarchy[i][0] ~hierarchy[i][3],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,则该值为负数。
https://blog.csdn.net/hjxu2016/article/details/77833336
🦄1.1.2 程序设计
注意:在查找物体轮廓之前要先对图像进行灰度化与二值化操作!
实验使用图像:
import cv2
import numpy as np
original = cv2.imread(r'C:\Users\Lenovo\Desktop\contour.jpg')
print(original.shape)
# 查找物体轮廓
def findcontour(img):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 图像灰度化
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 图像二值化
image, contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 查找物体轮廓
return image, contours, hierarchy
image, contours, hierarchy = findcontour(original)
我们打印轮廓数量:
print('轮廓数:', len(contours))
得到:轮廓数: 3
注意:findcontours函数会“原地”修改输入的图像!!!
🐶1.2 绘制轮廓
🦄1.2.1 函数API
函数:img = cv2.drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None)
参数介绍:
- 参数image:要绘制轮廓的图像,必须是三通道;
- 参数contours:表示轮廓本身,存储方式为list;
- 参数contourIdx:轮廓索引,表示要绘制哪条轮廓,若为-1,则绘制所有轮廓;
- 返回值img:绘制完轮廓的图像。
🦄1.2.2 全部轮廓绘制程序设计及结果可视化
contours = cv2.drawContours(original, contours, -1, (255, 0, 0), 5) # 绘制所有轮廓
cv2.imshow("contour", contours)
cv2.waitKey()
所有轮廓绘制的结果如下:
🦄1.2.2 逐个轮廓绘制程序设计及结果可视化
nums = len(contours)
color = [(255, 0, 0), (0, 255, 0), (0, 0, 255)]
contourssplit=[]
for i in range(nums):
temp = np.zeros(original.shape, np.uint8)
contourssplit.append(temp)
contourssplit[i] = cv2.drawContours(contourssplit[i], contours, i, color[i], 2)
cv2.imwrite(r'C:\\Users\\Lenovo\\Desktop\\%d.jpg' % i, contourssplit[i])
cv2.imshow("contours" + str(i), contourssplit[i])
cv2.waitKey()
逐个轮廓绘制的结果如下:
🐶1.3 统计轮廓信息
🦄1.3.1 函数API
计算轮廓面积
函数:area= cv2.contourArea(contour,oriented)
参数介绍:
- 参数contour:轮廓信息;
- 参数oriented:有方向的区域标志
true:此函数依赖轮廓的方向(顺时针或逆时针)返回一个已标记区域的值。
false:默认值。意味着返回不带方向的绝对值。
该函数有个缺点:由于其计算方式是利用格林公式计算轮廓面积,所以如果遇到具有自交点的轮廓,该函数会给出错误的结果。
统计轮廓信息
⬇️⬇️⬇️⬇️⬇️⬇️⬇️⬇️重点⬇️⬇️⬇️⬇️⬇️⬇️⬇️⬇️
函数:moment = cv2.moments(contour)
参数介绍:
- 参数contour:轮廓信息;
- 参数moment:图像的矩。
函数返回一个字典,你可以从中得到有关轮廓的各种信息,包括面积、重心等!
计算轮廓周长
函数:perimeter=cv2.arcLength(contour, closed)
参数介绍:
- 参数contour:轮廓信息;
- 参数closed:用于指示轮廓是否封闭。
True:轮廓封闭。
False:轮廓不封闭。
🦄1.3.2 程序设计
我们先看cv2.moments中的信息,使用debug看a中的数据:
a是一个具有24个键值对的字典,包含了轮廓的各个信息。
使用cv2.moments(contours[i])['m00']
得到轮廓面积;
使用int(cv2.moments(contours[i])['m10']/cv2.moments(contours[i])['m00'])
和
int(cv2.moments(contours[i])['m01']/cv2.moments(contours[i])['m00'])
得到轮廓重心;
使用cv2.arcLength(contours[i], True)
得到轮廓的长度。
nums = len(contours)
color = [(255, 0, 0), (0, 255, 0), (0, 0, 255)]
contourssplit=[]
for i in range(nums):
temp = np.zeros(original.shape, np.uint8)
contourssplit.append(temp)
contourssplit[i] = cv2.drawContours(contourssplit[i], contours, i, color[i], 2)
a = cv2.moments(contours[i])
print("轮廓" + str(i) + "的面积:%d" % cv2.moments(contours[i])['m00'])
print("轮廓" + str(i) + "的重心:%d" % int(cv2.moments(contours[i])['m10']/cv2.moments(contours[i])['m00']),
int(cv2.moments(contours[i])['m01']/cv2.moments(contours[i])['m00']))
print("轮廓" + str(i) + "的长度:%d" % cv2.arcLength(contours[i], True))
结果如下:
轮廓0的面积:3214
轮廓0的重心:69 199
轮廓0的长度:403
轮廓1的面积:4752
轮廓1的重心:202 142
轮廓1的长度:336
轮廓2的面积:8019
轮廓2的重心:69 67
轮廓2的长度:336