def _length_histogram( tracks_manager: pymap.TracksManager, points: Dict[str, pymap.Landmark]) -> Tuple[List[str], List[int]]: hist = defaultdict(int) for point in points.values(): obs_count = point.number_of_observations() if not obs_count: obs_count = len(tracks_manager.get_track_observations(point.id)) hist[obs_count] += 1 return list(hist.keys()), list(hist.values())
def add_correspondences_from_tracks_manager( self, tracks_manager: pymap.TracksManager) -> None: for track_id in tracks_manager.get_track_ids(): if track_id not in self.points: continue track_obs = tracks_manager.get_track_observations(track_id) for shot_id in track_obs.keys(): if shot_id in self.shots: observation = tracks_manager.get_observation( shot_id, track_id) self.add_observation(shot_id, track_id, observation)
def paint_reconstruction( data: DataSetBase, tracks_manager: pymap.TracksManager, reconstruction: types.Reconstruction, ) -> None: """Set the color of the points from the color of the tracks.""" for k, point in reconstruction.points.items(): point.color = list( map( float, next( iter( tracks_manager.get_track_observations( str(k)).values())).color, ))
def as_graph(tracks_manager: pymap.TracksManager) -> nx.Graph: """Return the tracks manager as a bipartite graph (legacy).""" tracks = tracks_manager.get_track_ids() images = tracks_manager.get_shot_ids() graph = nx.Graph() for track_id in tracks: graph.add_node(track_id, bipartite=1) for shot_id in images: graph.add_node(shot_id, bipartite=0) for track_id in tracks: for im, obs in tracks_manager.get_track_observations(track_id).items(): graph.add_edge( im, track_id, feature=obs.point, feature_scale=obs.scale, feature_id=obs.id, feature_color=obs.color, feature_segmentation=obs.segmentation, feature_instance=obs.instance, ) return graph
def save_topview( data: DataSetBase, tracks_manager: pymap.TracksManager, reconstructions: List[types.Reconstruction], output_path: str, io_handler: io.IoFilesystemBase, ) -> None: points = [] colors = [] for rec in reconstructions: for point in rec.points.values(): track = tracks_manager.get_track_observations(point.id) if len(track) < 2: continue coords = point.coordinates points.append(coords) r, g, b = [], [], [] for obs in track.values(): r.append(obs.color[0]) g.append(obs.color[1]) b.append(obs.color[2]) colors.append((statistics.median(r), statistics.median(g), statistics.median(b))) all_x = [] all_y = [] for rec in reconstructions: for shot in rec.shots.values(): o = shot.pose.get_origin() all_x.append(o[0]) all_y.append(o[1]) if not shot.metadata.gps_position.has_value: continue gps = shot.metadata.gps_position.value all_x.append(gps[0]) all_y.append(gps[1]) # compute camera's XY bounding box low_x, high_x = np.min(all_x), np.max(all_x) low_y, high_y = np.min(all_y), np.max(all_y) # get its size size_x = high_x - low_x size_y = high_y - low_y # expand bounding box by some margin margin = 0.05 low_x -= size_x * margin high_x += size_y * margin low_y -= size_x * margin high_y += size_y * margin # update size size_x = high_x - low_x size_y = high_y - low_y im_size_x = 2000 im_size_y = int(im_size_x * size_y / size_x) topview = np.zeros((im_size_y, im_size_x, 3)) # splat points using gaussian + max-pool splatting = 15 size = 2 * splatting + 1 kernel = _get_gaussian_kernel(splatting, 2) kernel /= kernel[splatting, splatting] for point, color in zip(points, colors): x, y = int((point[0] - low_x) / size_x * im_size_x), int( (point[1] - low_y) / size_y * im_size_y) if not ((0 < x < (im_size_x - 1)) and (0 < y < (im_size_y - 1))): continue k_low_x, k_low_y = -min(x - splatting, 0), -min(y - splatting, 0) k_high_x, k_high_y = ( size - max(x + splatting - (im_size_x - 2), 0), size - max(y + splatting - (im_size_y - 2), 0), ) h_low_x, h_low_y = max(x - splatting, 0), max(y - splatting, 0) h_high_x, h_high_y = min(x + splatting + 1, im_size_x - 1), min(y + splatting + 1, im_size_y - 1) for i in range(3): current = topview[h_low_y:h_high_y, h_low_x:h_high_x, i] splat = kernel[k_low_y:k_high_y, k_low_x:k_high_x] topview[h_low_y:h_high_y, h_low_x:h_high_x, i] = np.maximum(splat * (color[i] / 255.0), current) plt.clf() plt.imshow(topview) # display computed camera's XY linewidth = 1 markersize = 4 for rec in reconstructions: sorted_shots = sorted(rec.shots.values(), key=lambda x: x.metadata.capture_time.value) c_camera = cm.get_cmap("cool")(0 / len(reconstructions)) c_gps = cm.get_cmap("autumn")(0 / len(reconstructions)) for j, shot in enumerate(sorted_shots): o = shot.pose.get_origin() x, y = int((o[0] - low_x) / size_x * im_size_x), int( (o[1] - low_y) / size_y * im_size_y) plt.plot( x, y, linestyle="", marker="o", color=c_camera, markersize=markersize, linewidth=1, ) # also display camera path using capture time if j < len(sorted_shots) - 1: n = sorted_shots[j + 1].pose.get_origin() nx, ny = int((n[0] - low_x) / size_x * im_size_x), int( (n[1] - low_y) / size_y * im_size_y) plt.plot([x, nx], [y, ny], linestyle="-", color=c_camera, linewidth=linewidth) # display GPS error if not shot.metadata.gps_position.has_value: continue gps = shot.metadata.gps_position.value gps_x, gps_y = int((gps[0] - low_x) / size_x * im_size_x), int( (gps[1] - low_y) / size_y * im_size_y) plt.plot( gps_x, gps_y, linestyle="", marker="v", color=c_gps, markersize=markersize, linewidth=1, ) plt.plot([x, gps_x], [y, gps_y], linestyle="-", color=c_gps, linewidth=linewidth) plt.xticks( [0, im_size_x / 2, im_size_x], [0, f"{int(size_x / 2):.0f}", f"{size_x:.0f} meters"], fontsize="small", ) plt.yticks( [im_size_y, im_size_y / 2, 0], [0, f"{int(size_y / 2):.0f}", f"{size_y:.0f} meters"], fontsize="small", ) with io_handler.open(os.path.join(output_path, "topview.png"), "wb") as fwb: plt.savefig( fwb, dpi=300, bbox_inches="tight", )