def merge_two_reconstructions(r1, r2, config, threshold=1): """Merge two reconstructions with common tracks.""" t1, t2 = r1.points, r2.points common_tracks = list(set(t1) & set(t2)) if len(common_tracks) > 6: # Estimate similarity transform p1 = np.array([t1[t].coordinates for t in common_tracks]) p2 = np.array([t2[t].coordinates for t in common_tracks]) T, inliers = multiview.fit_similarity_transform(p1, p2, max_iterations=1000, threshold=threshold) if len(inliers) >= 10: s, A, b = multiview.decompose_similarity_transform(T) r1p = r1 align.apply_similarity(r1p, s, A, b) r = r2 r.shots.update(r1p.shots) r.points.update(r1p.points) align.align_reconstruction(r, None, config) return [r] else: return [r1, r2] else: return [r1, r2]
def merge_two_reconstructions(r1, r2, config, threshold=1): """Merge two reconstructions with common tracks.""" t1, t2 = r1.points, r2.points common_tracks = list(set(t1) & set(t2)) if len(common_tracks) > 6: # Estimate similarity transform p1 = np.array([t1[t].coordinates for t in common_tracks]) p2 = np.array([t2[t].coordinates for t in common_tracks]) T, inliers = multiview.fit_similarity_transform( p1, p2, max_iterations=1000, threshold=threshold) if len(inliers) >= 10: s, A, b = multiview.decompose_similarity_transform(T) r1p = r1 align.apply_similarity(r1p, s, A, b) r = r2 r.shots.update(r1p.shots) r.points.update(r1p.points) align.align_reconstruction(r, None, config) return [r] else: return [r1, r2] else: return [r1, r2]
def reconstruct(problem, data): """ Reconstruct 3D scene and save to the given DataSet. Relies on the feature matches and tracks graph to be already computed. Returns the reconstruction. """ graph = data.load_tracks_graph() reco_triple = problem.get_reconstruction_order() reco = bootstrap_reconstruction( problem, data, graph, reco_triple[0][0], reco_triple[0][1], reco_triple[0][2]) for prev_img, next_img, hint_forward in reco_triple[1:]: result = grow_reconstruction( problem, data, graph, reco, prev_img, next_img, hint_forward) if not result: print "Stopping because grow_reconstruction failed..." break # Give each 3D point in the reconstruction a color. reconstruction.paint_reconstruction(data, graph, reco) # Align the reconstruction with the ground plane for a sane visualization. align.align_reconstruction(reco, None, data.config) data.save_reconstruction([reco]) return reco
def merge_two_reconstructions(r1, r2, config, threshold=1): """Merge two reconstructions with common tracks IDs.""" common_tracks = list(set(r1.points) & set(r2.points)) worked, T, inliers = align_two_reconstruction(r1, r2, common_tracks, threshold) if worked and len(inliers) >= 10: s, A, b = multiview.decompose_similarity_transform(T) r1p = r1 apply_similarity(r1p, s, A, b) r = r2 r.shots.update(r1p.shots) r.points.update(r1p.points) align_reconstruction(r, None, config) return [r] else: return [r1, r2]
def merge_two_reconstructions(r1, r2, config, threshold=1): """Merge two reconstructions with common tracks IDs.""" common_tracks = list(set(r1.points) & set(r2.points)) worked, T, inliers = align_two_reconstruction( r1, r2, common_tracks, threshold) if worked and len(inliers) >= 10: s, A, b = multiview.decompose_similarity_transform(T) r1p = r1 apply_similarity(r1p, s, A, b) r = r2 r.shots.update(r1p.shots) r.points.update(r1p.points) align_reconstruction(r, None, config) return [r] else: return [r1, r2]
def grow_reconstruction(data, graph, reconstruction, images, gcp): """Incrementally add shots to an initial reconstruction.""" bundle(graph, reconstruction, None, data.config) align.align_reconstruction(reconstruction, gcp, data.config) should_bundle = ShouldBundle(data, reconstruction) should_retriangulate = ShouldRetriangulate(data, reconstruction) while True: if data.config.get('save_partial_reconstructions', False): paint_reconstruction(data, graph, reconstruction) data.save_reconstruction( [reconstruction], 'reconstruction.{}.json'.format( datetime.datetime.now().isoformat().replace(':', '_'))) common_tracks = reconstructed_points_for_images( graph, reconstruction, images) if not common_tracks: break logger.info("-------------------------------------------------------") for image, num_tracks in common_tracks: if resect(data, graph, reconstruction, image): logger.info("Adding {0} to the reconstruction".format(image)) images.remove(image) triangulate_shot_features( graph, reconstruction, image, data.config.get('triangulation_threshold', 0.004), data.config.get('triangulation_min_ray_angle', 2.0)) if should_bundle.should(reconstruction): bundle(graph, reconstruction, None, data.config) remove_outliers(graph, reconstruction, data.config) align.align_reconstruction(reconstruction, gcp, data.config) should_bundle.done(reconstruction) else: if data.config['local_bundle_radius'] > 0: bundle_local(graph, reconstruction, None, image, data.config) if should_retriangulate.should(reconstruction): logger.info("Re-triangulating") retriangulate(graph, reconstruction, data.config) bundle(graph, reconstruction, None, data.config) should_retriangulate.done(reconstruction) break else: logger.info("Some images can not be added") break logger.info("-------------------------------------------------------") bundle(graph, reconstruction, gcp, data.config) align.align_reconstruction(reconstruction, gcp, data.config) paint_reconstruction(data, graph, reconstruction) return reconstruction
def grow_reconstruction(data, graph, reconstruction, images, gcp): """Incrementally add shots to an initial reconstruction.""" bundle(graph, reconstruction, None, data.config) align.align_reconstruction(reconstruction, gcp, data.config) should_bundle = ShouldBundle(data, reconstruction) should_retriangulate = ShouldRetriangulate(data, reconstruction) while True: if data.config.get('save_partial_reconstructions', False): paint_reconstruction(data, graph, reconstruction) data.save_reconstruction( reconstruction, 'reconstruction.{}.json'.format( datetime.datetime.now().isoformat().replace(':', '_'))) common_tracks = reconstructed_points_for_images(graph, reconstruction, images) if not common_tracks: break logger.info("-------------------------------------------------------") for image, num_tracks in common_tracks: if resect(data, graph, reconstruction, image): logger.info("Adding {0} to the reconstruction".format(image)) images.remove(image) triangulate_shot_features( graph, reconstruction, image, data.config.get('triangulation_threshold', 0.004), data.config.get('triangulation_min_ray_angle', 2.0)) if should_bundle.should(reconstruction): bundle(graph, reconstruction, None, data.config) remove_outliers(graph, reconstruction, data.config) align.align_reconstruction(reconstruction, gcp, data.config) should_bundle.done(reconstruction) if should_retriangulate.should(reconstruction): logger.info("Re-triangulating") retriangulate(graph, reconstruction, data.config) bundle(graph, reconstruction, None, data.config) should_retriangulate.done(reconstruction) break else: logger.info("Some images can not be added") break logger.info("-------------------------------------------------------") bundle(graph, reconstruction, gcp, data.config) align.align_reconstruction(reconstruction, gcp, data.config) paint_reconstruction(data, graph, reconstruction) print 'Done.' return reconstruction
def grow_reconstruction(data, graph, reconstruction, images, gcp): """Incrementally add shots to an initial reconstruction.""" config = data.config report = {'steps': []} bundle(graph, reconstruction, None, config) remove_outliers(graph, reconstruction, config) align_reconstruction(reconstruction, gcp, config) should_bundle = ShouldBundle(data, reconstruction) should_retriangulate = ShouldRetriangulate(data, reconstruction) while True: if config['save_partial_reconstructions']: paint_reconstruction(data, graph, reconstruction) data.save_reconstruction( [reconstruction], 'reconstruction.{}.json'.format( datetime.datetime.now().isoformat().replace(':', '_'))) candidates = reconstructed_points_for_images( graph, reconstruction, images) if not candidates: break logger.info("-------------------------------------------------------") threshold = data.config['resection_threshold'] min_inliers = data.config['resection_min_inliers'] for image, num_tracks in candidates: camera = reconstruction.cameras[data.load_exif(image)['camera']] metadata = get_image_metadata(data, image) ok, resrep = resect(graph, reconstruction, image, camera, metadata, threshold, min_inliers) if not ok: continue bundle_single_view(graph, reconstruction, image, data.config) logger.info("Adding {0} to the reconstruction".format(image)) step = { 'image': image, 'resection': resrep, 'memory_usage': current_memory_usage() } report['steps'].append(step) images.remove(image) np_before = len(reconstruction.points) triangulate_shot_features(graph, reconstruction, image, config) np_after = len(reconstruction.points) step['triangulated_points'] = np_after - np_before if should_retriangulate.should(): logger.info("Re-triangulating") b1rep = bundle(graph, reconstruction, None, config) rrep = retriangulate(graph, reconstruction, config) b2rep = bundle(graph, reconstruction, None, config) remove_outliers(graph, reconstruction, config) align_reconstruction(reconstruction, gcp, config) step['bundle'] = b1rep step['retriangulation'] = rrep step['bundle_after_retriangulation'] = b2rep should_retriangulate.done() should_bundle.done() elif should_bundle.should(): brep = bundle(graph, reconstruction, None, config) remove_outliers(graph, reconstruction, config) align_reconstruction(reconstruction, gcp, config) step['bundle'] = brep should_bundle.done() elif config['local_bundle_radius'] > 0: brep = bundle_local(graph, reconstruction, None, image, config) remove_outliers(graph, reconstruction, config) step['local_bundle'] = brep break else: logger.info("Some images can not be added") break logger.info("-------------------------------------------------------") bundle(graph, reconstruction, gcp, config) remove_outliers(graph, reconstruction, config) align_reconstruction(reconstruction, gcp, config) paint_reconstruction(data, graph, reconstruction) return reconstruction, report
def bootstrap_reconstruction( data: DataSetBase, tracks_manager: pymap.TracksManager, im1: str, im2: str, p1: np.ndarray, p2: np.ndarray, ) -> Tuple[Optional[types.Reconstruction], Dict[str, Any]]: """Start a reconstruction using two shots.""" logger.info("Starting reconstruction with {} and {}".format(im1, im2)) report: Dict[str, Any] = { "image_pair": (im1, im2), "common_tracks": len(p1), } camera_priors = data.load_camera_models() camera1 = camera_priors[data.load_exif(im1)["camera"]] camera2 = camera_priors[data.load_exif(im2)["camera"]] threshold = data.config["five_point_algo_threshold"] min_inliers = data.config["five_point_algo_min_inliers"] iterations = data.config["five_point_refine_rec_iterations"] R, t, inliers, report[ "two_view_reconstruction"] = two_view_reconstruction_general( p1, p2, camera1, camera2, threshold, iterations) logger.info("Two-view reconstruction inliers: {} / {}".format( len(inliers), len(p1))) if len(inliers) <= 5: report["decision"] = "Could not find initial motion" logger.info(report["decision"]) return None, report rig_camera_priors = data.load_rig_cameras() rig_assignments = data.load_rig_assignments_per_image() reconstruction = types.Reconstruction() reconstruction.reference = data.load_reference() reconstruction.cameras = camera_priors reconstruction.rig_cameras = rig_camera_priors new_shots = add_shot(data, reconstruction, rig_assignments, im1, pygeometry.Pose()) if im2 not in new_shots: new_shots |= add_shot(data, reconstruction, rig_assignments, im2, pygeometry.Pose(R, t)) align_reconstruction(reconstruction, None, data.config) triangulate_shot_features(tracks_manager, reconstruction, new_shots, data.config) logger.info("Triangulated: {}".format(len(reconstruction.points))) report["triangulated_points"] = len(reconstruction.points) if len(reconstruction.points) < min_inliers: report["decision"] = "Initial motion did not generate enough points" logger.info(report["decision"]) return None, report to_adjust = {s for s in new_shots if s != im1} bundle_shot_poses(reconstruction, to_adjust, camera_priors, rig_camera_priors, data.config) retriangulate(tracks_manager, reconstruction, data.config) if len(reconstruction.points) < min_inliers: report[ "decision"] = "Re-triangulation after initial motion did not generate enough points" logger.info(report["decision"]) return None, report bundle_shot_poses(reconstruction, to_adjust, camera_priors, rig_camera_priors, data.config) report["decision"] = "Success" report["memory_usage"] = current_memory_usage() return reconstruction, report
def grow_reconstruction( data: DataSetBase, tracks_manager: pymap.TracksManager, reconstruction: types.Reconstruction, images: Set[str], gcp: List[pymap.GroundControlPoint], ) -> Tuple[types.Reconstruction, Dict[str, Any]]: """Incrementally add shots to an initial reconstruction.""" config = data.config report = {"steps": []} camera_priors = data.load_camera_models() rig_camera_priors = data.load_rig_cameras() paint_reconstruction(data, tracks_manager, reconstruction) align_reconstruction(reconstruction, gcp, config) bundle(reconstruction, camera_priors, rig_camera_priors, None, config) remove_outliers(reconstruction, config) paint_reconstruction(data, tracks_manager, reconstruction) should_bundle = ShouldBundle(data, reconstruction) should_retriangulate = ShouldRetriangulate(data, reconstruction) while True: if config["save_partial_reconstructions"]: paint_reconstruction(data, tracks_manager, reconstruction) data.save_reconstruction( [reconstruction], "reconstruction.{}.json".format( datetime.datetime.now().isoformat().replace(":", "_")), ) candidates = reconstructed_points_for_images(tracks_manager, reconstruction, images) if not candidates: break logger.info("-------------------------------------------------------") threshold = data.config["resection_threshold"] min_inliers = data.config["resection_min_inliers"] for image, _ in candidates: ok, new_shots, resrep = resect( data, tracks_manager, reconstruction, image, threshold, min_inliers, ) if not ok: continue images -= new_shots bundle_shot_poses( reconstruction, new_shots, camera_priors, rig_camera_priors, data.config, ) logger.info( f"Adding {' and '.join(new_shots)} to the reconstruction") step = { "images": list(new_shots), "resection": resrep, "memory_usage": current_memory_usage(), } report["steps"].append(step) np_before = len(reconstruction.points) triangulate_shot_features(tracks_manager, reconstruction, new_shots, config) np_after = len(reconstruction.points) step["triangulated_points"] = np_after - np_before if should_retriangulate.should(): logger.info("Re-triangulating") align_reconstruction(reconstruction, gcp, config) b1rep = bundle(reconstruction, camera_priors, rig_camera_priors, None, config) rrep = retriangulate(tracks_manager, reconstruction, config) b2rep = bundle(reconstruction, camera_priors, rig_camera_priors, None, config) remove_outliers(reconstruction, config) step["bundle"] = b1rep step["retriangulation"] = rrep step["bundle_after_retriangulation"] = b2rep should_retriangulate.done() should_bundle.done() elif should_bundle.should(): align_reconstruction(reconstruction, gcp, config) brep = bundle(reconstruction, camera_priors, rig_camera_priors, None, config) remove_outliers(reconstruction, config) step["bundle"] = brep should_bundle.done() elif config["local_bundle_radius"] > 0: bundled_points, brep = bundle_local( reconstruction, camera_priors, rig_camera_priors, None, image, config, ) remove_outliers(reconstruction, config, bundled_points) step["local_bundle"] = brep break else: logger.info("Some images can not be added") break logger.info("-------------------------------------------------------") align_reconstruction(reconstruction, gcp, config) bundle(reconstruction, camera_priors, rig_camera_priors, gcp, config) remove_outliers(reconstruction, config) paint_reconstruction(data, tracks_manager, reconstruction) return reconstruction, report
def grow_reconstruction(data, graph, reconstruction, images, gcp): """Incrementally add shots to an initial reconstruction.""" bundle(graph, reconstruction, None, data.config) # align the reconstruction points to the ground controlling points align.align_reconstruction(reconstruction, gcp, data.config) should_bundle = ShouldBundle(data, reconstruction) should_retriangulate = ShouldRetriangulate(data, reconstruction) bundle_local_neighbour = data.config.get("bundle_local_neighbour", 0) while True: if data.config.get('save_partial_reconstructions', False): paint_reconstruction(data, graph, reconstruction) data.save_reconstruction( [reconstruction], 'reconstruction.{}.json'.format( datetime.datetime.now().isoformat().replace(':', '_'))) # A list of (image, num_point) pairs sorted by decreasing number of points. common_tracks = reconstructed_points_for_images(graph, reconstruction, images) if not common_tracks: break logger.info("-------------------------------------------------------") # go through the order of overlapping most for image, num_tracks in common_tracks: if resect(data, graph, reconstruction, image): logger.info("Adding {0} to the reconstruction".format(image)) images.remove(image) # TODO: looser threshold is better, but we haven't determined which is best triangulate_shot_features( graph, reconstruction, image, 0.032, data.config.get('triangulation_min_ray_angle', 2.0)) ''' triangulate_shot_features( graph, reconstruction, image, data.config.get('triangulation_threshold', 0.004), data.config.get('triangulation_min_ray_angle', 2.0)) ''' if should_bundle.should(reconstruction): if bundle_local_neighbour > 0: bundle_local(graph, reconstruction, data.config, bundle_local_neighbour, None, image) else: bundle(graph, reconstruction, None, data.config) # delete the keypoints with large reprojection errors. # should not be a big problem, since not removing a lot in output remove_outliers(graph, reconstruction, data.config) align.align_reconstruction(reconstruction, gcp, data.config) should_bundle.done(reconstruction) # the default behavior is not retriangulate # TODO: check whether this is needed if should_retriangulate.should(reconstruction): logger.info("Re-triangulating") retriangulate(graph, reconstruction, data.config) if bundle_local_neighbour > 0: bundle_local(graph, reconstruction, data.config, bundle_local_neighbour, None, image) else: bundle(graph, reconstruction, None, data.config) should_retriangulate.done(reconstruction) break else: logger.info("Some images can not be added") break logger.info("-------------------------------------------------------") bundle(graph, reconstruction, gcp, data.config) align.align_reconstruction(reconstruction, gcp, data.config) paint_reconstruction(data, graph, reconstruction) return reconstruction
def grow_reconstruction(data, graph, reconstruction, images, gcp): """Incrementally add shots to an initial reconstruction.""" bundle(graph, reconstruction, None, data.config) align.align_reconstruction(reconstruction, gcp, data.config) should_bundle = ShouldBundle(data, reconstruction) should_retriangulate = ShouldRetriangulate(data, reconstruction) report = { 'steps': [], } while True: if data.config['save_partial_reconstructions']: paint_reconstruction(data, graph, reconstruction) data.save_reconstruction( [reconstruction], 'reconstruction.{}.json'.format( datetime.datetime.now().isoformat().replace(':', '_'))) common_tracks = reconstructed_points_for_images( graph, reconstruction, images) if not common_tracks: break logger.info("-------------------------------------------------------") for image, num_tracks in common_tracks: ok, resrep = resect(data, graph, reconstruction, image) if ok: logger.info("Adding {0} to the reconstruction".format(image)) step = { 'image': image, 'resection': resrep, 'memory_usage': current_memory_usage() } report['steps'].append(step) images.remove(image) np_before = len(reconstruction.points) triangulate_shot_features( graph, reconstruction, image, data.config['triangulation_threshold'], data.config['triangulation_min_ray_angle']) np_after = len(reconstruction.points) step['triangulated_points'] = np_after - np_before if should_bundle.should(reconstruction): brep = bundle(graph, reconstruction, None, data.config) step['bundle'] = brep remove_outliers(graph, reconstruction, data.config) align.align_reconstruction(reconstruction, gcp, data.config) should_bundle.done(reconstruction) else: if data.config['local_bundle_radius'] > 0: brep = bundle_local(graph, reconstruction, None, image, data.config) step['local_bundle'] = brep if should_retriangulate.should(reconstruction): logger.info("Re-triangulating") rrep = retriangulate(graph, reconstruction, data.config) step['retriangulation'] = rrep bundle(graph, reconstruction, None, data.config) should_retriangulate.done(reconstruction) break else: logger.info("Some images can not be added") break logger.info("-------------------------------------------------------") bundle(graph, reconstruction, gcp, data.config) align.align_reconstruction(reconstruction, gcp, data.config) paint_reconstruction(data, graph, reconstruction) return reconstruction, report
def grow_reconstruction(data, tracks_manager, reconstruction, images, camera_priors, gcp): """Incrementally add shots to an initial reconstruction.""" config = data.config report = {"steps": []} align_reconstruction(reconstruction, gcp, config) bundle(reconstruction, camera_priors, None, config) remove_outliers(reconstruction, config) should_bundle = ShouldBundle(data, reconstruction) should_retriangulate = ShouldRetriangulate(data, reconstruction) while True: if config["save_partial_reconstructions"]: paint_reconstruction(data, tracks_manager, reconstruction) data.save_reconstruction( [reconstruction], "reconstruction.{}.json".format( datetime.datetime.now().isoformat().replace(":", "_")), ) candidates = reconstructed_points_for_images(tracks_manager, reconstruction, images) if not candidates: break logger.info("-------------------------------------------------------") threshold = data.config["resection_threshold"] min_inliers = data.config["resection_min_inliers"] for image, _ in candidates: camera = reconstruction.cameras[data.load_exif(image)["camera"]] metadata = get_image_metadata(data, image) ok, resrep = resect( tracks_manager, reconstruction, image, camera, metadata, threshold, min_inliers, ) if not ok: continue bundle_single_view(reconstruction, image, camera_priors, data.config) logger.info("Adding {0} to the reconstruction".format(image)) step = { "image": image, "resection": resrep, "memory_usage": current_memory_usage(), } report["steps"].append(step) images.remove(image) np_before = len(reconstruction.points) triangulate_shot_features(tracks_manager, reconstruction, image, config) np_after = len(reconstruction.points) step["triangulated_points"] = np_after - np_before if should_retriangulate.should(): logger.info("Re-triangulating") align_reconstruction(reconstruction, gcp, config) b1rep = bundle(reconstruction, camera_priors, None, config) rrep = retriangulate(tracks_manager, reconstruction, config) b2rep = bundle(reconstruction, camera_priors, None, config) remove_outliers(reconstruction, config) step["bundle"] = b1rep step["retriangulation"] = rrep step["bundle_after_retriangulation"] = b2rep should_retriangulate.done() should_bundle.done() elif should_bundle.should(): align_reconstruction(reconstruction, gcp, config) brep = bundle(reconstruction, camera_priors, None, config) remove_outliers(reconstruction, config) step["bundle"] = brep should_bundle.done() elif config["local_bundle_radius"] > 0: bundled_points, brep = bundle_local(reconstruction, camera_priors, None, image, config) remove_outliers(reconstruction, config, bundled_points) step["local_bundle"] = brep break else: logger.info("Some images can not be added") break logger.info("-------------------------------------------------------") align_reconstruction(reconstruction, gcp, config) bundle(reconstruction, camera_priors, gcp, config) remove_outliers(reconstruction, config) paint_reconstruction(data, tracks_manager, reconstruction) return reconstruction, report
def grow_reconstruction(data, graph, reconstruction, images, gcp): """Incrementally add shots to an initial reconstruction.""" bundle(graph, reconstruction, None, data.config) align.align_reconstruction(reconstruction, gcp, data.config) should_bundle = ShouldBundle(data, reconstruction) should_retriangulate = ShouldRetriangulate(data, reconstruction) report = { 'steps': [], } while True: if data.config['save_partial_reconstructions']: paint_reconstruction(data, graph, reconstruction) data.save_reconstruction( [reconstruction], 'reconstruction.{}.json'.format( datetime.datetime.now().isoformat().replace(':', '_'))) common_tracks = reconstructed_points_for_images(graph, reconstruction, images) if not common_tracks: break logger.info("-------------------------------------------------------") for image, num_tracks in common_tracks: ok, resrep = resect(data, graph, reconstruction, image) if ok: logger.info("Adding {0} to the reconstruction".format(image)) step = { 'image': image, 'resection': resrep, 'memory_usage': current_memory_usage() } report['steps'].append(step) images.remove(image) np_before = len(reconstruction.points) triangulate_shot_features( graph, reconstruction, image, data.config['triangulation_threshold'], data.config['triangulation_min_ray_angle']) np_after = len(reconstruction.points) step['triangulated_points'] = np_after - np_before if should_bundle.should(reconstruction): brep = bundle(graph, reconstruction, None, data.config) step['bundle'] = brep remove_outliers(graph, reconstruction, data.config) align.align_reconstruction(reconstruction, gcp, data.config) should_bundle.done(reconstruction) else: if data.config['local_bundle_radius'] > 0: brep = bundle_local(graph, reconstruction, None, image, data.config) step['local_bundle'] = brep if should_retriangulate.should(reconstruction): logger.info("Re-triangulating") rrep = retriangulate(graph, reconstruction, data.config) step['retriangulation'] = rrep bundle(graph, reconstruction, None, data.config) should_retriangulate.done(reconstruction) break else: logger.info("Some images can not be added") break logger.info("-------------------------------------------------------") bundle(graph, reconstruction, gcp, data.config) align.align_reconstruction(reconstruction, gcp, data.config) paint_reconstruction(data, graph, reconstruction) return reconstruction, report
def grow_reconstruction( problem, data, graph, reco, im1, im2, hint_forward=False): """ Grow the given reconstruction `reco` by adding a new image `im2` to it. The new image `im2` is initially matched against an image `im1`, which must already exist in the reconstruction. See `custom_two_view_reconstruction` for the meaning of `hint_forward`. Updates the reconstruction in-place and returns `True` on success. """ # FIXME: # - Make DRY with bootstrap_reconstruction; they look similar but they're # different in subtle ways. # - Could probably align once at the end, instead of aligning at every # step. # - Sometimes we get "Termination: NO_CONVERGENCE" from Ceres. Check for # that error case and perhaps run it for more iterations. print "----------------" print "grow_reconstruction({}, {}, hint_forward={})".format( im1, im2, hint_forward) reconstruction.bundle(graph, reco, None, data.config) align.align_reconstruction(reco, None, data.config) assert im1 in reco.shots assert im2 not in reco.shots camera1 = problem.image2camera[im1] camera2 = problem.image2camera[im2] tracks, p1, p2 = matching.common_tracks(graph, im1, im2) print "Common tracks: {}".format(len(tracks)) thresh = data.config.get('five_point_algo_threshold', 0.006) R, t, inliers = custom_two_view_reconstruction( p1, p2, camera1, camera2, thresh, hint_forward) print "grow: R={} t={} len(inliers)={}".format(R, t, len(inliers)) if len(inliers) <= 5: print "grow failed: not enough points in initial reconstruction" return False # Reconstruction is up to scale; set translation to 1. # (This will be corrected later in the bundle adjustment step.) t /= np.linalg.norm(t) assert camera1.id in reco.cameras if camera2.id not in reco.cameras: reco.add_camera(camera2) shot1_pose = reco.shots[im1].pose shot2 = types.Shot() shot2.id = im2 shot2.camera = camera2 shot2.pose = types.Pose(R, t).compose(shot1_pose) shot2.metadata = get_empty_metadata() reco.add_shot(shot2) debug = partial(_debug_short, graph, reco, im1, im2) debug("started with") # FIXME: fail here if im2 does not have enough tracks in common with reco pose_before = deepcopy(reco.shots[im2].pose) reconstruction.bundle_single_view(graph, reco, im2, data.config) # It's possible that bundle_single_view caused hint_forward to be violated. # If that's the case, revert to the pose before bundle_single_view, and # hope that after triangulating the points from `im2`, bundle adjustment # will find a better solution. rel_pose_after = reco.shots[im2].pose.compose( reco.shots[im1].pose.inverse()) t_after_norm = rel_pose_after.translation / np.linalg.norm( rel_pose_after.translation) # print "*** t_after_norm={}".format(t_after_norm) if hint_forward and t_after_norm[2] >= -0.75: # FIXME put const in config print "*** hint_forward violated; undoing bundle_single_view" reco.shots[im2].pose = pose_before rel_pose_after = reco.shots[im2].pose.compose( reco.shots[im1].pose.inverse()) t_after_norm = rel_pose_after.translation / np.linalg.norm( rel_pose_after.translation) print "*** after undo: t_after_norm={}".format(t_after_norm) # print reconstruction.triangulate_shot_features( graph, reco, im2, data.config.get('triangulation_threshold', 0.004), data.config.get('triangulation_min_ray_angle', 2.0)) reconstruction.bundle(graph, reco, None, data.config) reconstruction.remove_outliers(graph, reco, data.config) align.align_reconstruction(reco, None, data.config) reconstruction.retriangulate(graph, reco, data.config) reconstruction.bundle(graph, reco, None, data.config) debug("ended with") return True