示例#1
0
def reproject_gcps(gcps: List[pymap.GroundControlPoint], reconstruction: types.Reconstruction, reproj_threshold):
    output = {}
    for gcp in gcps:
        point = multiview.triangulate_gcp(
            gcp,
            reconstruction.shots,
            reproj_threshold=reproj_threshold,
            min_ray_angle_degrees=0.1,
        )
        output[gcp.id] = {}
        n_obs = len(gcp.observations)
        if point is None:
            logger.info(f"Could not triangulate {gcp.id} with {n_obs} annotations")
            continue
        for observation in gcp.observations:
            lat, lon, alt = reconstruction.reference.to_lla(*point)
            output[gcp.id][observation.shot_id] = {"lla": [lat, lon, alt], "error": 0}
            if observation.shot_id not in reconstruction.shots:
                continue
            shot = reconstruction.shots[observation.shot_id]
            reproj = shot.project(point)
            error = np.linalg.norm(reproj - observation.projection)
            output[gcp.id][observation.shot_id].update(
                {
                    "error": error,
                    "reprojection": [reproj[0], reproj[1]],
                }
            )
    return output
示例#2
0
def gcp_errors(data: DataSetBase, reconstructions):
    all_errors = []

    gcp = data.load_ground_control_points()
    if not gcp:
        return {}

    all_errors = []
    for gcp in gcp:
        if not gcp.coordinates.has_value:
            continue

        for rec in reconstructions:
            triangulated = multiview.triangulate_gcp(gcp, rec.shots, 1.0, 0.1)
            if triangulated is None:
                continue
            else:
                break

        # pyre-fixme[61]: `triangulated` may not be initialized here.
        if triangulated is None:
            continue
        all_errors.append(triangulated - gcp.coordinates.value)

    return _gps_gcp_errors_stats(all_errors)
示例#3
0
def gcp_errors(data: DataSetBase,
               reconstructions: List[types.Reconstruction]) -> Dict[str, Any]:
    all_errors = []

    reference = data.load_reference()
    gcps = data.load_ground_control_points()
    if not gcps:
        return {}

    all_errors = []
    for gcp in gcps:
        if not gcp.lla:
            continue

        triangulated = None
        for rec in reconstructions:
            triangulated = multiview.triangulate_gcp(gcp, rec.shots, 1.0, 0.1)
            if triangulated is None:
                continue
            else:
                break

        if triangulated is None:
            continue
        gcp_enu = reference.to_topocentric(*gcp.lla_vec)
        all_errors.append(triangulated - gcp_enu)

    return _gps_gcp_errors_stats(np.array(all_errors))
示例#4
0
def add_gcp_to_bundle(ba, gcp, gcp_std, shots):
    """Add Ground Control Points constraints to the bundle problem."""
    for point in gcp:
        point_id = "gcp-" + point.id

        coordinates = multiview.triangulate_gcp(
            point,
            shots,
            reproj_threshold=1,
            min_ray_angle_degrees=0.1,
        )
        if coordinates is None:
            if point.coordinates.has_value:
                logger.warning(
                    f"Could not triangulate GCP '{point.id}'."
                    f"Using {point.coordinates.value} (derived from lat,lon)"
                )
                coordinates = point.coordinates.value
            else:
                logger.warning(
                    "Cannot initialize GCP '{}'." "  Ignoring it".format(point.id)
                )
                continue

        ba.add_point(point_id, coordinates, False)

        for observation in point.observations:
            if observation.shot_id in shots:
                ba.add_point_projection_observation(
                    observation.shot_id,
                    point_id,
                    observation.projection,
                    gcp_std,
                )
示例#5
0
def triangulate_gcps(gcps: List[pymap.GroundControlPoint], reconstruction: types.Reconstruction):
    coords = []
    for gcp in gcps:
        res = multiview.triangulate_gcp(
            gcp,
            reconstruction.shots,
            reproj_threshold=1,
            min_ray_angle_degrees=0.1,
        )
        coords.append(res)
    return coords
示例#6
0
def triangulate_gcps(gcps, reconstruction):
    coords = []
    for gcp in gcps:
        res = multiview.triangulate_gcp(
            gcp,
            reconstruction.shots,
            reproj_threshold=1,
            min_ray_angle_degrees=0.1,
        )
        coords.append(res)
    return coords
