Example #1
0
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 
Example #3
0
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()
Example #4
0
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)
Example #7
0
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))
Example #8
0
                                          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()