Ejemplo n.º 1
0
def add_shots_to_reconstruction(
    shots: List[List[str]],
    positions: List[np.ndarray],
    rotations: List[np.ndarray],
    rig_cameras: List[pymap.RigCamera],
    cameras: List[pygeometry.Camera],
    reconstruction: types.Reconstruction,
    sequence_key: str,
):
    for camera in cameras:
        reconstruction.add_camera(camera)

    rec_rig_cameras = []
    for rig_camera in rig_cameras:
        rec_rig_cameras.append(reconstruction.add_rig_camera(rig_camera))

    for i_shots, position, rotation in zip(shots, positions, rotations):
        instance_id = "_".join([s[0] for s in i_shots])
        rig_instance = reconstruction.add_rig_instance(pymap.RigInstance(instance_id))
        rig_instance.pose = pygeometry.Pose(rotation, -rotation.dot(position))

        for shot, camera in zip(i_shots, cameras):
            shot_id = shot[0]
            rig_camera_id = shot[1]
            shot = reconstruction.create_shot(
                shot_id,
                camera.id,
                pose=None,
                rig_camera_id=rig_camera_id,
                rig_instance_id=instance_id,
            )
            shot.metadata.sequence_key.value = sequence_key
Ejemplo n.º 2
0
def add_observation_to_reconstruction(
    tracks_manager: pymap.TracksManager,
    reconstruction: types.Reconstruction,
    shot_id: str,
    track_id: str,
) -> None:
    observation = tracks_manager.get_observation(shot_id, track_id)
    reconstruction.add_observation(shot_id, track_id, observation)
Ejemplo n.º 3
0
def set_gps_bias(
    reconstruction: types.Reconstruction,
    config: Dict[str, Any],
    gcp: List[pymap.GroundControlPoint],
    use_scale: bool,
) -> Optional[Tuple[float, np.ndarray, np.ndarray]]:
    """Compute and set the bias transform of the GPS coordinate system wrt. to the GCP one."""

    # Compute similarity ('gps_bias') that brings the reconstruction on the GCPs ONLY
    gps_bias = compute_reconstruction_similarity(reconstruction, gcp, config,
                                                 False, use_scale)
    if not gps_bias:
        logger.warning(
            "Cannot align on GCPs only, GPS bias won't be compensated.")
        return None

    # Align the reconstruction on GCPs ONLY
    s, A, b = gps_bias
    A_angle_axis = cv2.Rodrigues(A)[0].flatten()
    logger.info(
        f"Applying global bias with scale {s:.5f} / translation {b} / rotation {A_angle_axis}"
    )
    apply_similarity(reconstruction, s, A, b)

    # Compute per camera similarity between the GCP and the shots positions
    per_camera_shots = defaultdict(list)
    for s in reconstruction.shots.values():
        per_camera_shots[s.camera.id].append(s.id)

    per_camera_transform = {}
    for camera_id, shots_id in per_camera_shots.items():

        # As we re-use 'compute_reconstruction_similarity', we need to construct a 'Reconstruction'
        subrec = types.Reconstruction()
        subrec.add_camera(reconstruction.cameras[camera_id])
        for shot_id in shots_id:
            subrec.add_shot(reconstruction.shots[shot_id])
        per_camera_transform[camera_id] = compute_reconstruction_similarity(
            subrec, [], config, True, use_scale)

    if any([True for x in per_camera_transform.values() if not x]):
        logger.warning(
            "Cannot compensate some shots, GPS bias won't be compensated.")
    else:
        for camera_id, transform in per_camera_transform.items():
            s, A, b = transform
            A_angle_axis = cv2.Rodrigues(A)[0].flatten()
            s, A_angle_axis, b = 1.0 / s, -A_angle_axis, -A.T.dot(b) / s
            logger.info(
                f"Camera {camera_id} bias : scale {s:.5f} / translation {b} / rotation {A_angle_axis}"
            )
            camera_bias = pygeometry.Similarity(A_angle_axis, b, s)
            reconstruction.set_bias(camera_id, camera_bias)

    return gps_bias
Ejemplo n.º 4
0
def rig_instance_from_json(
    reconstruction: types.Reconstruction, instance_id: str, obj: Dict[str, Any]
) -> None:
    """
    Read any rig instance from a json shot object
    """
    reconstruction.add_rig_instance(pymap.RigInstance(instance_id))

    pose = pygeometry.Pose()
    pose.rotation = obj["rotation"]
    pose.translation = obj["translation"]
    reconstruction.rig_instances[instance_id].pose = pose
