cv2.findContours()函数介绍和解析
时间: 2023-11-02 07:32:18 浏览: 45
cv2.findContours()是一个用于在二进制图像中查找轮廓的函数。该函数接受一张二进制图像作为输入,并返回一个轮廓列表和轮廓的层次结构。
函数语法如下:
`contours, hierarchy = cv2.findContours(image, mode, method, offset)`
其中参数含义如下:
- image:输入的二进制图像。
- mode:轮廓检索模式,可以是RETR_EXTERNAL(只检索最外层轮廓)、RETR_LIST(检索所有轮廓,不建立父子关系)、RETR_CCOMP(检索所有轮廓,建立两层父子关系)、RETR_TREE(检索所有轮廓,建立完整的父子层级关系)。
- method:轮廓逼近方法,可以是CHAIN_APPROX_NONE(存储所有的轮廓点)、CHAIN_APPROX_SIMPLE(仅存储水平、垂直和斜线端点)、CHAIN_APPROX_TC89_L1、CHAIN_APPROX_TC89_KCOS。
- offset:可选参数,表示偏移量,用于调整轮廓中的坐标值。
该函数返回轮廓列表和轮廓的层次结构,其中轮廓列表是一个Numpy数组,每个元素都是一个轮廓,包含了轮廓上的所有点的坐标。轮廓的层次结构是一个Numpy数组,每个元素都是一个四元组,包含了轮廓的索引、下一个轮廓的索引、父轮廓的索引和内部轮廓的索引。
使用cv2.drawContours()函数可以在原始图像上绘制轮廓。
相关问题
results = [] if masks.shape[0] > 0: for label, score, seg in zip(class_ids, conf, masks): # 解析分割掩码 mask = seg.argmax(axis=0) # 取最大值的索引,将二维掩码还原为一维 mask = mask.astype(np.uint8) # 将掩码转换为无符号整数类型 _, mask_binary = cv2.threshold(mask, 0, 255, cv2.THRESH_BINARY) # 将掩码转换为二值图像 # 获取分割多边形 contours, _ = cv2.findContours(mask_binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) contour = contours[0].flatten().tolist() if len(contours) > 0 else [] results.append({ "confidence": str(score), "label": labels.get(label, "unknown"), "polygon": contour, "type": "polygon", "mask": mask.tolist() # 将分割掩码转换为列表形式 })直接给出掩码 成点points:
如果要将掩码转换为点(points)形式,您可以使用`cv2.findContours`函数找到分割多边形的轮廓,并将轮廓的点坐标提取出来作为点(points)。
以下是修改后的代码示例:
```python
results = []
if masks.shape[0] > 0:
for label, score, seg in zip(class_ids, conf, masks):
# 解析分割掩码
mask = seg.argmax(axis=0) # 取最大值的索引,将二维掩码还原为一维
mask = mask.astype(np.uint8) # 将掩码转换为无符号整数类型
_, mask_binary = cv2.threshold(mask, 0, 255, cv2.THRESH_BINARY) # 将掩码转换为二值图像
# 获取分割多边形
contours, _ = cv2.findContours(mask_binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contour = contours[0] if len(contours) > 0 else []
# 将分割多边形的点坐标转换为列表的点(points)形式
points = contour.squeeze().tolist() if len(contour) > 0 else []
results.append({
"confidence": str(score),
"label": labels.get(label, "unknown"),
"points": points,
"type": "polygon",
"mask": mask.tolist() # 将分割掩码转换为列表形式
})
```
在这个示例中,`contours[0]`表示第一个轮廓的点坐标,通过`squeeze()`方法将其从二维数组转换为一维数组,并使用`tolist()`方法将其转换为列表形式。然后将这些点(points)添加到结果中。
请注意,这里的`points`是以列表形式表示的点坐标,而不是一个个独立的点。如果您需要将每个点表示为独立的坐标对,可以进一步对`points`进行处理。
优化这段代码import cv2 import imutils import numpy as np img = cv2.imread('D:\pycharm\PycharmProjects\pythonProject\p1\p1.jpg', cv2.IMREAD_COLOR) img = cv2.resize(img, (600, 400)) cv2.imshow('Origin image', img) img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) img_gray = cv2.bilateralFilter(img_gray, 13, 15, 15) img_edged = cv2.Canny(img_gray, 30, 200) cv2.imshow('edged image', img_edged) img_contours = cv2.findContours(img_edged.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) img_contours = imutils.grab_contours(img_contours) img_contours = sorted(img_contours, key=cv2.contourArea, reverse=True)[:10] screenCnt = None for c in img_contours: peri = cv2.arcLength(c, True) approx = cv2.approxPolyDP(c, 0.018 * peri, True) if len(approx) == 4: screenCnt = approx break if screenCnt is None: detected = 0 print("No contour detected") else: detected = 1 if detected == 1: cv2.drawContours(img, [screenCnt], -1, (0, 0, 255), 3) mask = np.zeros(img_gray.shape, np.uint8) new_image = cv2.drawContours(mask, [screenCnt], 0, 255, -1, ) cv2.imshow('mask_image', new_image) new_image = cv2.bitwise_and(img, img, mask=mask) (x, y) = np.where(mask == 255) (topx, topy) = (np.min(x), np.min(y)) (bottomx, bottomy) = (np.max(x), np.max(y)) cropped = img_gray[topx:bottomx + 1, topy:bottomy + 1] cropped = cv2.resize(cropped, (400, 200)) cv2.imshow('Cropped', cropped) cv2.waitKey(0) cv2.destroyAllWindows()
这段代码主要是对一张图片进行边缘检测,并找出图片中的一个矩形区域进行裁剪。下面是对代码的一些优化建议:
1. 将代码拆分成多个函数,增加代码的可读性和可维护性。
2. 将文件路径字符串改为使用原始字符串(raw string),以避免转义字符带来的问题。
3. 考虑使用命令行参数或配置文件来指定输入文件路径和其他参数,以增加代码的灵活性。
4. 添加错误处理机制,例如检查文件是否存在,处理可能出现的异常情况。
5. 使用`with`语句来管理资源,例如`cv2.VideoCapture`和`cv2.imshow`,以确保资源的正确释放。
6. 使用`argparse`模块来解析命令行参数,以方便指定不同的参数和选项。
7. 使用更具描述性的变量名,以增加代码的可读性。
8. 添加注释来解释代码的功能和逻辑。
9. 考虑使用适当的异常处理机制,例如在无法找到矩形区域时抛出异常或返回错误码。
以上是对代码的一些优化建议,你可以根据实际需求进行调整。