示例#1
0
    def triangulate(
        self, track_2d: SfmTrack2d
    ) -> Tuple[Optional[SfmTrack], Optional[float], bool]:
        """Triangulates 3D point according to the configured triangulation mode.

        Args:
            track: feature track from which measurements are to be extracted

        Returns:
            track with inlier measurements and 3D landmark. None returned if triangulation fails or has high error.
            avg_track_reproj_error: reprojection error of 3d triangulated point to each image plane
                Note: this may be "None" if the 3d point could not be triangulated successfully
                due to a cheirality exception or insufficient number of RANSAC inlier measurements
            is_cheirality_failure: boolean representing whether the selected 2d measurements lead
                to a cheirality exception upon triangulation
        """
        if self.mode in [
                TriangulationParam.RANSAC_SAMPLE_UNIFORM,
                TriangulationParam.RANSAC_SAMPLE_BIASED_BASELINE,
                TriangulationParam.RANSAC_TOPK_BASELINES,
        ]:
            best_inliers = self.execute_ransac_variant(track_2d)

        elif self.mode == TriangulationParam.NO_RANSAC:
            best_inliers = np.ones(len(track_2d.measurements),
                                   dtype=bool)  # all marked as inliers

        inlier_idxs = (np.where(best_inliers)[0]).tolist()

        is_cheirality_failure = False
        if len(inlier_idxs) < 2:
            return None, None, is_cheirality_failure

        inlier_track = track_2d.select_subset(inlier_idxs)

        camera_track, measurement_track = self.extract_measurements(
            inlier_track)
        try:
            triangulated_pt = gtsam.triangulatePoint3(
                camera_track,
                measurement_track,
                rank_tol=SVD_DLT_RANK_TOL,
                optimize=True,
            )
        except RuntimeError:
            is_cheirality_failure = True
            return None, None, is_cheirality_failure

        # compute reprojection errors for each measurement
        reproj_errors = self.compute_track_reprojection_errors(
            inlier_track.measurements, triangulated_pt)

        # all the measurements should have error < threshold
        if not np.all(reproj_errors < self.reproj_error_thresh):
            return None, reproj_errors.mean(), is_cheirality_failure

        track_3d = SfmTrack(triangulated_pt)
        for i, uv in inlier_track.measurements:
            track_3d.add_measurement(i, uv)

        avg_track_reproj_error = reproj_errors.mean()
        return track_3d, avg_track_reproj_error, is_cheirality_failure
示例#2
0
    def triangulate(
        self, track_2d: SfmTrack2d
    ) -> Tuple[Optional[SfmTrack], Optional[float], TriangulationExitCode]:
        """Triangulates 3D point according to the configured triangulation mode.

        Args:
            track: feature track from which measurements are to be extracted

        Returns:
            track with inlier measurements and 3D landmark. None returned if triangulation fails or has high error.
            avg_track_reproj_error: reprojection error of 3d triangulated point to each image plane
                Note: this may be "None" if the 3d point could not be triangulated successfully
                due to a cheirality exception or insufficient number of RANSAC inlier measurements
            is_cheirality_failure: boolean representing whether the selected 2d measurements lead
                to a cheirality exception upon triangulation
        """
        # Check if we will run RANSAC, or not.
        if self.options.mode in [
                TriangulationSamplingMode.RANSAC_SAMPLE_UNIFORM,
                TriangulationSamplingMode.RANSAC_SAMPLE_BIASED_BASELINE,
                TriangulationSamplingMode.RANSAC_TOPK_BASELINES,
        ]:
            best_inliers = self.execute_ransac_variant(track_2d)
        elif self.options.mode == TriangulationSamplingMode.NO_RANSAC:
            best_inliers = np.ones(len(track_2d.measurements),
                                   dtype=bool)  # all marked as inliers

        # Verify we have at least 2 inliers.
        inlier_idxs = (np.where(best_inliers)[0]).tolist()
        if len(inlier_idxs) < 2:
            return None, None, TriangulationExitCode.INLIERS_UNDERCONSTRAINED

        # Extract keypoint measurements corresponding to inlier indices.
        inlier_track = track_2d.select_subset(inlier_idxs)
        track_cameras, track_measurements = self.extract_measurements(
            inlier_track)

        # Exit if we do not have at least 2 measurements in cameras with estimated poses.
        if track_cameras is None:
            return None, None, TriangulationExitCode.POSES_UNDERCONSTRAINED

        # Triangulate and check for cheirality failure from GTSAM.
        try:
            triangulated_pt = gtsam.triangulatePoint3(
                track_cameras,
                track_measurements,
                rank_tol=SVD_DLT_RANK_TOL,
                optimize=True,
            )
        except RuntimeError:
            return None, None, TriangulationExitCode.CHEIRALITY_FAILURE

        # Compute reprojection errors for each measurement.
        reproj_errors, avg_track_reproj_error = reproj_utils.compute_point_reprojection_errors(
            self.track_camera_dict, triangulated_pt, inlier_track.measurements)

        # Check that all measurements are within reprojection error threshold.
        if not np.all(
                reproj_errors.flatten() < self.options.reproj_error_threshold):
            return None, avg_track_reproj_error, TriangulationExitCode.EXCEEDS_REPROJ_THRESH

        # Create a gtsam.SfmTrack with the triangulated 3d point and associated 2d measurements.
        track_3d = SfmTrack(triangulated_pt)
        for i, uv in inlier_track.measurements:
            track_3d.addMeasurement(i, uv)

        return track_3d, avg_track_reproj_error, TriangulationExitCode.SUCCESS