Esempio n. 1
0
def clusterStrings(words, affinity="precomputed", damping=0.5):
    """
    Clusters a list of strings using Affinity propagation
    :param words: The list of strings you wish to cluster
    :type words: list of str
    :param affinity: The affinity method to use. Supported: "precomputed" and "euclidean"
    :type affinity: str
    :param damping: Damping factor (between 0.5 and 1) is the extent to which the current value is maintained relative to incoming values (weighted 1 - damping).
    :type damping: float
    :return: A dict of clusters with key being the cluster center
    """
    try:
        clusters = {}
        words = numpy.asarray(words)
        lev_similarity = -1*numpy.array([[distance(w1,w2) for w1 in words] for w2 in words])

        affprop = sklearn.cluster.AffinityPropagation(affinity="precomputed", damping=0.5)
        affprop.fit(lev_similarity)
        for cluster_id in numpy.unique(affprop.labels_):
            center = words[affprop.cluster_centers_indices_[cluster_id]]
            cluster = numpy.unique(words[numpy.nonzero(affprop.labels_==cluster_id)])
            clusters[center] = cluster.tolist()

    except Exception as e:
        prettyPrintError(e)
        return {}

    return dict(clusters)
 def build_ap_cluster_dictionary(self, labels, tokens, centers_indices):
     clusters = dict()
     for cluster_id in np.unique(labels):
         exemplar = tokens[centers_indices[cluster_id]]
         cluster = np.unique(tokens[np.nonzero(labels == cluster_id)])
         clusters[exemplar] = cluster.tolist()
     return clusters
 def cluster(self, distances, tokens):
     self.ap.fit(distances)
     clusters = dict()
     for cluster_id in np.unique(self.ap.labels_):
         exemplar = tokens[self.ap.cluster_centers_indices_[cluster_id]]
         cluster = np.unique(tokens[np.nonzero(self.ap.labels_ == cluster_id)])
         clusters[exemplar] = cluster.tolist()
     return clusters
 def build_cluster_dictionary(self, labels, tokens):
     clusters = dict()
     key = 0
     for cluster_id in np.unique(labels):
         cluster = np.unique(tokens[np.nonzero(labels == cluster_id)])
         clusters[key] = cluster.tolist()
         key += 1
     return clusters
    def detector_callback(self, preprocessed_pc):
        """
        Main callback method of the detector that executes the procedure of
        automatic thresholding, clustering, volume correction and some
        calculations to extract the volume, boundaries and centers of the gaps.

        Parameters
        ----------
        preprocessed_pc : sensor_msgs.pointcloud2
            Preprocessed point cloud generated by the preprocessing node.

        Notes
        -----
        After each procedure step a point cloud is published over the
        publishers defined in __init__ as well as some visualization Markers
        for RVIZ.

        """
        points = helpers.PC2_to_numpy_array(preprocessed_pc)
        self.frame_id = preprocessed_pc.header.frame_id

        # ----- AUTOMATIC THRESHOLDING TO FIND GAPS -----
        depth_axis_pts = points[:, self.depth_axis]

        if(self.automatic_thresholding == 0):
            try:
                threshold = threshold_minimum(depth_axis_pts)
            except RuntimeError:
                rospy.logwarn("threshold_minimum was unable to find two " +
                              "maxima in histogram!")
                return
        elif(self.automatic_thresholding == 1):
            threshold = threshold_li(depth_axis_pts)
        elif(self.automatic_thresholding == 2):
            threshold = threshold_yen(depth_axis_pts)
        elif(self.automatic_thresholding == 3):
            threshold = threshold_otsu(depth_axis_pts, self.otsu_bins)

        device_surface_pts = points[depth_axis_pts <= threshold]
        self.surface_height = np.median(device_surface_pts[:, self.depth_axis])

        points = points[depth_axis_pts > threshold]

        # ----- PUBLISHING OF THE THRESHOLDED CLOUD -----
        thresholded_cloud = helpers.numpy_array_to_PC2(points, self.frame_id)
        self.thresholded_cloud_pub.publish(thresholded_cloud)

        # ----- CLUSTERING THE GAPS -----
        clustering_switch = {
            0: self.kmeans,
            1: self.birch,
            2: self.dbscan,
            3: self.hdbscan
        }

        cluster_algorithm = clustering_switch[self.clustering]
        labels = cluster_algorithm(points)
        labels_T = np.array([labels]).T
        clustered_points = np.append(points, labels_T, axis=1)

        color_list = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0],
                      [1.0, 1.0, 1.0], [0.5, 0.5, 0.5], [1.0, 0.5, 0.5],
                      [0.5, 1.0, 0.5], [0.5, 0.5, 1.0]]

        clusters = []
        colored_clusters = []
        # check for each cluster if there are enough points in the cluster
        for i in set(labels):
            cluster = clustered_points[clustered_points[:, 3] == float(i)]
            cluster = cluster[:, [0, 1, 2]]

            # create seperate list of points to visualize clusters
            for cluster_point in cluster:
                try:
                    color = np.array(color_list[i])
                except IndexError:
                    color = np.array([0.0, 0.0, 0.0])
                point_with_color = np.append(cluster_point, color)
                colored_clusters.append(point_with_color)

            # To construct a convex hull a minimum of 4 points is needed
            num_of_points, dim = cluster.shape
            if(num_of_points >= 4):
                clusters.append(cluster)

        # ----- PUBLISHING OF CLUSTERS-----
        clustered_cloud = helpers.XYZRGB_to_PC2(
            colored_clusters, self.frame_id)
        self.clustered_cloud_pub.publish(clustered_cloud)

        # ----- VOLUME CORRECTION -----
        volume_corrected_clusters = []
        num_vol_corrected_pts = 0
        volume_corrected_pts_tuple = ()
        for cluster in clusters:
            hull = ConvexHull(cluster, qhull_options="QJ")

            # Map from vertex to point in cluster
            vertices = []
            for vertex in hull.vertices:
                x, y, z = cluster[vertex]
                vertices.append([x, y, z])

            gap = cluster.tolist()
            for vertex in vertices:
                # For each vertex, add a new point to the gap with the height
                # of the surface and the other axes corresponding to the vertex
                if(self.depth_axis == 0):
                    volume_point = [self.surface_height, vertex[1], vertex[2]]
                elif(self.depth_axis == 1):
                    volume_point = [vertex[0], self.surface_height, vertex[2]]
                elif(self.depth_axis == 2):
                    volume_point = [vertex[0], vertex[1], self.surface_height]

                gap.append(volume_point)
                num_vol_corrected_pts = num_vol_corrected_pts + 1

            volume_corrected_clusters.append(np.array(gap))
            volume_corrected_pts_tuple = volume_corrected_pts_tuple + \
                (num_vol_corrected_pts,)
            num_vol_corrected_pts = 0

        # ---- CALCULATING CONVEX HULLS OF GAPS AND THEIR CENTER -----
        convex_hulls_and_info = helpers.calculate_convex_hulls_and_centers(
            volume_corrected_clusters)

        # ---- FILTER BASED ON VOLUME -----
        self.gaps = []
        for gap_info in convex_hulls_and_info:
            gap_volume = gap_info[3]

            # convert cm^3 to m^3
            gap_volume = gap_volume * 1000000.0

            if(self.min_gap_volume <= gap_volume <= self.max_gap_volume):
                self.gaps.append(gap_info)

        # ----- PUBLISHING THE MARKERS TO RVIZ -----
        if not len(self.gaps) == 0:
            gap_info = zip(*self.gaps)
            centers, vertices, simplices, volumes, num_of_points = gap_info

            convex_hull_marker = visualization.draw_convex_hull(
                simplices, self.frame_id)
            self.convex_hull_marker_pub.publish(convex_hull_marker)

            centers_marker = visualization.draw_centers(centers, self.frame_id)
            self.centers_marker_pub.publish(centers_marker)

            volume_text_marker = visualization.draw_volume_text(
                volumes, centers, self.frame_id)
            self.volume_text_marker_pub.publish(volume_text_marker)

        # ----- EVALUATION -----
        if(self.create_evaluation):
            num_of_points = np.subtract(num_of_points, num_vol_corrected_pts)
            evaluation_info = zip(num_of_points, volumes, centers)
            helpers.evaluate_detector(evaluation_info)
            self.create_evaluation = False