@@ -98,6 +98,7 @@ def run_colmap(
9898 verbose : bool = False ,
9999 matching_method : Literal ["vocab_tree" , "exhaustive" , "sequential" ] = "vocab_tree" ,
100100 refine_intrinsics : bool = True ,
101+ use_best_sparse_model : bool = True ,
101102 colmap_cmd : str = "colmap" ,
102103) -> None :
103104 """Runs COLMAP on the images.
@@ -111,6 +112,7 @@ def run_colmap(
111112 verbose: If True, logs the output of the command.
112113 matching_method: Matching method to use.
113114 refine_intrinsics: If True, refine intrinsics.
115+ use_best_sparse_model: If True, refine intrinsics of the best sparse model.
114116 colmap_cmd: Path to the COLMAP executable.
115117 """
116118
@@ -173,11 +175,13 @@ def run_colmap(
173175 CONSOLE .log ("[bold green]:tada: Done COLMAP bundle adjustment." )
174176
175177 if refine_intrinsics :
178+ sparse_model = "0" if not use_best_sparse_model else BestSparseModel .get_model (colmap_dir )
179+
176180 with status (msg = "[bold yellow]Refine intrinsics..." , spinner = "dqpb" , verbose = verbose ):
177181 bundle_adjuster_cmd = [
178182 f"{ colmap_cmd } bundle_adjuster" ,
179- f"--input_path { sparse_dir } /0 " ,
180- f"--output_path { sparse_dir } /0 " ,
183+ f"--input_path { sparse_dir } /{ sparse_model } " ,
184+ f"--output_path { sparse_dir } /{ sparse_model } " ,
181185 "--BundleAdjustment.refine_principal_point 1" ,
182186 ]
183187 run_command (" " .join (bundle_adjuster_cmd ), verbose = verbose )
@@ -712,3 +716,64 @@ def create_ply_from_colmap(
712716 x , y , z = coord
713717 r , g , b = color
714718 f .write (f"{ x :8f} { y :8f} { z :8f} { r } { g } { b } \n " )
719+
720+
721+ class BestSparseModel :
722+ """
723+ Utility class to find and cache the best COLMAP sparse model
724+ from a given directory. Provides both the model name and full path.
725+
726+ The best model is defined as the one with the largest number of registered images.
727+ """
728+
729+ _cached_model = None # Cached name of the best sparse model
730+
731+ @staticmethod
732+ def _find_best_model (colmap_dir : Path ) -> str :
733+ """
734+ Find the best sparse model in the COLMAP directory.
735+
736+ Args:
737+ colmap_dir (Path): Path to the COLMAP project directory containing 'sparse/'.
738+
739+ Returns:
740+ str: Name of the best sparse model directory.
741+
742+ Raises:
743+ ValueError: If no valid sparse models are found.
744+ """
745+ sparse_dir = colmap_dir / "sparse"
746+ models = [m for m in sorted (sparse_dir .glob ("*" )) if (m / "images.bin" ).exists ()]
747+ if not models :
748+ raise ValueError (f"No valid COLMAP sparse models found in { sparse_dir } " )
749+
750+ best_model = max (models , key = lambda m : len (read_images_binary (m / "images.bin" )))
751+ return best_model .name
752+
753+ @staticmethod
754+ def get_model (colmap_dir : Path ) -> str :
755+ """
756+ Get the name of the best sparse model, using cache if available.
757+
758+ Args:
759+ colmap_dir (Path): Path to the COLMAP project directory containing 'sparse/'.
760+
761+ Returns:
762+ str: Name of the best sparse model.
763+ """
764+ if not BestSparseModel ._cached_model :
765+ BestSparseModel ._cached_model = BestSparseModel ._find_best_model (colmap_dir )
766+ return BestSparseModel ._cached_model
767+
768+ @staticmethod
769+ def get_model_path (colmap_dir : Path ) -> Path :
770+ """
771+ Get the full path to the best sparse model, using cache if available.
772+
773+ Args:
774+ colmap_dir (Path): Path to the COLMAP project directory containing 'sparse/'.
775+
776+ Returns:
777+ Path: Full path to the best sparse model directory.
778+ """
779+ return colmap_dir / "sparse" / BestSparseModel .get_model (colmap_dir )
0 commit comments