def read_ground_control_points(fileobj: IO) -> List[pymap.GroundControlPoint]: """Read ground control points from json file""" obj = json_load(fileobj) points = [] for point_dict in obj["points"]: point = pymap.GroundControlPoint() point.id = point_dict["id"] lla = point_dict.get("position") if lla: point.lla = lla point.has_altitude = "altitude" in point.lla observations = [] observing_images = set() for o_dict in point_dict["observations"]: o = pymap.GroundControlPointObservation() o.shot_id = o_dict["shot_id"] if o.shot_id in observing_images: logger.warning( "GCP {} has multiple observations in image {}".format( point.id, o.shot_id ) ) observing_images.add(o.shot_id) if "projection" in o_dict: o.projection = np.array(o_dict["projection"]) observations.append(o) point.observations = observations points.append(point) return points
def test_gcp(): gcp = [] for i in range(0, 10): p = pymap.GroundControlPoint() p.id = "p" + str(i) o1 = pymap.GroundControlPointObservation() o1.shot_id = "p1" o2 = pymap.GroundControlPointObservation() o2.shot_id = "p2" obs = [o1, o2] p.observations = obs gcp.append(p) assert p.observations[0].shot_id == "p1" assert p.observations[1].shot_id == "p2" p.add_observation(o2) p.add_observation(o2) assert len(p.observations) == 4 for pt in gcp: assert pt.observations[0].shot_id == "p1" assert pt.observations[1].shot_id == "p2"
def _read_gcp_list_lines(lines, projection, reference, exif): points = {} for line in lines: words = line.split(None, 5) easting, northing, alt, pixel_x, pixel_y = map(float, words[:5]) shot_id = words[5].strip() key = (easting, northing, alt) if key in points: point = points[key] else: # Convert 3D coordinates if np.isnan(alt): alt = 0 has_altitude = False else: has_altitude = True if projection is not None: lon, lat = projection(easting, northing, inverse=True) else: lon, lat = easting, northing point = pymap.GroundControlPoint() point.id = "unnamed-%d" % len(points) point.lla = {"latitude": lat, "longitude": lon, "altitude": alt} point.has_altitude = has_altitude if reference: x, y, z = reference.to_topocentric(lat, lon, alt) point.coordinates.value = np.array([x, y, z]) else: point.coordinates.reset() points[key] = point # Convert 2D coordinates d = exif[shot_id] coordinates = features.normalized_image_coordinates( np.array([[pixel_x, pixel_y]]), d["width"], d["height"] )[0] o = pymap.GroundControlPointObservation() o.shot_id = shot_id o.projection = coordinates point.add_observation(o) return list(points.values())
def read_ground_control_points(fileobj, reference): """Read ground control points from json file. Returns list of types.GroundControlPoint. """ obj = json_load(fileobj) points = [] for point_dict in obj["points"]: point = pymap.GroundControlPoint() point.id = point_dict["id"] lla = point_dict.get("position") if lla: point.lla = lla point.has_altitude = "altitude" in point.lla if reference: point.coordinates.value = reference.to_topocentric( point.lla["latitude"], point.lla["longitude"], point.lla.get("altitude", 0), ) else: point.coordinates.reset() observations = [] observing_images = set() for o_dict in point_dict["observations"]: o = pymap.GroundControlPointObservation() o.shot_id = o_dict["shot_id"] if o.shot_id in observing_images: logger.warning( "GCP {} has multiple observations in image {}".format( point.id, o.shot_id ) ) observing_images.add(o.shot_id) if "projection" in o_dict: o.projection = np.array(o_dict["projection"]) observations.append(o) point.observations = observations points.append(point) return points
def generate_track_data( reconstruction: types.Reconstruction, maximum_depth: float, projection_noise: float, gcp_noise: Tuple[float, float], gcps_count: Optional[int], gcp_shift: Optional[np.ndarray], on_disk_features_filename: Optional[str], ) -> Tuple[ sd.SyntheticFeatures, pymap.TracksManager, Dict[str, pymap.GroundControlPoint] ]: """Generate projection data from a reconstruction, considering a maximum viewing depth and gaussian noise added to the ideal projections. Returns feature/descriptor/color data per shot and a tracks manager object. """ tracks_manager = pymap.TracksManager() feature_data_type = np.float32 desc_size = 128 non_zeroes = 5 points_ids = list(reconstruction.points) points_coordinates = [p.coordinates for p in reconstruction.points.values()] points_colors = [p.color for p in reconstruction.points.values()] # generate random descriptors per point track_descriptors = [] for _ in points_coordinates: descriptor = np.zeros(desc_size) for _ in range(non_zeroes): index = np.random.randint(0, desc_size) descriptor[index] = np.random.random() * 255 track_descriptors.append(descriptor.round().astype(feature_data_type)) # should speed-up projection queries points_tree = spatial.cKDTree(points_coordinates) start = time.time() features = sd.SyntheticFeatures(on_disk_features_filename) default_scale = 0.004 for index, (shot_index, shot) in enumerate(reconstruction.shots.items()): # query all closest points neighbors = list( sorted(points_tree.query_ball_point(shot.pose.get_origin(), maximum_depth)) ) # project them projections = shot.project_many( np.array([points_coordinates[c] for c in neighbors]) ) # shot constants center = shot.pose.get_origin() z_axis = shot.pose.get_rotation_matrix()[2] is_panorama = pygeometry.Camera.is_panorama(shot.camera.projection_type) perturbation = float(projection_noise) / float( max(shot.camera.width, shot.camera.height) ) sigmas = np.array([perturbation, perturbation]) # pre-generate random perturbations perturbations = np.random.normal(0.0, sigmas, (len(projections), 2)) # run and check valid projections projections_inside = [] descriptors_inside = [] colors_inside = [] for i, (p_id, projection) in enumerate(zip(neighbors, projections)): if not _is_inside_camera(projection, shot.camera): continue point = points_coordinates[p_id] if not is_panorama and not _is_in_front(point, center, z_axis): continue # add perturbation projection += perturbations[i] # push data color = points_colors[p_id] original_id = points_ids[p_id] projections_inside.append([projection[0], projection[1], default_scale]) descriptors_inside.append(track_descriptors[p_id]) colors_inside.append(color) obs = pymap.Observation( projection[0], projection[1], default_scale, color[0], color[1], color[2], len(projections_inside) - 1, ) tracks_manager.add_observation(str(shot_index), str(original_id), obs) features[shot_index] = oft.FeaturesData( np.array(projections_inside), np.array(descriptors_inside), np.array(colors_inside), None, ) if index % 100 == 0: logger.info( f"Flushing images # {index} ({(time.time() - start)/(index+1)} sec. per image" ) features.sync() gcps = {} if gcps_count is not None and gcp_shift is not None: all_track_ids = list(tracks_manager.get_track_ids()) gcps_ids = [ all_track_ids[i] for i in np.random.randint(len(all_track_ids) - 1, size=gcps_count) ] sigmas_gcp = np.random.normal( 0.0, np.array([gcp_noise[0], gcp_noise[0], gcp_noise[1]]), (len(gcps_ids), 3), ) for i, gcp_id in enumerate(gcps_ids): point = reconstruction.points[gcp_id] gcp = pymap.GroundControlPoint() gcp.id = f"gcp-{gcp_id}" enu = point.coordinates + gcp_shift + sigmas_gcp[i] lat, lon, alt = reconstruction.reference.to_lla(*enu) gcp.lla = {"latitude": lat, "longitude": lon, "altitude": alt} gcp.has_altitude = True for shot_id, obs in tracks_manager.get_track_observations(gcp_id).items(): o = pymap.GroundControlPointObservation() o.shot_id = shot_id o.projection = obs.point gcp.add_observation(o) gcps[gcp.id] = gcp return features, tracks_manager, gcps