You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 04:05:52