import os import logging import typing import numpy as np from colmap_wrapper import run_colmap import colmap_read_model as read_model #from nerf_homemade.poses.colmap_wrapper import run_colmap #import nerf_homemade.poses.colmap_read_model as read_model def gen_poses(basedir: str, match_type: str='exhaustive') -> None: """ Geneate or retreive camera poses. Retrieve the cameras either by generating using COLMAP or reading them if they already have been written. Parameters ---------- basedir: str The path of the directory either containing raw images or the arborescence of a COLMAP directory if camera poses have already been computed match_type: {'exhaustive', 'sequential'} The type of match COLMAP should perform if it needs to be run. Defaults to 'exhaustive'. """ files_needed = ["cameras.bin", "images.bin", "points3D.bin"] path_to_sparse = os.path.join(basedir, "sparse/0") if os.path.exists(path_to_sparse): existing_files = os.listdir(path_to_sparse) else: existing_files = [] if not all([f in existing_files for f in files_needed]): logging.info("Running COLMAP") run_colmap(basedir, match_type) else: logging.info("Files genreated by COLMAP found. Skipping running COLMAP.") logging.debug("Loading COLMAP data") poses, points_3d, perm = load_colmap_data(basedir) logging.debug("Saving COLMAP data to npy") save_poses(basedir, poses, points_3d, perm) def load_colmap_data(basedir: str) -> (np.ndarray, dict, np.ndarray): """ Load data from a COLMAP arborescence. Parameters ---------- basedir: str The path of the directory which contains the COLMAP arborescence Returns ------- poses: numpy.ndarray List of poses for each image. pts3d: List of 3D points for each image. perm: Index list ordered by name of images. Should be [1, 2, ..., N] if well ordered. """ # append prefix basedir = os.path.join(basedir, "sparse/0/") # read cameras data cameras_file = os.path.join(basedir, "cameras.bin") cameras_data = read_model.read_cameras_binary(cameras_file) logging.debug(f"Loading camera model from {cameras_file}") # extract intrinsic values for the camera # asumption is made that it is unique camera_h = cameras_data[1].height camera_w = cameras_data[1].width camera_f = cameras_data[1].params[0] hwf = np.array([camera_h, camera_w, camera_f]).reshape([3,1]) logging.debug(f"Number of cameras: {len(cameras_data)}") # read images data images_file = os.path.join(basedir, "images.bin") images_data = read_model.read_images_binary(images_file) w2c_mats = [] bottom = np.array([0., 0., 0., 1.]).reshape([1, 4]) # sort by name names = [images_data[k].name for k in images_data] perm = np.argsort(names) # equivalent to a range since dict is index by number from 1 to N # create camera matrix for k in images_data: im = images_data[k] R = im.qvec2rotmat() t = im.tvec.reshape([3,1]) m = np.concatenate([np.concatenate([R, t], 1), bottom], 0) w2c_mats.append(m) w2c_mats = np.stack(w2c_mats, 0) c2w_mats = np.linalg.inv(w2c_mats) poses = c2w_mats[:, :3, :4].transpose([1,2,0]) poses = np.concatenate([poses, np.tile(hwf[..., np.newaxis], [1,1,poses.shape[-1]])], 1) # read 3d points data pts3d_file = os.path.join(basedir, "points3D.bin") pts3d = read_model.read_points3d_binary(pts3d_file) # must switch to [-u, r, -t] from [r, -u, t], NOT [r, u, -t] poses = np.concatenate([poses[:, 1:2, :], poses[:, 0:1, :], -poses[:, 2:3, :], poses[:, 3:4, :], poses[:, 4:5, :]], 1) return poses, pts3d, perm def save_poses(basedir, poses, pts3d, perm) -> None: """ Save the COLMAP data in a `.npy` format. Parameters ---------- basedir: str The path of the directory in which to save the data. Data will be saved in `basedir/poses_bounds.npy`. poses: The list of poses pts3d: The list of 3d points perm: The sorted index of the array """ # TODO