def colmap_build_sift_map(kapture_path: str, colmap_path: str, colmap_binary: str, colmap_use_cpu: bool, colmap_gpu_index: str, vocab_tree_path: str, point_triangulator_options: List[str], skip_list: List[str], force: bool) -> None: """ Build a colmap model using default SIFT features with the kapture data. :param kapture_path: path to the kapture to use :param colmap_path: path to the colmap build :param colmap_binary: path to the colmap executable :param colmap_use_cpu: to use cpu only (and ignore gpu) or to use also gpu :param colmap_gpu_index: gpu index for sift extractor and mapper :param vocab_tree_path: path to the colmap vocabulary tree file :param point_triangulator_options: options for the point triangulator :param skip_list: list of steps to skip :param force: Silently overwrite kapture files if already exists. """ os.makedirs(colmap_path, exist_ok=True) # Load input files first to make sure it is OK logger.info('loading kapture files...') kapture_data = kapture.io.csv.kapture_from_dir(kapture_path) if not (kapture_data.records_camera and kapture_data.sensors): raise ValueError('records_camera, sensors are mandatory') if not kapture_data.trajectories: logger.info('there are no trajectories, running mapper instead of point_triangulator') if not os.path.isfile(vocab_tree_path): raise ValueError(f'Vocabulary Tree file does not exist: {vocab_tree_path}') # COLMAP does not fully support rigs. if kapture_data.rigs is not None and kapture_data.trajectories is not None: # make sure, rigs are not used in trajectories. logger.info('remove rigs notation.') rigs_remove_inplace(kapture_data.trajectories, kapture_data.rigs) kapture_data.rigs.clear() # Set fixed name for COLMAP database colmap_db_path = path.join(colmap_path, 'colmap.db') image_list_path = path.join(colmap_path, 'images.list') reconstruction_path = path.join(colmap_path, "reconstruction") if 'delete_existing' not in skip_list: safe_remove_file(colmap_db_path, force) safe_remove_file(image_list_path, force) safe_remove_any_path(reconstruction_path, force) os.makedirs(reconstruction_path, exist_ok=True) if 'feature_extract' not in skip_list: logger.info("Step 1: Feature extraction using colmap") with open(image_list_path, 'w') as fid: for timestamp, sensor_id in sorted(kapture_data.records_camera.key_pairs()): fid.write(kapture_data.records_camera[timestamp][sensor_id] + "\n") colmap_lib.run_feature_extractor( colmap_binary, colmap_use_cpu, colmap_gpu_index, colmap_db_path, get_image_fullpath(kapture_path), image_list_path ) # Update cameras in COLMAP: # - use only one camera for all images taken with the same camera (update all camera IDs) # - import camera intrinsics # - import camera pose if 'update_db_cameras' not in skip_list: logger.info("Step 2: Populate COLMAP DB with cameras and poses") colmap_db = COLMAPDatabase.connect(colmap_db_path) database_extra.update_DB_cameras_and_poses(colmap_db, kapture_data) # close db before running colmap processes in order to avoid locks colmap_db.close() # Extract matches with COLMAP if 'matches' not in skip_list: logger.info("Step 3: Compute matches with colmap") colmap_lib.run_vocab_tree_matcher( colmap_binary, colmap_use_cpu, colmap_gpu_index, colmap_db_path, vocab_tree_path) if kapture_data.trajectories is not None: # Generate priors for reconstruction txt_path = path.join(colmap_path, "priors_for_reconstruction") os.makedirs(txt_path, exist_ok=True) if 'priors_for_reconstruction' not in skip_list: logger.info('Step 4: Exporting priors for reconstruction.') colmap_db = COLMAPDatabase.connect(colmap_db_path) database_extra.generate_priors_for_reconstruction(kapture_data, colmap_db, txt_path) colmap_db.close() # Point triangulator reconstruction_path = path.join(colmap_path, "reconstruction") os.makedirs(reconstruction_path, exist_ok=True) if 'triangulation' not in skip_list: logger.info("Step 5: Triangulation") colmap_lib.run_point_triangulator( colmap_binary, colmap_db_path, get_image_fullpath(kapture_path), txt_path, reconstruction_path, point_triangulator_options ) else: # mapper reconstruction_path = path.join(colmap_path, "reconstruction") os.makedirs(reconstruction_path, exist_ok=True) if 'triangulation' not in skip_list: logger.info("Step 5: Triangulation") colmap_lib.run_mapper( colmap_binary, colmap_db_path, get_image_fullpath(kapture_path), None, reconstruction_path, point_triangulator_options ) # use reconstruction 0 as main first_reconstruction = os.path.join(reconstruction_path, '0') files = os.listdir(first_reconstruction) for f in files: shutil.move(os.path.join(first_reconstruction, f), os.path.join(reconstruction_path, f)) shutil.rmtree(first_reconstruction) # run model_converter if 'model_converter' not in skip_list: logger.info("Step 6: Export reconstruction results to txt") colmap_lib.run_model_converter( colmap_binary, reconstruction_path, reconstruction_path )
def colmap_build_map_from_loaded_data(kapture_data: kapture.Kapture, kapture_path: str, colmap_path: str, colmap_binary: str, pairsfile_path: Optional[str], use_colmap_matches_importer: bool, point_triangulator_options: List[str], skip_list: List[str], force: bool) -> None: """ Build a colmap model using custom features with the kapture data. :param kapture_data: kapture data to use :param kapture_path: path to the kapture to use :param colmap_path: path to the colmap build :param colmap_binary: path to the colmap executable :param pairsfile_path: Optional[str], :param use_colmap_matches_importer: bool, :param point_triangulator_options: options for the point triangulator :param skip_list: list of steps to skip :param force: Silently overwrite kapture files if already exists. """ os.makedirs(colmap_path, exist_ok=True) if not (kapture_data.records_camera and kapture_data.sensors and kapture_data.keypoints and kapture_data.matches): raise ValueError('records_camera, sensors, keypoints, matches are mandatory') if not kapture_data.trajectories: logger.info('there are no trajectories, running mapper instead of point_triangulator') # COLMAP does not fully support rigs. if kapture_data.rigs is not None and kapture_data.trajectories is not None: # make sure, rigs are not used in trajectories. logger.info('remove rigs notation.') rigs_remove_inplace(kapture_data.trajectories, kapture_data.rigs) kapture_data.rigs.clear() # Set fixed name for COLMAP database colmap_db_path = path.join(colmap_path, 'colmap.db') reconstruction_path = path.join(colmap_path, "reconstruction") priors_txt_path = path.join(colmap_path, "priors_for_reconstruction") if 'delete_existing' not in skip_list: safe_remove_file(colmap_db_path, force) safe_remove_any_path(reconstruction_path, force) safe_remove_any_path(priors_txt_path, force) os.makedirs(reconstruction_path, exist_ok=True) if 'colmap_db' not in skip_list: logger.info('Using precomputed keypoints and matches') logger.info('Step 1: Export kapture format to colmap') colmap_db = COLMAPDatabase.connect(colmap_db_path) if kapture_data.descriptors is not None: kapture_data.descriptors.clear() database_extra.kapture_to_colmap(kapture_data, kapture_path, colmap_db, export_two_view_geometry=not use_colmap_matches_importer) # close db before running colmap processes in order to avoid locks colmap_db.close() if use_colmap_matches_importer: logger.info('Step 2: Run geometric verification') logger.debug('running colmap matches_importer...') colmap_lib.run_matches_importer_from_kapture( colmap_binary, colmap_use_cpu=True, colmap_gpu_index=None, colmap_db_path=colmap_db_path, kapture_data=kapture_data, force=force ) else: logger.info('Step 2: Run geometric verification - skipped') if kapture_data.trajectories is not None: # Generate priors for reconstruction os.makedirs(priors_txt_path, exist_ok=True) if 'priors_for_reconstruction' not in skip_list: logger.info('Step 3: Exporting priors for reconstruction.') colmap_db = COLMAPDatabase.connect(colmap_db_path) database_extra.generate_priors_for_reconstruction(kapture_data, colmap_db, priors_txt_path) colmap_db.close() # Point triangulator reconstruction_path = path.join(colmap_path, "reconstruction") os.makedirs(reconstruction_path, exist_ok=True) if 'triangulation' not in skip_list: logger.info("Step 4: Triangulation") colmap_lib.run_point_triangulator( colmap_binary, colmap_db_path, get_image_fullpath(kapture_path), priors_txt_path, reconstruction_path, point_triangulator_options ) else: # mapper reconstruction_path = path.join(colmap_path, "reconstruction") os.makedirs(reconstruction_path, exist_ok=True) if 'triangulation' not in skip_list: logger.info("Step 4: Triangulation") colmap_lib.run_mapper( colmap_binary, colmap_db_path, get_image_fullpath(kapture_path), None, reconstruction_path, point_triangulator_options ) # use reconstruction 0 as main first_reconstruction = os.path.join(reconstruction_path, '0') files = os.listdir(first_reconstruction) for f in files: shutil.move(os.path.join(first_reconstruction, f), os.path.join(reconstruction_path, f)) shutil.rmtree(first_reconstruction) # run model_converter if 'model_converter' not in skip_list: logger.info("Step 5: Export reconstruction results to txt") colmap_lib.run_model_converter( colmap_binary, reconstruction_path, reconstruction_path )
def reconstruct(self, kapture_data): os.makedirs(self._colmap_path, exist_ok=True) if not (kapture_data.records_camera and kapture_data.sensors and kapture_data.keypoints and kapture_data.matches and kapture_data.trajectories): raise ValueError( 'records_camera, sensors, keypoints, matches, trajectories are mandatory' ) # Set fixed name for COLMAP database colmap_db_path = path.join(self._colmap_path, 'colmap.db') reconstruction_path = path.join(self._colmap_path, "reconstruction") priors_txt_path = path.join(self._colmap_path, "priors_for_reconstruction") safe_remove_file(colmap_db_path, True) safe_remove_any_path(reconstruction_path, True) safe_remove_any_path(priors_txt_path, True) os.makedirs(reconstruction_path, exist_ok=True) # COLMAP does not fully support rigs. print("Step 1. Remove rigs") if kapture_data.rigs is not None and kapture_data.trajectories is not None: # make sure, rigs are not used in trajectories. rigs_remove_inplace(kapture_data.trajectories, kapture_data.rigs) kapture_data.rigs.clear() print("Step 2. Kapture to colmap") colmap_db = COLMAPDatabase.connect(colmap_db_path) database_extra.kapture_to_colmap(kapture_data, kapture_data.kapture_path, colmap_db, export_two_view_geometry=True) colmap_db.close() os.makedirs(priors_txt_path, exist_ok=True) print("Step 3. Generate priors for reconstruction") colmap_db = COLMAPDatabase.connect(colmap_db_path) database_extra.generate_priors_for_reconstruction( kapture_data, colmap_db, priors_txt_path) colmap_db.close() # Point triangulator print("Step 4. Point triangulator") reconstruction_path = path.join(self._colmap_path, "reconstruction") os.makedirs(reconstruction_path, exist_ok=True) run_point_triangulator(self._colmap_binary, colmap_db_path, kapture_data.image_path, priors_txt_path, reconstruction_path, self._point_triangulator_options) print("Step 5. Model converter") run_model_converter(self._colmap_binary, reconstruction_path, reconstruction_path) print("Step 5. Reconstruction import") points3d, observations = import_from_colmap_points3d_txt( os.path.join(reconstruction_path, "points3D.txt"), kapture_data.image_names) kapture_data.observations = observations kapture_data.points3d = points3d