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


问题描述
- 直线与轮廓相交检测时,红色圆圈区域检测到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
相关产品推荐
相关产品推荐