Ejemplo n.º 5
0
def add_shots_to_reconstruction(
    shot_ids: List[str],
    positions: List[np.ndarray],
    rotations: List[np.ndarray],
    camera: pygeometry.Camera,
    reconstruction: types.Reconstruction,
):
    reconstruction.add_camera(camera)
    for shot_id, position, rotation in zip(shot_ids, positions, rotations):
        pose = pygeometry.Pose(rotation)
        pose.set_origin(position)
        reconstruction.create_shot(shot_id, camera.id, pose)
Ejemplo n.º 6
0
def add_points_to_reconstruction(
    points: np.ndarray, color: np.ndarray, reconstruction: types.Reconstruction
):
    shift = len(reconstruction.points)
    for i in range(points.shape[0]):
        point = reconstruction.create_point(str(shift + i), points[i, :])
        point.color = color
Ejemplo n.º 7
0
def retriangulate(
    tracks_manager: pymap.TracksManager,
    reconstruction: types.Reconstruction,
    config: Dict[str, Any],
) -> Dict[str, Any]:
    """Retrianguate all points"""
    chrono = Chronometer()
    report = {}
    report["num_points_before"] = len(reconstruction.points)

    threshold = config["triangulation_threshold"]
    min_ray_angle = config["triangulation_min_ray_angle"]

    reconstruction.points = {}

    all_shots_ids = set(tracks_manager.get_shot_ids())

    triangulator = TrackTriangulator(tracks_manager, reconstruction)
    tracks = set()
    for image in reconstruction.shots.keys():
        if image in all_shots_ids:
            tracks.update(tracks_manager.get_shot_observations(image).keys())
    for track in tracks:
        if config["triangulation_type"] == "ROBUST":
            triangulator.triangulate_robust(track, threshold, min_ray_angle)
        elif config["triangulation_type"] == "FULL":
            triangulator.triangulate(track, threshold, min_ray_angle)

    report["num_points_after"] = len(reconstruction.points)
    chrono.lap("retriangulate")
    report["wall_time"] = chrono.total_time()
    return report
Ejemplo n.º 8
0
def point_from_json(
    reconstruction: types.Reconstruction, key: str, obj: Dict[str, Any]
) -> pymap.Landmark:
    """
    Read a point from a json object
    """
    point = reconstruction.create_point(key, obj["coordinates"])
    point.color = obj["color"]
    return point
Ejemplo n.º 9
0
def get_shot_with_different_camera(
    urec: types.Reconstruction,
    shot: pymap.Shot,
    image_format: str,
) -> pymap.Shot:
    new_shot_id = add_image_format_extension(shot.id, image_format)
    new_shot = urec.create_shot(new_shot_id, shot.camera.id, shot.pose)
    new_shot.metadata = shot.metadata
    return new_shot
Ejemplo n.º 10
0
def add_shot(
    data: DataSetBase,
    reconstruction: types.Reconstruction,
    rig_assignments: Dict[str, Tuple[int, str, List[str]]],
    shot_id: str,
    pose: pygeometry.Pose,
) -> Set[str]:
    """Add a shot to the recontruction.

    In case of a shot belonging to a rig instance, the pose of
    shot will drive the initial pose setup of the rig instance.
    All necessary shots and rig models will be created.
    """

    added_shots = set()
    if shot_id not in rig_assignments:
        camera_id = data.load_exif(shot_id)["camera"]
        shot = reconstruction.create_shot(shot_id, camera_id, pose)
        shot.metadata = get_image_metadata(data, shot_id)
        added_shots = {shot_id}
    else:
        instance_id, _, instance_shots = rig_assignments[shot_id]

        created_shots = {}
        for shot in instance_shots:
            camera_id = data.load_exif(shot)["camera"]
            created_shots[shot] = reconstruction.create_shot(
                shot, camera_id, pygeometry.Pose()
            )
            created_shots[shot].metadata = get_image_metadata(data, shot)

        rig_instance = reconstruction.add_rig_instance(pymap.RigInstance(instance_id))
        for shot in instance_shots:
            _, rig_camera_id, _ = rig_assignments[shot]
            rig_instance.add_shot(
                reconstruction.rig_cameras[rig_camera_id], created_shots[shot]
            )
        rig_instance.update_instance_pose_with_shot(shot_id, pose)
        added_shots = set(instance_shots)

    return added_shots
Ejemplo n.º 11
0
def add_rigs_to_reconstruction(
    shots: List[List[str]],
    positions: List[np.ndarray],
    rotations: List[np.ndarray],
    rig_cameras: List[pymap.RigCamera],
    reconstruction: types.Reconstruction,
):
    rec_rig_cameras = []
    for rig_camera in rig_cameras:
        if rig_camera.id not in reconstruction.rig_cameras:
            rec_rig_cameras.append(reconstruction.add_rig_camera(rig_camera))
        else:
            rec_rig_cameras.append(reconstruction.rig_cameras[rig_camera.id])

    for i, (i_shots, position,
            rotation) in enumerate(zip(shots, positions, rotations)):
        rig_instance = reconstruction.add_rig_instance(pymap.RigInstance(i))
        for j, s in enumerate(i_shots):
            rig_instance.add_shot(rec_rig_cameras[j],
                                  reconstruction.get_shot(s[0]))
        rig_instance.pose = pygeometry.Pose(rotation, -rotation.dot(position))
