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