Package: pycolmap
Python bindings for COLMAPThis repository exposes to Python most capabilities ofCOLMAPfor Structure-from-Motion and Multiview-stereo, such as reconstruction pipelines & objects and geometric estimators.InstallationWheels for Python 8/9/10 on Linux, macOS 10/11/12 (both Intel and Apple Silicon), and Windows can be installed using pip:pipinstallpycolmapThe wheels are automatically built and pushed toPyPIat each release. They are currently not built with CUDA support, which requires building from source.[Building PyCOLMAP from source - click to expand]Install COLMAP from source followingthe official guide. Use COLMAP 3.8 or 3.9.1 for PyCOLMAP 0.4.0 or 0.5.0/0.6.0.Clone the PyCOLMAP repository:gitclone-b0.6.0https://github.com/colmap/pycolmap.gitcdpycolmapBuild:On Linux and macOS:python-mpipinstall.On Windows, after installing COLMAPvia VCPKG, run in powershell:py-mpipinstall.`--cmake.define.CMAKE_TOOLCHAIN_FILE="$VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake"`--cmake.define.VCPKG_TARGET_TRIPLET="x64-windows"Reconstruction pipelinePyCOLMAP provides bindings for multiple steps of the standard reconstruction pipeline:extracting and matching SIFT featuresimporting an image folder into a COLMAP databaseinferring the camera parameters from the EXIF metadata of an image filerunning two-view geometric verification of matches on a COLMAP databasetriangulating points into an existing COLMAP modelrunning incremental reconstruction from a COLMAP databasedense reconstruction with multi-view stereoSparse & Dense reconstruction from a folder of images can be performed with:output_path:pathlib.Pathimage_dir:pathlib.Pathoutput_path.mkdir()mvs_path=output_path/"mvs"database_path=output_path/"database.db"pycolmap.extract_features(database_path,image_dir)pycolmap.match_exhaustive(database_path)maps=pycolmap.incremental_mapping(database_path,image_dir,output_path)maps[0].write(output_path)# dense reconstructionpycolmap.undistort_images(mvs_path,output_path,image_dir)pycolmap.patch_match_stereo(mvs_path)# requires compilation with CUDApycolmap.stereo_fusion(mvs_path/"dense.ply",mvs_path)PyCOLMAP can leverage the GPU for feature extraction, matching, and multi-view stereo if COLMAP was compiled with CUDA support.
Similarly, PyCOLMAP can run Delauney Triangulation if COLMAP was compiled with CGAL support.
This requires to build the package from source and is not available with the PyPI wheels.All of the above steps are easily configurable with python dicts which are recursively merged into
their respective defaults, for example:pycolmap.extract_features(database_path,image_dir,sift_options={"max_num_features":512})# equivalent toops=pycolmap.SiftExtractionOptions()ops.max_num_features=512pycolmap.extract_features(database_path,image_dir,sift_options=ops)To list available options and their default parameters:help(pycolmap.SiftExtractionOptions)For another example of usage, seeexample.pyorhloc/reconstruction.py.Reconstruction objectWe can load and manipulate an existing COLMAP 3D reconstruction:importpycolmapreconstruction=pycolmap.Reconstruction("path/to/reconstruction/dir")print(reconstruction.summary())forimage_id,imageinreconstruction.images.items():print(image_id,image)forpoint3D_id,point3Dinreconstruction.points3D.items():print(point3D_id,point3D)forcamera_id,camerainreconstruction.cameras.items():print(camera_id,camera)reconstruction.write("path/to/reconstruction/dir/")The object API mirrors the COLMAP C++ library. The bindings support many other operations, for example:projecting a 3D point into an image with arbitrary camera model:uv=camera.img_from_cam(image.cam_from_world*point3D.xyz)aligning two 3D reconstructions by their camera poses:rec2_from_rec1=pycolmap.align_reconstructions_via_reprojections(reconstruction1,reconstrution2)reconstruction1.transform(rec2_from_rec1)print(rec2_from_rec1.scale,rec2_from_rec1.rotation,rec2_from_rec1.translation)exporting reconstructions to text, PLY, or other formats:reconstruction.write_text("path/to/new/reconstruction/dir/")# text formatreconstruction.export_PLY("rec.ply")# PLY formatEstimatorsWe provide robust RANSAC-based estimators for absolute camera pose (single-camera and multi-camera-rig), essential matrix, fundamental matrix, homography, and two-view relative pose for calibrated cameras.All RANSAC and estimation parameters are exposed as objects that behave similarly as Python dataclasses. The RANSAC options are described incolmap/optim/ransac.hand their default values are:ransac_options=pycolmap.RANSACOptions(max_error=4.0,# for example the reprojection error in pixelsmin_inlier_ratio=0.01,confidence=0.9999,min_num_trials=1000,max_num_trials=100000,)Absolute pose estimationFor instance, to estimate the absolute pose of a query camera given 2D-3D correspondences:# Parameters:# - points2D: Nx2 array; pixel coordinates# - points3D: Nx3 array; world coordinates# - camera: pycolmap.Camera# Optional parameters:# - estimation_options: dict or pycolmap.AbsolutePoseEstimationOptions# - refinement_options: dict or pycolmap.AbsolutePoseRefinementOptionsanswer=pycolmap.absolute_pose_estimation(points2D,points3D,camera)# Returns: dictionary of estimation outputs or None if failure2D and 3D points are passed as Numpy arrays or lists. The options are defined inestimators/absolute_pose.ccand can be passed as regular (nested) Python dictionaries:pycolmap.absolute_pose_estimation(points2D,points3D,camera,estimation_options=dict(ransac=dict(max_error=12.0)),refinement_options=dict(refine_focal_length=True),)Absolute Pose Refinement# Parameters:# - cam_from_world: pycolmap.Rigid3d, initial pose# - points2D: Nx2 array; pixel coordinates# - points3D: Nx3 array; world coordinates# - inlier_mask: array of N bool; inlier_mask[i] is true if correpondence i is an inlier# - camera: pycolmap.Camera# Optional parameters:# - refinement_options: dict or pycolmap.AbsolutePoseRefinementOptionsanswer=pycolmap.pose_refinement(cam_from_world,points2D,points3D,inlier_mask,camera)# Returns: dictionary of refinement outputs or None if failureEssential matrix estimation# Parameters:# - points1: Nx2 array; 2D pixel coordinates in image 1# - points2: Nx2 array; 2D pixel coordinates in image 2# - camera1: pycolmap.Camera of image 1# - camera2: pycolmap.Camera of image 2# Optional parameters:# - options: dict or pycolmap.RANSACOptions (default inlier threshold is 4px)answer=pycolmap.essential_matrix_estimation(points1,points2,camera1,camera2)# Returns: dictionary of estimation outputs or None if failureFundamental matrix estimationanswer=pycolmap.fundamental_matrix_estimation(points1,points2,[options],# optional dict or pycolmap.RANSACOptions)Homography estimationanswer=pycolmap.homography_matrix_estimation(points1,points2,[options],# optional dict or pycolmap.RANSACOptions)Two-view geometry estimationCOLMAP can also estimate a relative pose between two calibrated cameras by estimating both E and H and accounting for the degeneracies of each model.# Parameters:# - camera1: pycolmap.Camera of image 1# - points1: Nx2 array; 2D pixel coordinates in image 1# - camera2: pycolmap.Camera of image 2# - points2: Nx2 array; 2D pixel coordinates in image 2# Optional parameters:# - matches: Nx2 integer array; correspondences across images# - options: dict or pycolmap.TwoViewGeometryOptionsanswer=pycolmap.estimate_calibrated_two_view_geometry(camera1,points1,camera2,points2)# Returns: pycolmap.TwoViewGeometryTheTwoViewGeometryOptionscontrol how each model is selected. The output structure contains the geometric model, inlier matches, the relative pose (ifoptions.compute_relative_pose=True), and the type of camera configuration, which is an instance of the enumpycolmap.TwoViewGeometryConfiguration.Camera argumentSome estimators expect a COLMAP camera object, which can be created as follow:camera=pycolmap.Camera(model=camera_model_name_or_id,width=width,height=height,params=params,)The different camera models and their extra parameters are defined incolmap/src/colmap/sensor/models.h. For example for a pinhole camera:camera=pycolmap.Camera(model='SIMPLE_PINHOLE',width=width,height=height,params=[focal_length,cx,cy],)Alternatively, we can also pass a camera dictionary:camera_dict={'model':COLMAP_CAMERA_MODEL_NAME_OR_ID,'width':IMAGE_WIDTH,'height':IMAGE_HEIGHT,'params':EXTRA_CAMERA_PARAMETERS_LIST}SIFT feature extractionimportnumpyasnpimportpycolmapfromPILimportImage,ImageOps# Input should be grayscale image with range [0, 1].img=Image.open('image.jpg').convert('RGB')img=ImageOps.grayscale(img)img=np.array(img).astype(np.float)/255.# Optional parameters:# - options: dict or pycolmap.SiftExtractionOptions# - device: default pycolmap.Device.auto uses the GPU if availablesift=pycolmap.Sift()# Parameters:# - image: HxW float arraykeypoints,descriptors=sift.extract(img)# Returns:# - keypoints: Nx4 array; format: x (j), y (i), scale, orientation# - descriptors: Nx128 array; L2-normalized descriptorsTODOAdd documentationAdd more detailed examplesAdd unit tests for reconstruction bindingsCreated and maintained byMihai Dusmanu,Philipp Lindenberger,John Lambert,Paul-Edouard Sarlin, and other contributors.