def run_consistency_check(mvs_dir, window_radius, depth_range=None): # do forward-backward checking and filtering cmd = 'colmap patch_match_stereo --workspace_path {} \ --PatchMatchStereo.window_radius {} \ --PatchMatchStereo.min_triangulation_angle 5.0 \ --PatchMatchStereo.geom_consistency 1 \ --PatchMatchStereo.use_exist_photom 1 \ --PatchMatchStereo.overwrite 1 \ --PatchMatchStereo.geom_consistency_regularizer 0.3 \ --PatchMatchStereo.geom_consistency_max_cost 3 \ --PatchMatchStereo.filter 1 \ --PatchMatchStereo.filter_min_triangulation_angle 4.99 \ --PatchMatchStereo.filter_min_ncc 0.1 \ --PatchMatchStereo.filter_geom_consistency_max_cost 1 \ --PatchMatchStereo.filter_min_num_consistent 2 \ --PatchMatchStereo.gpu_index={} \ --PatchMatchStereo.num_samples 15 \ --PatchMatchStereo.num_iterations 1'.format(mvs_dir, window_radius, gpu_index) if depth_range is not None: depth_min, depth_max = depth_range other_opts = '--PatchMatchStereo.depth_min {} \ --PatchMatchStereo.depth_max {}'.format(depth_min, depth_max) cmd = '{} {}'.format(cmd, other_opts) run_cmd(cmd)
def run_point_triangulation(img_dir, db_file, out_dir, template_file, tri_merge_max_reproj_error, tri_complete_max_reproj_error, filter_max_reproj_error): if not os.path.exists(out_dir): os.mkdir(out_dir) # create initial poses create_init_files(db_file, template_file, out_dir) # triangulate points cmd = 'colmap point_triangulator --Mapper.ba_refine_principal_point 1 \ --database_path {} \ --image_path {} \ --input_path {} \ --output_path {} \ --Mapper.filter_min_tri_angle 4.99 \ --Mapper.init_max_forward_motion 1e20 \ --Mapper.tri_min_angle 5.00 \ --Mapper.tri_merge_max_reproj_error {} \ --Mapper.tri_complete_max_reproj_error {} \ --Mapper.filter_max_reproj_error {} \ --Mapper.extract_colors 1 \ --Mapper.ba_refine_focal_length 0 \ --Mapper.ba_refine_extra_params 0\ --Mapper.max_extra_param 1e20 \ --Mapper.ba_local_num_images 6 \ --Mapper.ba_local_max_num_iterations 100 \ --Mapper.ba_global_images_ratio 1.0000001\ --Mapper.ba_global_max_num_iterations 100 \ --Mapper.tri_ignore_two_view_tracks 1'.format( db_file, img_dir, out_dir, out_dir, tri_merge_max_reproj_error, tri_complete_max_reproj_error, filter_max_reproj_error) run_cmd(cmd)
def run_sift_matching(img_dir, db_file, camera_model): assert (camera_model == 'PINHOLE' or camera_model == 'PERSPECTIVE') if os.path.exists(db_file): # otherwise colmap will skip sift matching os.remove(db_file) # feature extraction cmd = 'colmap feature_extractor --database_path {} \ --image_path {} \ --ImageReader.camera_model {} \ --SiftExtraction.max_image_size 10000 \ --SiftExtraction.estimate_affine_shape 0 \ --SiftExtraction.domain_size_pooling 1 \ --SiftExtraction.max_num_features 25000 \ --SiftExtraction.num_threads -1 \ --SiftExtraction.use_gpu 1 \ --SiftExtraction.gpu_index {}'.format( db_file, img_dir, camera_model, gpu_index) run_cmd(cmd) # feature matching cmd = 'colmap exhaustive_matcher --database_path {} \ --SiftMatching.guided_matching 1 \ --SiftMatching.num_threads -1 \ --SiftMatching.max_error 3 \ --SiftMatching.max_num_matches 30000 \ --SiftMatching.gpu_index {}'.format( db_file, gpu_index) run_cmd(cmd)
def triangulate_task(track, rpc_models, affine_models, out_file): init = solve_init(track, rpc_models, affine_models) write_to_taskfile(track, rpc_models, init, out_file) # triangulate tmp_file = '{}.result.txt'.format(out_file) run_cmd( '/data2/kz298/satellite_stereo/rpc_triangulate_solver/multi_rpc_triangule/multi_rpc_triangulate {} {}' .format(out_file, tmp_file), disable_log=True) # read result with open(out_file) as fp: lines = fp.readlines() init_point = [float(x) for x in lines[0].strip().split(' ')] # init_err = float(lines[1].strip()) with open(tmp_file) as fp: lines = fp.readlines() final_point = [float(x) for x in lines[0].strip().split(' ')] # final_err = float(lines[1].strip()) # remove tmpfile os.remove(tmp_file) # double check the final_err # init_err = compute_reproj_err(rpc_models, track, init) final_err = compute_reproj_err(rpc_models, track, final_point) # #print('here ceres final_err: {}, python: {}'.format(final_err, tmp)) # assert (np.abs(init_err - final_err) < 0.001) # logging.info('init point: lat,lon,alt={}, reproj. err.: {}'.format(init_point, init_err)) # logging.info('final point: lat,lon,alt={}, reproj. err.: {}'.format(final_point, final_err)) return final_point, final_err
def fuse(colmap_dir): cmd = 'colmap stereo_fusion --workspace_path {colmap_dir}/mvs \ --output_path {colmap_dir}/mvs/fused.ply \ --input_type geometric \ --StereoFusion.min_num_pixels 4\ --StereoFusion.max_reproj_error 2\ --StereoFusion.max_depth_error 1.0\ --StereoFusion.max_normal_error 10'.format( colmap_dir=colmap_dir) run_cmd(cmd)
def run_photometric_mvs(mvs_dir, window_radius, depth_range=None): cmd = 'colmap patch_match_stereo --workspace_path {} \ --PatchMatchStereo.window_radius {}\ --PatchMatchStereo.min_triangulation_angle 5.0 \ --PatchMatchStereo.filter 0 \ --PatchMatchStereo.geom_consistency 0 \ --PatchMatchStereo.gpu_index={} \ --PatchMatchStereo.num_samples 15 \ --PatchMatchStereo.num_iterations 12 \ --PatchMatchStereo.overwrite 1'.format(mvs_dir, window_radius, gpu_index) if depth_range is not None: depth_min, depth_max = depth_range other_opts = '--PatchMatchStereo.depth_min {} \ --PatchMatchStereo.depth_max {}'.format(depth_min, depth_max) cmd = '{} {}'.format(cmd, other_opts) run_cmd(cmd)
def crop_ntf(in_ntf, out_png, ntf_size, bbx_size): (ntf_width, ntf_height) = ntf_size (ul_col, ul_row, width, height) = bbx_size # assert bounding box is completely inside the image assert (ul_col >= 0 and ul_col + width - 1 < ntf_width and ul_row >= 0 and ul_row + height - 1 < ntf_height) logging.info('ntf image to cut: {}, width, height: {}, {}'.format(in_ntf, ntf_width, ntf_height)) logging.info('cut image bounding box, ul_col, ul_row, width, height: {}, {}, {}, {}'.format(ul_col, ul_row, width, height)) logging.info('png image to save: {}'.format(out_png)) # note the coordinate system of .ntf cmd = 'gdal_translate -of png -ot UInt16 -srcwin {} {} {} {} {} {}' \ .format(ul_col, ul_row, width, height, in_ntf, out_png) run_cmd(cmd) os.remove('{}.aux.xml'.format(out_png))
def run_global_ba(in_dir, out_dir, weight): if not os.path.exists(out_dir): os.mkdir(out_dir) # global bundle adjustment # one meter is roughly three pixels, we should square it cmd = 'colmap bundle_adjuster --input_path {in_dir} --output_path {out_dir} \ --BundleAdjustment.max_num_iterations 5000 \ --BundleAdjustment.refine_focal_length 0\ --BundleAdjustment.refine_principal_point 1 \ --BundleAdjustment.refine_extra_params 0 \ --BundleAdjustment.refine_extrinsics 0 \ --BundleAdjustment.function_tolerance 0 \ --BundleAdjustment.gradient_tolerance 0 \ --BundleAdjustment.parameter_tolerance 1e-10 \ --BundleAdjustment.constrain_points 1 \ --BundleAdjustment.constrain_points_loss_weight {weight}'.format( in_dir=in_dir, out_dir=out_dir, weight=weight) run_cmd(cmd)