Simple way of fusing a few close points?

前端 未结 4 2131
南旧
南旧 2021-02-06 16:57

I have a list of points as such

points = [(-57.213878612138828, 17.916958304169601),
          (76.392039480378514, 0.060882542482108504),
          (0.124176706         


        
4条回答
  •  遥遥无期
    2021-02-06 17:13

    Ok, here's my severly unoptimized go at a slightly more complex algorithm, which first creates a boolean proximity matrix, from that a list of clusters which is ultimately used to obtain the averaged coordinates:

    # -*- coding: utf-8 -*-
    """
    Created on Wed Oct 16 08:42:50 2013
    
    @author: Tobias Kienzler
    """
    
    
    def squared_distance(p1, p2):
        # TODO optimization: use numpy.ndarrays, simply return (p1-p2)**2
        sd = 0
        for x, y in zip(p1, p2):
            sd += (x-y)**2
        return sd
    
    
    def get_proximity_matrix(points, threshold):
        n = len(points)
        t2 = threshold**2
        # TODO optimization: use sparse boolean matrix
        prox = [[False]*n for k in xrange(n)]
        for i in xrange(0, n):
            for j in xrange(i+1, n):
                prox[i][j] = (squared_distance(points[i], points[j]) < t2)
                prox[j][i] = prox[i][j]  # symmetric matrix
        return prox
    
    
    def find_clusters(points, threshold):
        n = len(points)
        prox = get_proximity_matrix(points, threshold)
        point_in_list = [None]*n
        clusters = []
        for i in xrange(0, n):
            for j in xrange(i+1, n):
                if prox[i][j]:
                    list1 = point_in_list[i]
                    list2 = point_in_list[j]
                    if list1 is not None:
                        if list2 is None:
                            list1.append(j)
                            point_in_list[j] = list1
                        elif list2 is not list1:
                            # merge the two lists if not identical
                            list1 += list2
                            point_in_list[j] = list1
                            del clusters[clusters.index(list2)]
                        else:
                            pass  # both points are already in the same cluster
                    elif list2 is not None:
                        list2.append(i)
                        point_in_list[i] = list2
                    else:
                        list_new = [i, j]
                        for index in [i, j]:
                            point_in_list[index] = list_new
                        clusters.append(list_new)
            if point_in_list[i] is None:
                list_new = [i]  # point is isolated so far
                point_in_list[i] = list_new
                clusters.append(list_new)
        return clusters
    
    
    def average_clusters(points, threshold=1.0, clusters=None):
        if clusters is None:
            clusters = find_clusters(points, threshold)
        newpoints = []
        for cluster in clusters:
            n = len(cluster)
            point = [0]*len(points[0])  # TODO numpy
            for index in cluster:
                part = points[index]  # in numpy: just point += part / n
                for j in xrange(0, len(part)):
                    point[j] += part[j] / n  # TODO optimization: point/n later
            newpoints.append(point)
        return newpoints
    
    
    points = [(-57.213878612138828, 17.916958304169601),
              (76.392039480378514, 0.060882542482108504),
              (0.12417670682730897, 1.0417670682730924),
              (-64.840321976787706, 21.374279296143762),
              (-48.966302937359913, 81.336323778066188),
              (11.122014925372399, 85.001119402984656),
              (8.6383049769438465, 84.874829066623917),
              (-57.349835526315836, 16.683634868421084),
              (83.051530302006697, 97.450469562867383),
              (8.5405200433369473, 83.566955579631625),
              (81.620435769843965, 48.106831247886376),
              (78.713027357450656, 19.547209139192304),
              (82.926153287322933, 81.026080639302577)]
    
    threshold = 20.0
    clusters = find_clusters(points, threshold)
    clustered = average_clusters(points, clusters=clusters)
    print "clusters:", clusters
    print clustered
    
    import matplotlib.pyplot as plt
    ax = plt.figure().add_subplot(1, 1, 1)
    for cluster in clustered:
        ax.add_patch(plt.Circle(cluster, radius=threshold/2, color='g'))
    for point in points:
        ax.add_patch(plt.Circle(point, radius=threshold/2, edgecolor='k', facecolor='none'))
    plt.plot(*zip(*points), marker='o', color='r', ls='')
    plt.plot(*zip(*clustered), marker='.', color='g', ls='')
    plt.axis('equal')
    plt.show()
    

    clustering...

    (For better visualization, the circles' radii are half the threshold, i.e. points are in the same cluster if their circles merely intersect/touch one another's edge.)

提交回复
热议问题