示例#7
0
def triangulate_all_gcp(reconstruction, gcp):
    """Group and triangulate Ground Control Points seen in 2+ images."""
    triangulated, measured = [], []
    for point in gcp:
        x = multiview.triangulate_gcp(
            point,
            reconstruction.shots,
            reproj_threshold=0.004,
            min_ray_angle_degrees=2.0,
        )
        if x is not None:
            triangulated.append(x)
            measured.append(point.coordinates.value)
    return triangulated, measured
示例#8
0
def gcp_errors(
    candidate: types.Reconstruction, gcps: Dict[str, pymap.GroundControlPoint]
) -> np.ndarray:
    errors = []
    for gcp in gcps.values():
        if not gcp.lla:
            continue

        triangulated = multiview.triangulate_gcp(gcp, candidate.shots, 1.0, 0.1)
        if triangulated is None:
            continue

        gcp_enu = candidate.reference.to_topocentric(*gcp.lla_vec)
        errors.append(triangulated - gcp_enu)
    return np.array(errors)
示例#9
0
文件: align.py 项目: mfkiwl/OpenSfM
def triangulate_all_gcp(
    reconstruction: types.Reconstruction, gcp: List[pymap.GroundControlPoint]
) -> Tuple[List[np.ndarray], List[np.ndarray]]:
    """Group and triangulate Ground Control Points seen in 2+ images."""
    triangulated, measured = [], []
    for point in gcp:
        x = multiview.triangulate_gcp(
            point,
            reconstruction.shots,
            reproj_threshold=0.004,
            min_ray_angle_degrees=2.0,
        )
        if x is not None:
            triangulated.append(x)
            point_enu = reconstruction.reference.to_topocentric(*point.lla_vec)
            measured.append(point_enu)
    return triangulated, measured
示例#10
0
def add_gcp_to_bundle(
    ba: orec.pybundle.BundleAdjuster,
    reference: types.TopocentricConverter,
    gcp: List[pymap.GroundControlPoint],
    gcp_std,
    shots,
):
    """Add Ground Control Points constraints to the bundle problem."""
    for point in gcp:
        point_id = "gcp-" + point.id

        coordinates = multiview.triangulate_gcp(
            point,
            shots,
            reproj_threshold=1,
            min_ray_angle_degrees=0.1,
        )
        if coordinates is None:
            if point.lla:
                enu = reference.to_topocentric(*point.lla_vec)
                logger.warning(
                    f"Could not triangulate GCP '{point.id}'."
                    f"Using {enu} (derived from lat,lon)"
                )
                coordinates = enu
            else:
                logger.warning(
                    "Cannot initialize GCP '{}'." "  Ignoring it".format(point.id)
                )
                continue

        ba.add_point(point_id, coordinates, False)

        for observation in point.observations:
            if observation.shot_id in shots:
                ba.add_point_projection_observation(
                    observation.shot_id,
                    point_id,
                    observation.projection,
                    gcp_std,
                )
示例#11
0
def _add_gcp_to_bundle(
    ba: pybundle.BundleAdjuster, gcp: List[pymap.GroundControlPoint], shots: List[str]
):
    """Add Ground Control Points constraints to the bundle problem."""
    for point in gcp:
        point_id = "gcp-" + point.id

        coordinates = multiview.triangulate_gcp(
            point,
            shots,
            reproj_threshold=1,
            min_ray_angle_degrees=0.1,
        )
        if coordinates is None:
            if point.coordinates.has_value:
                coordinates = point.coordinates.value
            else:
                logger.warning(
                    "Cannot initialize GCP '{}'." "  Ignoring it".format(point.id)
                )
                continue

        ba.add_point(point_id, coordinates, False)

        if point.coordinates.has_value:
            point_type = pybundle.XYZ if point.has_altitude else pybundle.XY
            ba.add_point_position_world(
                point_id, point.coordinates.value, 0.1, point_type
            )

        for observation in point.observations:
            if observation.shot_id in shots:
                # TODO(pau): move this to a config or per point parameter.
                scale = 0.0001
                ba.add_point_projection_observation(
                    observation.shot_id,
                    point_id,
                    observation.projection,
                    scale,
                )
示例#12
0
def gcp_errors(data, reconstructions):
    all_errors = []

    gcp = data.load_ground_control_points()
    if not gcp:
        return {}

    all_errors = []
    for gcp in gcp:
        if not gcp.coordinates.has_value:
            continue

        for rec in reconstructions:
            triangulated = multiview.triangulate_gcp(gcp, rec.shots, 1.0, 0.1)
            if triangulated is None:
                continue
            else:
                break

        if triangulated is None:
            continue
        all_errors.append(triangulated - gcp.coordinates.value)

    return _gps_gcp_errors_stats(all_errors)