Ejemplo n.º 12
0
def shot_in_reconstruction_from_json(
    reconstruction: types.Reconstruction,
    key: str,
    obj: Dict[str, Any],
    rig_instance_id: Optional[str] = None,
    rig_camera_id: Optional[str] = None,
    is_pano_shot: bool = False,
) -> pymap.Shot:
    """
    Read shot from a json object and append it to a reconstruction
    """
    pose = pose_from_json(obj)

    if is_pano_shot:
        shot = reconstruction.create_pano_shot(key, obj["camera"], pose)
    else:
        shot = reconstruction.create_shot(
            key, obj["camera"], pose, rig_camera_id, rig_instance_id
        )
    assign_shot_attributes(obj, shot)
    return shot
Ejemplo n.º 13
0
def perspective_views_of_a_panorama(
    spherical_shot: pymap.Shot,
    width: int,
    reconstruction: types.Reconstruction,
    image_format: str,
    rig_instance_count: Iterator[int],
):
    """Create 6 perspective views of a panorama."""
    camera = pygeometry.Camera.create_perspective(0.5, 0.0, 0.0)
    camera.id = "perspective_panorama_camera"
    camera.width = width
    camera.height = width
    reconstruction.add_camera(camera)

    names = ["front", "left", "back", "right", "top", "bottom"]
    rotations = [
        tf.rotation_matrix(-0 * np.pi / 2, (0, 1, 0)),
        tf.rotation_matrix(-1 * np.pi / 2, (0, 1, 0)),
        tf.rotation_matrix(-2 * np.pi / 2, (0, 1, 0)),
        tf.rotation_matrix(-3 * np.pi / 2, (0, 1, 0)),
        tf.rotation_matrix(-np.pi / 2, (1, 0, 0)),
        tf.rotation_matrix(+np.pi / 2, (1, 0, 0)),
    ]

    rig_instance = pymap.RigInstance(next(rig_instance_count))
    rig_instance.pose = spherical_shot.pose

    shots = []
    for name, rotation in zip(names, rotations):
        if name not in reconstruction.rig_cameras:
            rig_camera_pose = pygeometry.Pose()
            rig_camera_pose.set_rotation_matrix(rotation[:3, :3])
            rig_camera = pymap.RigCamera(rig_camera_pose, name)
            reconstruction.add_rig_camera(rig_camera)
        rig_camera = reconstruction.rig_cameras[name]

        shot_id = add_image_format_extension(
            f"{spherical_shot.id}_perspective_view_{name}", image_format
        )
        shot = reconstruction.create_shot(shot_id, camera.id)
        shot.metadata = spherical_shot.metadata
        rig_instance.add_shot(rig_camera, shot)

        shots.append(shot)
    reconstruction.add_rig_instance(rig_instance)

    return shots
Ejemplo n.º 14
0
    def check_merge_partial_reconstructions(self):
        if self.reconstructed():
            data = DataSet(self.opensfm_project_path)
            reconstructions = data.load_reconstruction()
            tracks_manager = data.load_tracks_manager()

            if len(reconstructions) > 1:
                log.ODM_WARNING(
                    "Multiple reconstructions detected (%s), this might be an indicator that some areas did not have sufficient overlap"
                    % len(reconstructions))
                log.ODM_INFO("Attempting merge")

                merged = Reconstruction()
                merged.set_reference(reconstructions[0].reference)

                for ix_r, rec in enumerate(reconstructions):
                    if merged.reference != rec.reference:
                        # Should never happen
                        continue

                    log.ODM_INFO("Merging reconstruction %s" % ix_r)

                    for camera in rec.cameras.values():
                        merged.add_camera(camera)

                    for point in rec.points.values():
                        try:
                            new_point = merged.create_point(
                                point.id, point.coordinates)
                            new_point.color = point.color
                        except RuntimeError as e:
                            log.ODM_WARNING("Cannot merge shot id %s (%s)" %
                                            (shot.id, str(e)))
                            continue

                    for shot in rec.shots.values():
                        merged.add_shot(shot)
                        try:
                            obsdict = tracks_manager.get_shot_observations(
                                shot.id)
                        except RuntimeError:
                            log.ODM_WARNING(
                                "Shot id %s missing from tracks_manager!" %
                                shot.id)
                            continue
                        for track_id, obs in obsdict.items():
                            if track_id in merged.points:
                                merged.add_observation(shot.id, track_id, obs)

                data.save_reconstruction([merged])