def main(args): db = COLMAPDatabase.connect(args.input) c = db.cursor() c.execute("SELECT pair_id,rows,cols,data FROM matches LIMIT 1") data = c.fetchall() print(data) db.close()
def get_keypoint_from_db(db_path): db = COLMAPDatabase.connect(db_path) c = db.cursor() c.execute("SELECT image_id,rows,cols,data FROM keypoints") keypoints_data = list(map(keypoint_decode,c.fetchall())) db.close() keypoint_lookup = {} for img_id, kpt_data in keypoints_data: keypoint_lookup[img_id] = kpt_data return keypoint_lookup
def copy_images(args): destionation_db = COLMAPDatabase.connect(args.destionation) images = read_images_binary(os.path.join(args.source, 'images.bin')) destionation_db.execute('DELETE FROM images') for i in images: img_id, qvec, tvec, cam_id, name, xys, point3D_ids = images[i] destionation_db.add_image(name, cam_id, prior_q=qvec, prior_t=tvec, image_id=img_id) destionation_db.commit() destionation_db.close()
def copy_camera(args): cameras = read_cameras_binary(os.path.join(args.source, 'cameras.bin')) destionation_db = COLMAPDatabase.connect(args.destionation) c = destionation_db.cursor() c.execute('SELECT * FROM cameras') destionation_db.execute('DELETE FROM cameras') for i in cameras: cam_id, model, width, height, params = cameras[i] known_focal = params[0] destionation_db.add_camera(model, width, height, params[:-1], prior_focal_length=known_focal, camera_id=cam_id) destionation_db.commit() destionation_db.close()
def take_steamvr_images(save_dir, num_images, delay_between_images): plt.show() openvr.init(openvr.VRApplication_Scene) convert_coordinate_system = np.identity(4) convert_coordinate_system[:3, :3] = Rotation.from_euler( 'XYZ', (180, 0, 0), degrees=True).as_matrix() device = openvr.k_unTrackedDeviceIndex_Hmd num_cameras = openvr.VRSystem().getInt32TrackedDeviceProperty( device, openvr.Prop_NumCameras_Int32) camera_to_head_mat = (openvr.HmdMatrix34_t * num_cameras)() openvr.VRSystem().getArrayTrackedDeviceProperty( device, openvr.Prop_CameraToHeadTransforms_Matrix34_Array, openvr.k_unHmdMatrix34PropertyTag, camera_to_head_mat, 48 * num_cameras) cam = openvr.VRTrackedCamera() cam_handle = cam.acquireVideoStreamingService(device) width, height, buffer_size = cam.getCameraFrameSize( device, openvr.VRTrackedCameraFrameType_MaximumUndistorted) fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.set_xlabel('x axis - metres') ax.set_ylabel('z axis - metres') ax.set_zlabel('y axis - metres') ax.set_xlim(-0.5, 0.5) ax.set_ylim(-0.5, 0.5) ax.set_zlim(0, 1) save_dir = ColmapFolder(save_dir) db = COLMAPDatabase.connect(save_dir.database_path) db.create_tables() init_params = np.array( (420.000000, (width / num_cameras) / 2, height / 2, 0.000000)) camera_model = CAMERA_MODEL_NAMES['SIMPLE_RADIAL'] cameras = {} camera_to_head_transforms = {} for i in range(num_cameras): cam_id = db.add_camera(camera_model.model_id, width / 2, height, init_params) camera_to_head_transforms[cam_id] = hmd_matrix_to_numpy( camera_to_head_mat[i]) cameras[cam_id] = Camera(id=cam_id, model=camera_model.model_name, width=width / num_cameras, height=height, params=init_params) poses = [] # Let waitGetPoses populate the poses structure the first time cam_positions = [] images = [] for i in range(num_images): poses, game_poses = openvr.VRCompositor().waitGetPoses(poses, None) hmd_pose = poses[openvr.k_unTrackedDeviceIndex_Hmd] if not hmd_pose.bPoseIsValid: print("Pose not valid") continue world_to_head = hmd_matrix_to_numpy(hmd_pose.mDeviceToAbsoluteTracking) world_to_cams = { id_: world_to_head @ head_to_cam @ convert_coordinate_system for (id_, head_to_cam) in camera_to_head_transforms.items() } image_buffer = (ctypes.c_ubyte * buffer_size)() try: cam.getVideoStreamFrameBuffer( cam_handle, openvr.VRTrackedCameraFrameType_MaximumUndistorted, image_buffer, buffer_size) except: print("Error getting video stream buffer") continue image_array = np.array(image_buffer) image_array = image_array.reshape((height, width, 4)) image_array = image_array[:, :, 0:3] image_array = np.clip(image_array, 0, 255) for j, (cam_id, world_to_cam) in enumerate(world_to_cams.items()): image = Image.fromarray( image_array[:, int(width / num_cameras) * j:int(width / num_cameras) * (j + 1), :]) name = f"{i:03d}_cam{j}.jpg" image.save(save_dir.images_path / name) image_obj = read_write_model.Image( camera_id=cam_id, name=name, transformation_matrix=world_to_cam) images.append(image_obj) draw_axes(ax, transform_mat=world_to_cam) fig.show() fig.canvas.draw() fig.canvas.flush_events() time.sleep(delay_between_images) print(f"Picture taken :{i}") image_dict = {} print("All pictures taken") with open(save_dir.geo_reg_path, 'w') as geo_reg_file: for image in images: image_id = db.add_image(image=image) image.id = image_id image_dict[image_id] = image geo_reg_file.write( f"{name} {' '.join(map(str, image.transformation_matrix[0:3, 3]))}\n" ) read_write_model.write_model(cameras, image_dict, {}, save_dir.sparse_path, '.txt') db.commit() db.close() print("Metadata saved") openvr.shutdown() plt.show()
def pose_to_sparse(txt_src, img_src, spa_dst, DEBUG=False, exists_ok=True, worker_idx=None, world_size=None): opt = argparse.Namespace(txt_src=txt_src, img_src=img_src, spa_dst=spa_dst) assert os.path.exists(opt.txt_src), opt.txt_src assert os.path.exists(opt.img_src), opt.img_src if not os.path.exists(opt.spa_dst): os.makedirs(opt.spa_dst) else: if DEBUG: shutil.rmtree(opt.spa_dst) elif not exists_ok: print("Output directory exists, doing nothing") return 0 txts = sorted(glob.glob(os.path.join(opt.txt_src, "*.txt"))) if DEBUG: print(txts) if worker_idx is not None and world_size is not None: txts = txts[worker_idx::world_size] if DEBUG: txts = txts[:1] failed = list() for txt in txts: vidid = os.path.splitext(os.path.split(txt)[1])[0] print(f"Processing {vidid}") if (os.path.exists( os.path.join(opt.spa_dst, vidid, "sparse", "cameras.bin")) and os.path.exists( os.path.join(opt.spa_dst, vidid, "sparse", "images.bin")) and os.path.exists( os.path.join(opt.spa_dst, vidid, "sparse", "points3D.bin"))): print("Found sparse model, skipping {}".format(vidid)) continue if os.path.exists(os.path.join(opt.spa_dst, vidid)): shutil.rmtree(os.path.join(opt.spa_dst, vidid)) print("Found partial output of previous run, removed {}".format( vidid)) # read camera poses for this sequence with open(txt, "r") as f: firstline = f.readline() if firstline.startswith("http"): if DEBUG: print("Ignoring first line.") skiprows = 1 else: skiprows = 0 vid_data = np.loadtxt(txt, skiprows=skiprows) if len(vid_data.shape) != 2: failed.append(vidid) print(f"Wrong txt format for {vidid}!") continue timestamps = vid_data[:, 0].astype(np.int) if DEBUG: print(timestamps) filenames = [str(ts) + ".png" for ts in timestamps] if not len(filenames) > 1: failed.append(vidid) print(f"Less than two frames, skipping {vidid}!") continue if not os.path.exists(os.path.join(opt.img_src, vidid)): failed.append(vidid) print(f"Could not find frames, skipping {vidid}!") continue if not len(glob.glob(os.path.join(opt.img_src, vidid, "*.png"))) == len(filenames): failed.append(vidid) print(f"Could not find all frames, skipping {vidid}!") continue if DEBUG: print(vid_data[0, 1:]) K_params = vid_data[:, 1:7] Ks = np.zeros((K_params.shape[0], 3, 3)) Ks[:, 0, 0] = K_params[:, 0] Ks[:, 1, 1] = K_params[:, 1] Ks[:, 0, 2] = K_params[:, 2] Ks[:, 1, 2] = K_params[:, 3] Ks[:, 2, 2] = 1 assert (Ks[0, ...] == Ks[1, ...]).all() K = Ks[0] if DEBUG: print(K) Rts = vid_data[:, 7:].reshape(-1, 3, 4) if DEBUG: print(Rts[0]) # given these intrinsics and extrinsics, find a sparse set of scale # consistent 3d points following # https://colmap.github.io/faq.html#reconstruct-sparse-dense-model-from-known-camera-poses # extract and match features on frames dst_dir = os.path.join(opt.spa_dst, vidid) os.makedirs(dst_dir) database_path = os.path.join(dst_dir, "database.db") # symlink images image_path = os.path.join(dst_dir, "images") os.symlink(os.path.abspath(os.path.join(opt.img_src, vidid)), image_path) cmd = [ "colmap", "feature_extractor", "--database_path", database_path, "--image_path", image_path, "--ImageReader.camera_model", "PINHOLE", "--ImageReader.single_camera", "1", "--SiftExtraction.use_gpu", "1" ] if DEBUG: print(" ".join(cmd)) subprocess.run(cmd, check=True) # read the database from database import COLMAPDatabase, blob_to_array, array_to_blob db = COLMAPDatabase.connect(database_path) # read and update camera ## https://colmap.github.io/cameras.html cam = db.execute("SELECT * FROM cameras").fetchone() camera_id = cam[0] camera_model = cam[1] assert camera_model == 1 # PINHOLE width = cam[2] height = cam[3] params = blob_to_array(cam[4], dtype=np.float64) assert len(params) == 4 # fx, fy, cx, cy for PINHOLE # adjust params params[0] = width * K[0, 0] params[1] = height * K[1, 1] params[2] = width * K[0, 2] params[3] = height * K[1, 2] # update db.execute("UPDATE cameras SET params = ? WHERE camera_id = ?", (array_to_blob(params), camera_id)) db.commit() # match features cmd = [ "colmap", "sequential_matcher", "--database_path", database_path, "--SiftMatching.use_gpu", "1" ] if DEBUG: print(" ".join(cmd)) subprocess.run(cmd, check=True) # triangulate ## prepare pose model ### https://colmap.github.io/format.html#text-format pose_dir = os.path.join(dst_dir, "pose") os.makedirs(pose_dir) cameras_txt = os.path.join(pose_dir, "cameras.txt") with open(cameras_txt, "w") as f: f.write("{} PINHOLE {} {} {}".format( camera_id, width, height, " ".join(["{:.2f}".format(p) for p in params]))) images_txt = os.path.join(pose_dir, "images.txt") # match image ids with filenames and export their extrinsics to images.txt images = db.execute( "SELECT image_id, name, camera_id FROM images").fetchall() lines = list() for image in images: assert image[2] == camera_id image_id = image[0] image_name = image[1] image_idx = filenames.index(image_name) Rt = Rts[image_idx] R = Rt[:3, :3] t = Rt[:3, 3] # convert R to quaternion from scipy.spatial.transform import Rotation Q = Rotation.from_matrix(R).as_quat() # from x,y,z,w to w,x,y,z line = " ".join([ "{:.6f}".format(x) for x in [Q[3], Q[0], Q[1], Q[2], t[0], t[1], t[2]] ]) line = "{} ".format(image_id) + line + " {} {}".format( camera_id, image_name) lines.append(line) lines.append("") # empty line for 3d points to be triangulated with open(images_txt, "w") as f: f.write("\n".join(lines) + "\n") # create empty points3D.txt points3D_txt = os.path.join(pose_dir, "points3D.txt") open(points3D_txt, "w").close() # run point_triangulator out_dir = os.path.join(dst_dir, "sparse") os.makedirs(out_dir) cmd = [ "colmap", "point_triangulator", "--database_path", database_path, "--image_path", image_path, "--input_path", pose_dir, "--output_path", out_dir ] result = subprocess.run(cmd) if result.returncode != 0: print(f"Triangulation failed for {vidid}!") failed.append(vidid) print("Failed sequences:") print("\n".join(failed)) print(f"Could not create sparse models for {len(failed)} sequences.") return len(txts)
def main(args): db = COLMAPDatabase.connect(args.input) c = db.cursor() c.execute("SELECT pair_id,rows,cols,data FROM matches") matches_data = c.fetchall() c.execute("SELECT image_id,rows,cols,data FROM keypoints") keypoints_data = c.fetchall() db.close() total_image = len(keypoints_data) output_track = [] match_from = {} match_search = {} keypoint_search = {} total_image_list = [] keypoint_counter = 0 for keypoint_image in keypoints_data: img_id, r, c, data = keypoint_image kpt = blob_to_array(data, np.float32, (r, c)) image_kpt = {} for i in range(r): u, v = kpt[i, :2] image_kpt[i] = [u, v] keypoint_search[img_id] = image_kpt for match_record in matches_data: image_from, image_to = pair_id_to_image_ids(match_record[0]) image_from = int(image_from) total_image_list.append(image_from) if match_record[1] != 0: if not image_from in match_from: match_from[image_from] = [] match_from[image_from].append(match_record[0]) lookup = blob_to_array(match_record[3], np.int32, (match_record[1], match_record[2])) match_search[match_record[0]] = dict(lookup) for image_from, records in match_from.items(): for kpt_id, [x, y] in keypoint_search[image_from].items(): buffer = [] buffer.append({ 'image': image_from, 'x': x, 'y': y, 'kpt_id': keypoint_counter }) for record in records: if kpt_id in match_search[record]: _, image_to = pair_id_to_image_ids(record) kpt_on_dest = match_search[record][kpt_id] x, y = keypoint_search[image_to][kpt_on_dest] buffer.append({ 'image': image_to, 'x': x, 'y': y, 'kpt_id': keypoint_counter }) if len(buffer) != 1: output_track = output_track + buffer keypoint_counter = keypoint_counter + 1 # write output with open('feature_matching.txt', 'w') as f: f.write('%d %d %d\n' % (total_image, keypoint_counter, len(output_track))) for o in output_track: f.write('%d %d %lf %lf\n' % (o['image'] - 1, o['kpt_id'], o['x'], o['y'])) if args.zero_polyfill: # zero polyfill for backward compatibility for i in range(3 * keypoint_counter + total_image * 9): f.write('0\n') else: random_value = np.random.normal( 0, 1, 3 * keypoint_counter + total_image * 9) for value in random_value: f.write('{}\n'.format(value))
recompute=args.recompute_features) else: extractor = CrossDomainFeatureExtractor( input_dir, image_list_file, cuda=args.cuda, recompute=args.recompute_features) extractor.extract() if not args.only_features: if os.path.exists(database_path): print("WARNING: database already exists, it will be removed.") os.remove(database_path) print("Opening database: ", database_path) db = COLMAPDatabase.connect(database_path) db.create_tables() if args.spatial_matching: matcher = SpatialMatcher( input_dir, image_list_file, db, suffix, recompute=args.recompute_matches, cuda=args.cuda, num_processes=args.processes, max_distance=args.spatial_matching, disable_photo2photo_matching=args.disable_photo2photo_matching) else: matcher = ExhaustiveMatcher(
def create_init_files(pinhole_dict_file, db_file, out_dir): if not os.path.exists(out_dir): os.mkdir(out_dir) # create template with open(pinhole_dict_file) as fp: pinhole_dict = json.load(fp) template = {} cameras_line_template = '{camera_id} PINHOLE {width} {height} {fx} {fy} {cx} {cy}\n' images_line_template = '{image_id} {qw} {qx} {qy} {qz} {tx} {ty} {tz} {camera_id} {image_name}\n\n' for img_name in pinhole_dict: # w, h, fx, fy, cx, cy, qvec, t params = pinhole_dict[img_name] w = params[0] h = params[1] fx = params[2] fy = params[3] cx = params[4] cy = params[5] qvec = params[6:10] tvec = params[10:13] cam_line = cameras_line_template.format(camera_id="{camera_id}", width=w, height=h, fx=fx, fy=fy, cx=cx, cy=cy) img_line = images_line_template.format(image_id="{image_id}", qw=qvec[0], qx=qvec[1], qy=qvec[2], qz=qvec[3], tx=tvec[0], ty=tvec[1], tz=tvec[2], camera_id="{camera_id}", image_name=img_name) template[img_name] = (cam_line, img_line) # read database db = COLMAPDatabase.connect(db_file) table_images = db.execute("SELECT * FROM images") img_name2id_dict = {} for row in table_images: img_name2id_dict[row[1]] = row[0] cameras_txt_lines = [] images_txt_lines = [] for img_name, img_id in img_name2id_dict.items(): camera_line = template[img_name][0].format(camera_id=img_id) cameras_txt_lines.append(camera_line) image_line = template[img_name][1].format(image_id=img_id, camera_id=img_id) images_txt_lines.append(image_line) with open(os.path.join(out_dir, 'cameras.txt'), 'w') as fp: fp.writelines(cameras_txt_lines) with open(os.path.join(out_dir, 'images.txt'), 'w') as fp: fp.writelines(images_txt_lines) fp.write('\n') # create an empty points3D.txt fp = open(os.path.join(out_dir, 'points3D.txt'), 'w') fp.close()