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

如何迭代列表对相近点取均值 计算轮廓直线交点距离

样例检测结果图
交点检测细节图

问题描述
  • 直线与轮廓相交检测时,红色圆圈区域检测到2个距离极近的像素点,橙色圆圈区域检测到1个像素点
  • 直接调用math.dist()计算两组点的距离时,红圈区域的近邻重复点会导致结果偏差,需要先对近邻点求坐标均值合并,但目前无法将平均点正确追加回点列表
  • 目标效果:所有距离相近的点自动分组求均值合并,最终只保留2个有效点用于距离计算

原实现代码如下:

import numpy as np
import cv2
import math
from matplotlib import pyplot as plt
from scipy import stats


img = cv2.imread("C:/Users/jay/Desktop/a.png")
gry = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gry,0,255,cv2.THRESH_BINARY_INV)
cnt,_ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

# 可视化全量轮廓
fullContour = np.zeros((thresh.shape[0], thresh.shape[1], 3), np.uint8)
cv2.drawContours(fullContour, cnt,-1, (255,255,255), 1)

cntPoints = []

for c in cnt:
    for cc in c:
        for ccc in cc:
            cntPoints.append((ccc[0], ccc[1]))

for i in range (len(cnt)):
    
    singleContour = np.zeros((thresh.shape[0], thresh.shape[1], 3), np.uint8)
    
    cv2.drawContours(singleContour, cnt[i], -1, (255,255,255), 1)
    
    visualSingleContour = singleContour.copy()
    
    for _ in range (10):
        
        line_blank_mask = np.zeros((thresh.shape[0], thresh.shape[1], 3), np.uint8)
        
        top = [np.random.randint(0,285),0]
        bottom = [np.random.randint(0,285), 305*2]
        
        cv2.line(visualSingleContour, (top[0],top[1]), (bottom[0],bottom[1]), (255,255,255), 1, cv2.LINE_4)
        cv2.line(line_blank_mask, (top[0],top[1]), (bottom[0],bottom[1]), (255,255,255), 1, cv2.LINE_4)
        
        comparedMask = cv2.bitwise_and(singleContour, line_blank_mask)
        
        points = []
        distance = []

        for x in range (visualSingleContour.shape[1]):
            for y in range (visualSingleContour.shape[0]):

                if comparedMask[y][x][0] == 255:
                    points.append([x,y])
        
        print(points)

        plt.subplot(1,3,1)
        plt.imshow(fullContour)
        plt.subplot(1,3,2)
        plt.imshow(visualSingleContour)
        plt.subplot(1,3,3)
        plt.imshow(comparedMask)
        plt.pause(1)
解决方案

在收集完所有交点存入points列表后,增加基于距离阈值的聚类合并逻辑,自动把间距小于阈值的近邻点归为一组,每组取坐标均值作为合并后的有效点即可。

修改时,在print(points)这行之前插入以下代码:

# 近邻点合并配置 可根据实际近邻点的间距调整阈值,单位为像素
DIST_THRESHOLD = 3
points_arr = np.array(points)
clusters = []

for p in points_arr:
    matched = False
    # 遍历已有聚类,判断当前点是否属于近邻组
    for cluster in clusters:
        cluster_center = np.mean(cluster, axis=0)
        # 计算当前点到聚类中心的欧氏距离
        if np.linalg.norm(p - cluster_center) < DIST_THRESHOLD:
            cluster.append(p)
            matched = True
            break
    # 没有匹配到近邻组则新建聚类
    if not matched:
        clusters.append([p])

# 每个聚类取坐标均值,得到最终有效点
merged_points = [np.mean(group, axis=0).astype(int).tolist() for group in clusters]

使用说明:

  • DIST_THRESHOLD为近邻判定阈值,根据实际检测到的近邻点间距调整即可,比如红圈内两个点间距为2像素时,设为3即可正确归组
  • 该逻辑不限制单组近邻点的数量,2个、3个甚至更多挨在一起的检测点都会被自动合并为一个均值点
  • 后续距离计算直接使用merged_points即可,正常场景下最终会得到2个有效点,调用math.dist(merged_points[0], merged_points[1])就能得到无偏差的距离结果

内容的提问来源于stack exchange,提问作者peter teoh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 02:51:21