opensfm/config.py (158 lines of code) (raw):
import os
from dataclasses import dataclass, asdict
import yaml
@dataclass
class OpenSfMConfig:
##################################
# Params for metadata
##################################
use_exif_size: bool = True
# Treat images from unknown camera models as comming from different cameras
unknown_camera_models_are_different: bool = False
default_focal_prior: float = 0.85
##################################
# Params for features
##################################
# Feature type (AKAZE, SURF, SIFT, HAHOG, ORB)
feature_type: str = "HAHOG"
# If true, apply square root mapping to features
feature_root: bool = True
# If fewer frames are detected, sift_peak_threshold/surf_hessian_threshold is reduced.
feature_min_frames: int = 4000
# Same as above but for panorama images
feature_min_frames_panorama: int = 16000
# Resize the image if its size is larger than specified. Set to -1 for original size
feature_process_size: int = 2048
# Same as above but for panorama images
feature_process_size_panorama: int = 4096
feature_use_adaptive_suppression: bool = False
# Bake segmentation info (class and instance) in the feature data. Thus it is done once for all at extraction time.
features_bake_segmentation: bool = False
##################################
# Params for SIFT
##################################
# Smaller value -> more features
sift_peak_threshold: float = 0.1
# See OpenCV doc
sift_edge_threshold: int = 10
##################################
# Params for SURF
##################################
# Smaller value -> more features
surf_hessian_threshold: float = 3000
# See OpenCV doc
surf_n_octaves: int = 4
# See OpenCV doc
surf_n_octavelayers: int = 2
# See OpenCV doc
surf_upright: int = 0
##################################
# Params for AKAZE (See details in lib/src/third_party/akaze/AKAZEConfig.h)
##################################
# Maximum octave evolution of the image 2^sigma (coarsest scale sigma units)
akaze_omax: int = 4
# Detector response threshold to accept point
akaze_dthreshold: float = 0.001
# Feature type
akaze_descriptor: str = "MSURF"
# Size of the descriptor in bits. 0->Full size
akaze_descriptor_size: int = 0
# Number of feature channels (1,2,3)
akaze_descriptor_channels: int = 3
akaze_kcontrast_percentile: float = 0.7
akaze_use_isotropic_diffusion: bool = False
##################################
# Params for HAHOG
##################################
hahog_peak_threshold: float = 0.00001
hahog_edge_threshold: float = 10
hahog_normalize_to_uchar: bool = True
##################################
# Params for general matching
##################################
# Ratio test for matches
lowes_ratio: float = 0.8
# FLANN, BRUTEFORCE, or WORDS
matcher_type: str = "FLANN"
# Match symmetricly or one-way
symmetric_matching: bool = True
##################################
# Params for FLANN matching
##################################
# Algorithm type (KMEANS, KDTREE)
flann_algorithm: str = "KMEANS"
# See OpenCV doc
flann_branching: int = 8
# See OpenCV doc
flann_iterations: int = 10
# See OpenCV doc
flann_tree: int = 8
# Smaller -> Faster (but might lose good matches)
flann_checks: int = 20
##################################
# Params for BoW matching
##################################
bow_file: str = "bow_hahog_root_uchar_10000.npz"
# Number of words to explore per feature.
bow_words_to_match: int = 50
# Number of matching features to check.
bow_num_checks: int = 20
# Matcher type to assign words to features
bow_matcher_type: str = "FLANN"
##################################
# Params for VLAD matching
##################################
vlad_file: str = "bow_hahog_root_uchar_64.npz"
##################################
# Params for guided matching
##################################
# Number of randomized spanning-trees to samples over the tracks-graph
guided_spanning_trees: int = 5
# Random ratio higher bound edges are multiplied with
guided_spanning_trees_random: float = 0.5
# Threshold for epipolar distance for accepting a match in radians
guided_matching_threshold: float = 0.006
# Minimum track length for initial triangulation
guided_min_length_initial: int = 3
# Minimum track length for final triangulation
guided_min_length_final: int = 3
# Threshold of reprojection for extending a track within a new image (in radians)
guided_extend_threshold: float = 0.002
# Number of images considered as neighbors of another one
guided_extend_image_neighbors: int = 50
# Maximum number of reprojected neighbors (in the tracks-graph) to check when extending a track within a new image
guided_extend_feature_neighbors: int = 10
##################################
# Params for matching
##################################
# Maximum gps distance between two images for matching
matching_gps_distance: float = 150
# Number of images to match selected by GPS distance. Set to 0 to use no limit (or disable if matching_gps_distance is also 0)
matching_gps_neighbors: int = 0
# Number of images to match selected by time taken. Set to 0 to disable
matching_time_neighbors: int = 0
# Number of images to match selected by image name. Set to 0 to disable
matching_order_neighbors: int = 0
# Number of images to match selected by BoW distance. Set to 0 to disable
matching_bow_neighbors: int = 0
# Maximum GPS distance for preempting images before using selection by BoW distance. Set to 0 to disable
matching_bow_gps_distance: float = 0
# Number of images (selected by GPS distance) to preempt before using selection by BoW distance. Set to 0 to use no limit (or disable if matching_bow_gps_distance is also 0)
matching_bow_gps_neighbors: int = 0
# If True, BoW image selection will use N neighbors from the same camera + N neighbors from any different camera. If False, the selection will take the nearest neighbors from all cameras.
matching_bow_other_cameras: bool = False
# Number of images to match selected by VLAD distance. Set to 0 to disable
matching_vlad_neighbors: int = 0
# Maximum GPS distance for preempting images before using selection by VLAD distance. Set to 0 to disable
matching_vlad_gps_distance: float = 0
# Number of images (selected by GPS distance) to preempt before using selection by VLAD distance. Set to 0 to use no limit (or disable if matching_vlad_gps_distance is also 0)
matching_vlad_gps_neighbors: int = 0
# If True, VLAD image selection will use N neighbors from the same camera + N neighbors from any different camera. If False, the selection will take the nearest neighbors from all cameras.
matching_vlad_other_cameras: bool = False
# Number of rounds to run when running triangulation-based pair selection
matching_graph_rounds: int = 0
# If True, removes static matches using ad-hoc heuristics
matching_use_filters: bool = False
# Use segmentation information (if available) to improve matching
matching_use_segmentation: bool = False
##################################
# Params for geometric estimation
##################################
# Outlier threshold for fundamental matrix estimation as portion of image width
robust_matching_threshold: float = 0.004
# Outlier threshold for essential matrix estimation during matching in radians
robust_matching_calib_threshold: float = 0.004
# Minimum number of matches to accept matches between two images
robust_matching_min_match: int = 20
# Outlier threshold for essential matrix estimation during incremental reconstruction in radians
five_point_algo_threshold: float = 0.004
# Minimum number of inliers for considering a two view reconstruction valid
five_point_algo_min_inliers: int = 20
# Number of LM iterations to run when refining relative pose during matching
five_point_refine_match_iterations: int = 10
# Number of LM iterations to run when refining relative pose during reconstruction
five_point_refine_rec_iterations: int = 1000
# Check for Necker reversal ambiguities. Useful for long focal length with long distance capture (aerial manned)
five_point_reversal_check: bool = False
# Ratio of triangulated points non-reversed/reversed when checking for Necker reversal ambiguities
five_point_reversal_ratio: float = 0.95
# Outlier threshold for accepting a triangulated point in radians
triangulation_threshold: float = 0.006
# Minimum angle between views to accept a triangulated point
triangulation_min_ray_angle: float = 1.0
# Triangulation type : either considering all rays (FULL), or sing a RANSAC variant (ROBUST)
triangulation_type: str = "FULL"
# Number of LM iterations to run when refining a point
triangulation_refinement_iterations: int = 10
# Outlier threshold for resection in radians
resection_threshold: float = 0.004
# Minimum number of resection inliers to accept it
resection_min_inliers: int = 10
##################################
# Params for track creation
##################################
# Minimum number of features/images per track
min_track_length: int = 2
##################################
# Params for bundle adjustment
##################################
# Loss function for the ceres problem (see: http://ceres-solver.org/modeling.html#lossfunction)
loss_function: str = "SoftLOneLoss"
# Threshold on the squared residuals. Usually cost is quadratic for smaller residuals and sub-quadratic above.
loss_function_threshold: float = 1
# The standard deviation of the reprojection error
reprojection_error_sd: float = 0.004
# The standard deviation of the exif focal length in log-scale
exif_focal_sd: float = 0.01
# The standard deviation of the principal point coordinates
principal_point_sd: float = 0.01
# The standard deviation of the first radial distortion parameter
radial_distortion_k1_sd: float = 0.01
# The standard deviation of the second radial distortion parameter
radial_distortion_k2_sd: float = 0.01
# The standard deviation of the third radial distortion parameter
radial_distortion_k3_sd: float = 0.01
# The standard deviation of the fourth radial distortion parameter
radial_distortion_k4_sd: float = 0.01
# The standard deviation of the first tangential distortion parameter
tangential_distortion_p1_sd: float = 0.01
# The standard deviation of the second tangential distortion parameter
tangential_distortion_p2_sd: float = 0.01
# The default horizontal standard deviation of the GCPs (in meters)
gcp_horizontal_sd: float = 0.01
# The default vertical standard deviation of the GCPs (in meters)
gcp_vertical_sd: float = 0.1
# The standard deviation of the rig translation
rig_translation_sd: float = 0.1
# The standard deviation of the rig rotation
rig_rotation_sd: float = 0.1
# Type of threshold for filtering outlier : either fixed value (FIXED) or based on actual distribution (AUTO)
bundle_outlier_filtering_type: str = "FIXED"
# For AUTO filtering type, projections with larger reprojection than ratio-times-mean, are removed
bundle_outlier_auto_ratio: float = 3.0
# For FIXED filtering type, projections with larger reprojection error after bundle adjustment are removed
bundle_outlier_fixed_threshold: float = 0.006
# Optimize internal camera parameters during bundle
optimize_camera_parameters: bool = True
# Maximum optimizer iterations.
bundle_max_iterations: int = 100
# Retriangulate all points from time to time
retriangulation: bool = True
# Retriangulate when the number of points grows by this ratio
retriangulation_ratio: float = 1.2
# Use analytic derivatives or auto-differentiated ones during bundle adjustment
bundle_analytic_derivatives: bool = True
# Bundle after adding 'bundle_interval' cameras
bundle_interval: int = 999999
# Bundle when the number of points grows by this ratio
bundle_new_points_ratio: float = 1.2
# Max image graph distance for images to be included in local bundle adjustment
local_bundle_radius: int = 3
# Minimum number of common points betwenn images to be considered neighbors
local_bundle_min_common_points: int = 20
# Max number of shots to optimize during local bundle adjustment
local_bundle_max_shots: int = 30
# Save reconstructions at every iteration
save_partial_reconstructions: bool = False
##################################
# Params for GPS alignment
##################################
# Use or ignore EXIF altitude tag
use_altitude_tag: bool = False
# orientation_prior or naive
align_method: str = "auto"
# horizontal, vertical or no_roll
align_orientation_prior: str = "horizontal"
# Enforce GPS position in bundle adjustment
bundle_use_gps: bool = True
# Enforce Ground Control Point position in bundle adjustment
bundle_use_gcp: bool = False
# Compensate GPS with a per-camera similarity transform
bundle_compensate_gps_bias: bool = False
##################################
# Params for rigs
##################################
# Number of rig instances to use when calibration rigs
rig_calibration_subset_size: int = 15
# Ratio of reconstructed images needed to consider a reconstruction for rig calibration
rig_calibration_completeness: float = 0.85
# Number of SfM tentatives to run until we get a satisfying reconstruction
rig_calibration_max_rounds: int = 10
##################################
# Params for image undistortion
##################################
# Format in which to save the undistorted images
undistorted_image_format: str = "jpg"
# Max width and height of the undistorted image
undistorted_image_max_size: int = 100000
##################################
# Params for depth estimation
##################################
# Raw depthmap computation algorithm (PATCH_MATCH, BRUTE_FORCE, PATCH_MATCH_SAMPLE)
depthmap_method: str = "PATCH_MATCH_SAMPLE"
# Resolution of the depth maps
depthmap_resolution: int = 640
# Number of neighboring views
depthmap_num_neighbors: int = 10
# Number of neighboring views used for each depthmaps
depthmap_num_matching_views: int = 6
# Minimum depth in meters. Set to 0 to auto-infer from the reconstruction.
depthmap_min_depth: float = 0
# Maximum depth in meters. Set to 0 to auto-infer from the reconstruction.
depthmap_max_depth: float = 0
# Number of PatchMatch iterations to run
depthmap_patchmatch_iterations: int = 3
# Size of the correlation patch
depthmap_patch_size: int = 7
# Patches with lower standard deviation are ignored
depthmap_min_patch_sd: float = 1.0
# Minimum correlation score to accept a depth value
depthmap_min_correlation_score: float = 0.1
# Threshold to measure depth closeness
depthmap_same_depth_threshold: float = 0.01
# Min number of views that should reconstruct a point for it to be valid
depthmap_min_consistent_views: int = 3
# Save debug files with partial reconstruction results
depthmap_save_debug_files: bool = False
##################################
# Params for multi-processing/threading
##################################
# Number of threads to use
processes: int = 1
# When processes > 1, number of threads used for reading images
read_processes: int = 4
##################################
# Params for submodel split and merge
##################################
# Average number of images per submodel
submodel_size: int = 80
# Radius of the overlapping region between submodels
submodel_overlap: float = 30.0
# Relative path to the submodels directory
submodels_relpath: str = "submodels"
# Template to generate the relative path to a submodel directory
submodel_relpath_template: str = "submodels/submodel_%04d"
# Template to generate the relative path to a submodel images directory
submodel_images_relpath_template: str = "submodels/submodel_%04d/images"
def default_config():
"""Return default configuration"""
return asdict(OpenSfMConfig())
def load_config(filepath):
"""DEPRECATED: = Load config from a config.yaml filepath"""
if not os.path.isfile(filepath):
return default_config()
with open(filepath) as fin:
return load_config_from_fileobject(fin)
def load_config_from_fileobject(f):
"""Load config from a config.yaml fileobject"""
config = default_config()
new_config = yaml.safe_load(f)
if new_config:
for k, v in new_config.items():
config[k] = v
return config