示例#13
0
def resect_image(im, camera, gcps, reconstruction, data, dst_reconstruction=None):
    """
    Resect an image into a reconstruction based only on GCPs annotations.
    Pass another reconstruction to dst_reconstruction
    if you want the resected points to be added there instead

    Returns:
        The resected shot.
    """
    threshold = 0.01
    min_inliers = 3

    bs, Xs = [], []
    for gcp in gcps:
        obs = _gcp_image_observation(gcp, im)
        if not obs:
            continue
        gcp_3d_coords = multiview.triangulate_gcp(
            gcp,
            reconstruction.shots,
            reproj_threshold=1,
            min_ray_angle_degrees=0.1,
        )
        if gcp_3d_coords is None:
            continue

        b = camera.pixel_bearing(obs.projection)
        bs.append(b)
        Xs.append(gcp_3d_coords)
    bs = np.array(bs)
    Xs = np.array(Xs)

    if len(bs) < min_inliers:
        logger.info(f"Not enough annotations to resect image {im}")
        return None

    T = multiview.absolute_pose_ransac(bs, Xs, threshold, 1000, 0.999)
    R = T[:, :3]
    t = T[:, 3]

    reprojected_bs = R.T.dot((Xs - t).T).T
    reprojected_bs /= np.linalg.norm(reprojected_bs, axis=1)[:, np.newaxis]

    inliers = np.linalg.norm(reprojected_bs - bs, axis=1) < threshold
    ninliers = int(sum(inliers))

    logger.info(f"{im} resection inliers: {ninliers} / {len(bs)}")

    if dst_reconstruction is None:
        dst_reconstruction = reconstruction

    if ninliers >= min_inliers:
        R = T[:, :3].T
        t = -R.dot(T[:, 3])
        dst_reconstruction.add_camera(camera)
        shot = dst_reconstruction.create_shot(im, camera.id, pygeometry.Pose(R, t))
        shot.metadata = helpers.get_image_metadata(data, im)
        return shot
    else:
        logger.info(f"Not enough inliers to resect image {im}")
        return None
示例#14
0
文件: stats.py 项目: CosmosHua/GLD
def gcp_errors(data: DataSetBase,
               reconstructions: List[types.Reconstruction]) -> Dict[str, Any]:
    all_errors = []

    reference = data.load_reference()
    gcps = data.load_ground_control_points()
    if not gcps:
        return {}

    all_errors = []
    gcp_stats = []

    for gcp in gcps:
        if not gcp.lla:
            continue
        triangulated = None
        for rec in reconstructions:
            triangulated = multiview.triangulate_gcp(gcp, rec.shots, 1.0, 0.1)
            if triangulated is None:
                continue
            else:
                break

        if triangulated is None:
            continue

        gcp_enu = reference.to_topocentric(*gcp.lla_vec)
        e = triangulated - gcp_enu
        all_errors.append(e)

        # Begin computation of GCP stats
        observations = []
        for i, obs in enumerate(gcp.observations):
            if not obs.shot_id in rec.shots:
                continue
            shot = rec.shots[obs.shot_id]

            reprojected = shot.project(gcp_enu)
            annotated = obs.projection

            r_pixel = features.denormalized_image_coordinates(
                np.array([[reprojected[0], reprojected[1]]]),
                shot.camera.width, shot.camera.height)[0]
            r_pixel[0] /= shot.camera.width
            r_pixel[1] /= shot.camera.height

            a_pixel = features.denormalized_image_coordinates(
                np.array([[annotated[0], annotated[1]]]), shot.camera.width,
                shot.camera.height)[0]
            a_pixel[0] /= shot.camera.width
            a_pixel[1] /= shot.camera.height

            observations.append({
                'shot_id': obs.shot_id,
                'annotated': list(a_pixel),
                'reprojected': list(r_pixel)
            })

        gcp_stats.append({
            'id': gcp.id,
            'coordinates': list(gcp_enu),
            'observations': observations,
            'error': list(e)
        })

        # End computation of GCP stats

    with open(
            os.path.join(data.data_path, "stats",
                         "ground_control_points.json"), 'w') as f:
        f.write(json.dumps(gcp_stats, indent=4))

    return _gps_gcp_errors_stats(np.array(all_errors))