Python实现邻近轮廓分组并绘制外接包围框方法咨询
实现邻近轮廓分组与外接框绘制的方案
一、核心思路:基于轮廓中心的距离聚类
要把邻近轮廓分组,核心是先计算每个轮廓的中心坐标(质心或外接矩形中心),再依据中心间的距离判断归属,最后为每组计算并绘制外接包围框。
二、具体实现步骤
1. 计算每个轮廓的中心坐标
遍历检测到的黄色物体轮廓,用两种方式获取中心(避免质心计算的除零问题):
import cv2 import numpy as np # 假设已得到黄色物体的轮廓列表 contours contours = [...] # 你的轮廓检测结果 # 存储每个轮廓的中心坐标 centers = [] for cnt in contours: # 优先用质心 M = cv2.moments(cnt) if M["m00"] != 0: cX = int(M["m10"] / M["m00"]) cY = int(M["m01"] / M["m00"]) else: # 质心计算失败时,用外接矩形中心替代 x, y, w, h = cv2.boundingRect(cnt) cX = x + w//2 cY = y + h//2 centers.append((cX, cY))
2. 基于距离阈值的分组
设定像素距离阈值(根据实际场景调整),将距离小于阈值的轮廓归为同一组:
# 初始化分组,每个轮廓先单独成组 groups = [[i] for i in range(len(contours))] # 距离阈值,单位:像素 distance_threshold = 50 # 遍历所有中心对,合并邻近组 for i in range(len(centers)): for j in range(i+1, len(centers)): # 计算欧氏距离 dist = np.linalg.norm(np.array(centers[i]) - np.array(centers[j])) if dist < distance_threshold: # 找到两个轮廓所在的组 group_i = None group_j = None for g in groups: if i in g: group_i = g if j in g: group_j = g # 不在同一组则合并 if group_i != group_j: group_i.extend(group_j) groups.remove(group_j)
3. 为每组绘制外接包围框
收集组内所有轮廓的外接矩形坐标,计算整个组的最小外接框并绘制:
# 读取原始图像 img = cv2.imread("your_image.jpg") for group in groups: # 收集组内所有轮廓的外接矩形坐标 rects = [] for idx in group: x, y, w, h = cv2.boundingRect(contours[idx]) rects.append((x, y, x+w, y+h)) # 计算组的最小外接矩形 all_x = [r[0] for r in rects] all_y = [r[1] for r in rects] all_x2 = [r[2] for r in rects] all_y2 = [r[3] for r in rects] group_x = min(all_x) group_y = min(all_y) group_w = max(all_x2) - group_x group_h = max(all_y2) - group_y # 绘制红色外接框(线宽2) cv2.rectangle(img, (group_x, group_y), (group_x+group_w, group_y+group_h), (0,0,255), 2) # 显示结果 cv2.imshow("Grouped Bounding Boxes", img) cv2.waitKey(0) cv2.destroyAllWindows()
三、关于KMeans分组的可行性
用scikit-learn的KMeans是可行的,但必须预先知道大致的分组数量(即n_clusters参数)。如果场景中黄色物体的组数不固定,KMeans效果会很差——比如实际有3组但设n_clusters=2,会错误合并;设多了又会拆分正确的组。
若要用KMeans,示例代码如下:
from sklearn.cluster import KMeans # 转换中心坐标为numpy数组 centers_np = np.array(centers) # 假设已知有3组,设置n_clusters=3 kmeans = KMeans(n_clusters=3, random_state=0).fit(centers_np) labels = kmeans.labels_ # 根据标签分组 groups = {} for idx, label in enumerate(labels): if label not in groups: groups[label] = [] groups[label].append(idx) # 后续绘制外接框步骤同前
更推荐用距离阈值法,它无需预先知道组数,适配动态场景。
内容的提问来源于stack exchange,提问作者SunAwtCanvas
相关产品推荐
相关产品推荐

