in annotation_gui_gcp/run_ba.py [0: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