示例#1
0
 def setUp(self):
     self._tempdir = tempfile.TemporaryDirectory()
     self._samples_folder = path.abspath(path.join(path.dirname(__file__), '..', 'samples', 'maupertuis'))
     self._kapture_dirpath = path.join(self._samples_folder, 'kapture')
     self._kapture_data = csv.kapture_from_dir(self._kapture_dirpath)
示例#2
0
    def test_import_single_model(self):
        nvm_path = path.join(self.aachen_models_folder,
                             'aachen_cvpr2018_db.nvm')

        with tempfile.TemporaryDirectory() as tmpdirname:
            import_nvm(nvm_path,
                       self.images_folder,
                       tmpdirname,
                       filter_list_path="",
                       ignore_trajectories=False,
                       add_reconstruction=True,
                       force_overwrite_existing=True)

            expected_kdata = kapture_from_dir(
                path.join(self.aachen_folder, 'kapture/training'))
            imported_aachen_data = kapture_from_dir(tmpdirname)
            self.assertTrue(equal_kapture(imported_aachen_data,
                                          expected_kdata))

        # test without trajectories
        with tempfile.TemporaryDirectory() as tmpdirname:
            import_nvm(nvm_path,
                       self.images_folder,
                       tmpdirname,
                       filter_list_path="",
                       ignore_trajectories=True,
                       add_reconstruction=True,
                       force_overwrite_existing=True)

            expected_kdata = kapture_from_dir(
                path.join(self.aachen_folder, 'kapture/training'))
            expected_kdata._trajectories = None
            imported_aachen_data = kapture_from_dir(tmpdirname)
            self.assertTrue(equal_kapture(imported_aachen_data,
                                          expected_kdata))

        # test without points3d
        with tempfile.TemporaryDirectory() as tmpdirname:
            import_nvm(nvm_path,
                       self.images_folder,
                       tmpdirname,
                       filter_list_path="",
                       ignore_trajectories=False,
                       add_reconstruction=False,
                       force_overwrite_existing=True)

            expected_kdata = kapture_from_dir(
                path.join(self.aachen_folder, 'kapture/training'))
            expected_kdata._points3d = None
            expected_kdata._keypoints = None
            expected_kdata._observations = None
            imported_aachen_data = kapture_from_dir(tmpdirname)
            self.assertTrue(equal_kapture(imported_aachen_data,
                                          expected_kdata))

        # test with filter list
        with tempfile.TemporaryDirectory() as tmpdirname:
            import_nvm(nvm_path,
                       self.images_folder,
                       tmpdirname,
                       filter_list_path=self.filter,
                       ignore_trajectories=True,
                       add_reconstruction=False,
                       force_overwrite_existing=True)

            imported_aachen_data = kapture_from_dir(tmpdirname)
            self.assertTrue(
                len(imported_aachen_data.records_camera.key_pairs()) == 2)
            images_set = {
                image_path
                for _, _, image_path in kapture.flatten(
                    imported_aachen_data.records_camera)
            }
            self.assertTrue('db/1045.jpg' in images_set)
            self.assertFalse('db/4446.jpg' in images_set)
            self.assertTrue('db/1135.jpg' in images_set)
            self.assertIsNone(imported_aachen_data.trajectories)
            self.assertIsNone(imported_aachen_data.points3d)
示例#3
0
 def test_kapture_format_version_memory(self):
     kapture_data = kapture.Kapture()
     kapture_data.sensors = kapture.Sensors()
     csv.kapture_to_dir(self._tempdir.name, kapture_data)
     kapture_read = csv.kapture_from_dir(self._tempdir.name)
     self.assertEqual(csv.current_format_version(), kapture_read.format_version, "We have the current version")
示例#4
0
 def test_read_write(self):
     kapture_data = csv.kapture_from_dir(self._samples_folder)
     csv.kapture_to_dir(self._tempdir.name, kapture_data)
示例#5
0
def extract_kapture_keypoints(args):
    """
    Extract r2d2 keypoints and descritors to the kapture format directly 
    """
    print('extract_kapture_keypoints...')
    kdata = kapture_from_dir(args.kapture_root,
                             matches_pairs_file_path=None,
                             skip_list=[
                                 kapture.GlobalFeatures, kapture.Matches,
                                 kapture.Points3d, kapture.Observations
                             ])

    assert kdata.records_camera is not None
    image_list = [
        filename for _, _, filename in kapture.flatten(kdata.records_camera)
    ]
    if kdata.keypoints is not None and kdata.descriptors is not None:
        image_list = [
            name for name in image_list
            if name not in kdata.keypoints or name not in kdata.descriptors
        ]

    if len(image_list) == 0:
        print('All features were already extracted')
        return
    else:
        print(f'Extracting r2d2 features for {len(image_list)} images')

    iscuda = common.torch_set_gpu(args.gpu)

    # load the network...
    net = load_network(args.model)
    if iscuda: net = net.cuda()

    # create the non-maxima detector
    detector = NonMaxSuppression(rel_thr=args.reliability_thr,
                                 rep_thr=args.repeatability_thr)

    keypoints_dtype = None if kdata.keypoints is None else kdata.keypoints.dtype
    descriptors_dtype = None if kdata.descriptors is None else kdata.descriptors.dtype

    keypoints_dsize = None if kdata.keypoints is None else kdata.keypoints.dsize
    descriptors_dsize = None if kdata.descriptors is None else kdata.descriptors.dsize

    for image_name in image_list:
        img_path = get_image_fullpath(args.kapture_root, image_name)

        print(f"\nExtracting features for {img_path}")
        img = Image.open(img_path).convert('RGB')
        W, H = img.size
        img = norm_RGB(img)[None]
        if iscuda: img = img.cuda()

        # extract keypoints/descriptors for a single image
        xys, desc, scores = extract_multiscale(net,
                                               img,
                                               detector,
                                               scale_f=args.scale_f,
                                               min_scale=args.min_scale,
                                               max_scale=args.max_scale,
                                               min_size=args.min_size,
                                               max_size=args.max_size,
                                               verbose=True)

        xys = xys.cpu().numpy()
        desc = desc.cpu().numpy()
        scores = scores.cpu().numpy()
        idxs = scores.argsort()[-args.top_k or None:]

        xys = xys[idxs]
        desc = desc[idxs]
        if keypoints_dtype is None or descriptors_dtype is None:
            keypoints_dtype = xys.dtype
            descriptors_dtype = desc.dtype

            keypoints_dsize = xys.shape[1]
            descriptors_dsize = desc.shape[1]

            kdata.keypoints = kapture.Keypoints('r2d2', keypoints_dtype,
                                                keypoints_dsize)
            kdata.descriptors = kapture.Descriptors('r2d2', descriptors_dtype,
                                                    descriptors_dsize)

            keypoints_config_absolute_path = get_csv_fullpath(
                kapture.Keypoints, args.kapture_root)
            descriptors_config_absolute_path = get_csv_fullpath(
                kapture.Descriptors, args.kapture_root)

            keypoints_to_file(keypoints_config_absolute_path, kdata.keypoints)
            descriptors_to_file(descriptors_config_absolute_path,
                                kdata.descriptors)
        else:
            assert kdata.keypoints.type_name == 'r2d2'
            assert kdata.descriptors.type_name == 'r2d2'
            assert kdata.keypoints.dtype == xys.dtype
            assert kdata.descriptors.dtype == desc.dtype
            assert kdata.keypoints.dsize == xys.shape[1]
            assert kdata.descriptors.dsize == desc.shape[1]

        keypoints_fullpath = get_keypoints_fullpath(args.kapture_root,
                                                    image_name)
        print(f"Saving {xys.shape[0]} keypoints to {keypoints_fullpath}")
        image_keypoints_to_file(keypoints_fullpath, xys)
        kdata.keypoints.add(image_name)

        descriptors_fullpath = get_descriptors_fullpath(
            args.kapture_root, image_name)
        print(f"Saving {desc.shape[0]} descriptors to {descriptors_fullpath}")
        image_descriptors_to_file(descriptors_fullpath, desc)
        kdata.descriptors.add(image_name)

    if not keypoints_check_dir(kdata.keypoints, args.kapture_root) or \
            not descriptors_check_dir(kdata.descriptors, args.kapture_root):
        print(
            'local feature extraction ended successfully but not all files were saved'
        )
示例#6
0
def compute_image_pairs(mapping_path: str, query_path: str, output_path: str,
                        topk: int):
    """
    compute image pairs between query -> mapping from global features, and write the result in a text file

    :param mapping_path: input path to kapture input root directory
    :type mapping_path: str
    :param query_path: input path to a kapture root directory
    :type query_path: str
    :param output_path: output path to pairsfile
    :type output_path: str
    :param topk: the max number of top retained images
    :type topk: int
    """
    logger.info(f'compute_image_pairs. loading mapping: {mapping_path}')
    kdata_mapping = kapture_from_dir(mapping_path)
    assert kdata_mapping.sensors is not None
    assert kdata_mapping.records_camera is not None
    assert kdata_mapping.global_features is not None

    if mapping_path == query_path:
        kdata_query = kdata_mapping
    else:
        logger.info(f'compute_image_pairs. loading query: {query_path}')
        kdata_query = kapture_from_dir(query_path)
        assert kdata_query.sensors is not None
        assert kdata_query.records_camera is not None
        assert kdata_query.global_features is not None

    assert kdata_mapping.global_features is not None
    assert kdata_query.global_features is not None
    assert kdata_mapping.global_features.type_name == kdata_query.global_features.type_name
    assert kdata_mapping.global_features.dtype == kdata_query.global_features.dtype
    assert kdata_mapping.global_features.dsize == kdata_query.global_features.dsize
    global_features_config = ImageFeatureConfig(
        kdata_mapping.global_features.type_name,
        kdata_mapping.global_features.dtype,
        kdata_mapping.global_features.dsize)

    logger.info(
        f'computing pairs from with {kdata_mapping.global_features.type_name}...'
    )

    mapping_global_features_to_filepaths = global_features_to_filepaths(
        kdata_mapping.global_features, mapping_path)
    mapping_list = list(
        kapture.flatten(mapping_global_features_to_filepaths, is_sorted=True))
    mapping_indexes, mapping_features = stack_global_features(
        global_features_config, mapping_list)

    if mapping_path == query_path:
        query_indexes, query_features = mapping_indexes, mapping_features
    else:
        query_global_features_to_filepaths = global_features_to_filepaths(
            kdata_query.global_features, query_path)
        query_list = list(
            kapture.flatten(query_global_features_to_filepaths,
                            is_sorted=True))
        query_indexes, query_features = stack_global_features(
            global_features_config, query_list)
    # compute similarity matrix
    similarity_matrix = query_features.dot(mapping_features.T)

    # convert similarity matrix to dictionary query_name -> sorted (high score first) list [(mapping_name, score), ...]
    similarity_dict = {}
    for i, line in enumerate(similarity_matrix):
        scores = line
        indexes = np.argsort(-scores)
        query_name = query_indexes[i]
        similarity_dict[query_name] = list(
            zip(mapping_indexes[indexes], scores[indexes]))

    # get list of image pairs
    image_pairs = []
    for query_image_name, images_to_match in sorted(similarity_dict.items()):
        for mapping_image_name, score in images_to_match[:topk]:
            image_pairs.append([query_image_name, mapping_image_name, score])

    logger.info('saving to file  ...')
    p = pathlib.Path(output_path)
    os.makedirs(str(p.parent.resolve()), exist_ok=True)
    with open(output_path, 'w') as fid:
        table_to_file(fid,
                      image_pairs,
                      header='# query_image, map_image, score')
    logger.info('all done')
示例#7
0
def extract_kapture_global_features(kapture_root_path: str,
                                    net,
                                    global_features_type: str,
                                    trfs,
                                    pooling='mean',
                                    gemp=3,
                                    whiten=None,
                                    threads=8,
                                    batch_size=16):
    """ Extract features from trained model (network) on a given dataset.
    """
    print(f'loading {kapture_root_path}')
    with get_all_tar_handlers(kapture_root_path,
                              mode={
                                  kapture.Keypoints: 'r',
                                  kapture.Descriptors: 'r',
                                  kapture.GlobalFeatures: 'a',
                                  kapture.Matches: 'r'
                              }) as tar_handlers:
        kdata = kapture_from_dir(kapture_root_path,
                                 None,
                                 skip_list=[
                                     kapture.Keypoints, kapture.Descriptors,
                                     kapture.Matches, kapture.Points3d,
                                     kapture.Observations
                                 ],
                                 tar_handlers=tar_handlers)
        root = get_image_fullpath(kapture_root_path, image_filename=None)
        assert kdata.records_camera is not None
        imgs = [
            image_name
            for _, _, image_name in kapture.flatten(kdata.records_camera)
        ]
        if kdata.global_features is None:
            kdata.global_features = {}

        if global_features_type in kdata.global_features:
            imgs = [
                image_name for image_name in imgs if image_name not in
                kdata.global_features[global_features_type]
            ]
        if len(imgs) == 0:
            print('All global features are already extracted')
            return

        dataset = ImageList(img_list_path=None, root=root, imgs=imgs)

        print(f'\nEvaluation on {dataset}')
        # extract DB feats
        bdescs = []
        trfs_list = [trfs] if isinstance(trfs, str) else trfs

        for trfs in trfs_list:
            kw = dict(iscuda=net.iscuda,
                      threads=threads,
                      batch_size=batch_size,
                      same_size='Pad' in trfs or 'Crop' in trfs)
            bdescs.append(
                extract_image_features(dataset, trfs, net, desc="DB", **kw))

        # pool from multiple transforms (scales)
        bdescs = tonumpy(F.normalize(pool(bdescs, pooling, gemp), p=2, dim=1))

        if whiten is not None:
            bdescs = common.whiten_features(bdescs, net.pca, **whiten)

        print('writing extracted global features')
        os.umask(0o002)
        gfeat_dtype = bdescs.dtype
        gfeat_dsize = bdescs.shape[1]
        if global_features_type not in kdata.global_features:
            kdata.global_features[
                global_features_type] = kapture.GlobalFeatures(
                    'dirtorch', gfeat_dtype, gfeat_dsize, 'L2')
            global_features_config_absolute_path = get_feature_csv_fullpath(
                kapture.GlobalFeatures, global_features_type,
                kapture_root_path)
            global_features_to_file(
                global_features_config_absolute_path,
                kdata.global_features[global_features_type])
        else:
            assert kdata.global_features[
                global_features_type].dtype == gfeat_dtype
            assert kdata.global_features[
                global_features_type].dsize == gfeat_dsize
            assert kdata.global_features[
                global_features_type].metric_type == 'L2'
        for i in tqdm.tqdm(range(dataset.nimg)):
            image_name = dataset.get_key(i)
            global_feature_fullpath = get_global_features_fullpath(
                global_features_type, kapture_root_path, image_name,
                tar_handlers)
            gfeat_i = bdescs[i, :]
            assert gfeat_i.shape == (gfeat_dsize, )
            image_global_features_to_file(global_feature_fullpath, gfeat_i)
            kdata.global_features[global_features_type].add(image_name)
            del gfeat_i

        del bdescs

        if not global_features_check_dir(
                kdata.global_features[global_features_type],
                global_features_type, kapture_root_path, tar_handlers):
            print(
                'global feature extraction ended successfully but not all files were saved'
            )
        else:
            print('Features extracted.')
示例#8
0
def plot_ply(kapture_path: str, ply_path: str, axis_length: float, only: [],
             skip: []) -> None:
    """
    Plot the kapture data in a PLY file.

    :param kapture_path: top directory of the kapture
    :param ply_path: path to the ply file to create
    :param axis_length: length of axis representation (in world unit)
    :param only: list of the only kapture objects to plot (optional)
    :param skip: list of the kapture objects to skip
    """
    try:
        os.makedirs(ply_path, exist_ok=True)

        logger.info('loading data ...')
        kapture_data = csv.kapture_from_dir(kapture_path)

        def _should_do(choice: str) -> bool:
            return (not only or choice in only) and choice not in skip

        logger.info('plotting  ...')
        if _should_do('rigs') and kapture_data.rigs:
            logger.info(f'creating {len(kapture_data.rigs)} rigs.')
            for rig_id, rig in kapture_data.rigs.items():
                rig_ply_filepath = path.join(ply_path, f'rig_{rig_id}.ply')
                logger.info(f'creating rig file : {rig_ply_filepath}.')
                logger.debug(rig_ply_filepath)
                ply.rig_to_ply(rig_ply_filepath, rig, axis_length)

        if _should_do('trajectories') and kapture_data.trajectories:
            trajectories_ply_filepath = path.join(ply_path, 'trajectories.ply')
            logger.info(
                f'creating trajectories file : {trajectories_ply_filepath}')
            ply.trajectories_to_ply(trajectories_ply_filepath,
                                    kapture_data.trajectories, axis_length)

        if _should_do('points3d') and kapture_data.points3d:
            points3d_ply_filepath = path.join(ply_path, 'points3d.ply')
            logger.info(f'creating 3D points file : {points3d_ply_filepath}')
            ply.points3d_to_ply(points3d_ply_filepath, kapture_data.points3d)

        if _should_do('keypoints') and kapture_data.keypoints:
            logger.info(
                f'creating keypoints in 3D : {kapture.io.features.get_keypoints_fullpath(ply_path)}'
            )
            keypoints_dsize = kapture_data.keypoints.dsize
            keypoints_dtype = kapture_data.keypoints.dtype
            keypoints_filepaths = kapture.io.features.keypoints_to_filepaths(
                kapture_data.keypoints, kapture_path)
            for image_filename, keypoints_filepath in tqdm(
                    keypoints_filepaths.items(),
                    disable=logger.level >= logging.CRITICAL):
                image_filepath = kapture.io.records.get_image_fullpath(
                    kapture_path, image_filename)
                image_keypoints_filepath = kapture.io.features.get_keypoints_fullpath(
                    ply_path, image_filename) + '.jpg'
                image.image_keypoints_to_image_file(image_keypoints_filepath,
                                                    image_filepath,
                                                    keypoints_filepath,
                                                    keypoints_dtype,
                                                    keypoints_dsize)

        logger.info('done.')

    except Exception as e:
        logging.critical(e)
        raise
def evaluate_command_line() -> None:
    """
    Do the evaluation using the parameters given on the command line.
    """
    parser = argparse.ArgumentParser(
        description='Evaluation script for kapture data.')
    parser_verbosity = parser.add_mutually_exclusive_group()
    parser_verbosity.add_argument(
        '-v',
        '--verbose',
        nargs='?',
        default=logging.WARNING,
        const=logging.INFO,
        action=kapture.utils.logging.VerbosityParser,
        help=
        'verbosity level (debug, info, warning, critical, ... or int value) [warning]'
    )
    parser_verbosity.add_argument('-q',
                                  '--silent',
                                  '--quiet',
                                  action='store_const',
                                  dest='verbose',
                                  const=logging.CRITICAL)
    parser.add_argument(
        '-i',
        '--inputs',
        nargs='+',
        help=
        'input path to kapture data root directory. You can compare multiple models'
    )
    parser.add_argument(
        '--labels',
        nargs='+',
        default=[],
        help='labels for inputs. must be of same length as inputs')
    parser.add_argument(
        '-gt',
        '--ground-truth',
        required=True,
        help='input path to data ground truth root directory in kapture format'
    )
    parser.add_argument('-o',
                        '--output',
                        help='output directory.',
                        required=True)
    parser.add_argument(
        '-l',
        '--image-list',
        default="",
        help=
        'optional, path to a text file containing the list of images to consider'
        ' (1 line per image or a pairsfile). if not present, all gt images are used'
    )
    parser.add_argument(
        '--bins',
        nargs='+',
        default=["0.25 2", "0.5 5", "5 10"],
        help='the desired positions/rotations thresholds for bins'
        'format is string : position_threshold_in_m space rotation_threshold_in_degree'
    )
    parser.add_argument(
        '-p',
        '--plot-rotation-threshold',
        default=-1,
        type=float,
        help=
        'rotation threshold for position error threshold plot. negative values -> ignore rotation'
    )
    parser.add_argument('--plot-max',
                        default=100,
                        type=int,
                        help='maximum distance in cm shown in plot')
    parser.add_argument('--plot-title',
                        default="",
                        help='title for position error threshold plot')
    parser.add_argument(
        '--plot-loc',
        default="best",
        choices=[
            'best', 'upper right', 'upper left', 'lower left', 'lower right',
            'right', 'center left', 'center right', 'lower center',
            'upper center', 'center'
        ],
        help='position of plot legend. loc param for plt.legend.')
    parser.add_argument('--plot-font-size',
                        default=15,
                        type=int,
                        help='value for plt.rcParams[\'font.size\']')
    parser.add_argument('--plot-legend-font-size',
                        default=8,
                        type=int,
                        help='value for plt.rcParams[\'legend.fontsize\']')
    parser.add_argument('-f',
                        '-y',
                        '--force',
                        action='store_true',
                        default=False,
                        help='Force delete output directory if already exists')
    args = parser.parse_args()

    logger.setLevel(args.verbose)
    if args.verbose <= logging.DEBUG:
        # also let kapture express its logs
        kapture.utils.logging.getLogger().setLevel(args.verbose)
        kapture_localization.utils.logging.getLogger().setLevel(args.verbose)
    assert (len(args.inputs) > 0)
    if len(args.labels) == 0:
        args.labels = [f'input{i}' for i in range(1, len(args.inputs) + 1)]
    assert (len(args.labels) == len(args.inputs))

    try:
        logger.debug(''.join(
            ['\n\t{:13} = {}'.format(k, v) for k, v in vars(args).items()]))

        os.makedirs(args.output, exist_ok=True)

        logger.debug('loading: {}'.format(args.inputs))
        all_kapture_to_eval = [
            csv.kapture_from_dir(folder) for folder in args.inputs
        ]

        logger.info('loading ground truth data')
        gt_kapture = csv.kapture_from_dir(args.ground_truth)
        assert gt_kapture.records_camera is not None
        assert gt_kapture.trajectories is not None

        if args.image_list:
            with open(args.image_list, 'r') as fid:
                table = table_from_file(fid)
                image_set = {line[0] for line in table}
        else:
            if gt_kapture.rigs is not None:
                gt_trajectories = kapture.rigs_remove(gt_kapture.trajectories,
                                                      gt_kapture.rigs)
            else:
                gt_trajectories = gt_kapture.trajectories
            image_set = set(image_name for ts, sensor_id, image_name in
                            kapture.flatten(gt_kapture.records_camera)
                            if (ts, sensor_id) in gt_trajectories)
        if len(image_set) == 0:
            logger.info(
                'image_set is empty, for some reason, I could not find images to evaluate'
            )
            exit(0)

        results = [
            evaluate(kapture_to_eval, gt_kapture, image_set)
            for kapture_to_eval in all_kapture_to_eval
        ]

        save_evaluation(results, args.output, args.labels, args.bins,
                        args.plot_rotation_threshold, args.plot_max,
                        args.plot_title, args.plot_loc, args.plot_font_size,
                        args.plot_legend_font_size, args.force)

    except Exception as e:
        logger.critical(e)
        if args.verbose > 1:
            raise
def pose_approximation_from_pairsfile(input_path: str, pairsfile_path: str,
                                      output_path: str,
                                      query_path: Optional[str],
                                      topk: Optional[int], method: str,
                                      additional_parameters: dict,
                                      force: bool):
    """
    localize from pairsfile
    """
    os.makedirs(output_path, exist_ok=True)
    delete_existing_kapture_files(output_path, force_erase=force)

    logger.info(f'pose_approximation. loading mapping: {input_path}')
    kdata = kapture_from_dir(input_path,
                             None,
                             skip_list=[
                                 kapture.Keypoints, kapture.Descriptors,
                                 kapture.GlobalFeatures, kapture.Matches,
                                 kapture.Points3d, kapture.Observations
                             ])
    if query_path is not None:
        logger.info(f'pose_approximation. loading query: {query_path}')
        kdata_query = kapture_from_dir(query_path,
                                       skip_list=[
                                           kapture.Keypoints,
                                           kapture.Descriptors,
                                           kapture.GlobalFeatures,
                                           kapture.Matches, kapture.Points3d,
                                           kapture.Observations
                                       ])
    else:
        kdata_query = kdata

    logger.info(f'pose_approximation. loading pairs: {pairsfile_path}')
    similarity_dict = get_ordered_pairs_from_file(pairsfile_path,
                                                  kdata_query.records_camera,
                                                  kdata.records_camera, topk)
    query_images = set(similarity_dict.keys())

    kdata_result = kapture.Kapture(sensors=kapture.Sensors(),
                                   records_camera=kapture.RecordsCamera(),
                                   trajectories=kapture.Trajectories())
    for timestamp, cam_id, image_name in kapture.flatten(
            kdata_query.records_camera):
        if image_name not in query_images:
            continue
        if cam_id not in kdata_result.sensors:
            kdata_result.sensors[cam_id] = kdata_query.sensors[cam_id]
        kdata_result.records_camera[(timestamp, cam_id)] = image_name

    if kdata.rigs is None:
        map_trajectories = kdata.trajectories
    else:
        map_trajectories = kapture.rigs_remove(kdata.trajectories, kdata.rigs)
    training_trajectories_reversed = {
        image_name: map_trajectories[(timestamp, cam_id)]
        for timestamp, cam_id, image_name in kapture.flatten(
            kdata.records_camera) if (timestamp, cam_id) in map_trajectories
    }
    records_camera_reversed = {
        image_name: (timestamp, cam_id)
        for timestamp, cam_id, image_name in kapture.flatten(
            kdata_result.records_camera)
    }

    for image_name, similar_images in similarity_dict.items():
        pose_inv_list = [
            training_trajectories_reversed[k].inverse()
            for k, _ in similar_images
        ]
        timestamp = records_camera_reversed[image_name][0]
        cam_id = records_camera_reversed[image_name][1]

        if method == 'equal_weighted_barycenter':
            weight_list = [
                1.0 / len(pose_inv_list) for _ in range(len(pose_inv_list))
            ]
        else:
            assert 'alpha' in additional_parameters
            alpha = additional_parameters['alpha']
            weights = np.zeros((len(pose_inv_list), ))
            for i, (_, score) in enumerate(similar_images):
                weights[i] = score
            weights[:] = weights[:]**(alpha)
            weights[:] = weights[:] / np.sum(weights[:])
            weight_list = weights.tolist()
        final_pose = average_pose_transform_weighted(pose_inv_list,
                                                     weight_list).inverse()
        kdata_result.trajectories[(timestamp, cam_id)] = final_pose

    kapture_to_dir(output_path, kdata_result)
    logger.info('all done')
def local_sfm(map_plus_query_path: str, map_plus_query_gv_path: str,
              query_path: str, pairsfile_path: str, output_path_root: str,
              colmap_binary: str, force: bool):
    """
    Localize query images in a COLMAP model built from topk retrieved images.

    :param map_plus_query_path: path to the kapture data consisting of mapping and query data (sensors and reconstruction)
    :param map_plus_query_gv_path: path to the kapture data consisting of mapping and query data after geometric verification (sensors and reconstruction)
    :param query_path: path to the query kapture data (sensors)
    :param pairsfile_path: path to the pairsfile that contains the topk retrieved mapping images for each query image
    :param output_path_root: root path where outputs should be stored
    :param colmap_binary: path to the COLMAP binary
    :param force: silently overwrite already existing results
    """

    # load query kapture (we use query kapture to reuse sensor_ids etc.)
    kdata_query = kapture_from_dir(query_path)
    if kdata_query.trajectories:
        logger.warning(
            "Query data contains trajectories: they will be ignored")
        kdata_query.trajectories.clear()
    else:
        kdata_query.trajectories = kapture.Trajectories()

    # load output kapture
    output_path = os.path.join(output_path_root, 'localized')
    if os.path.exists(os.path.join(output_path, 'sensors/trajectories.txt')):
        kdata_output = kapture_from_dir(output_path)
        if kdata_query.records_camera == kdata_output.records_camera and len(
                kdata_output.trajectories) != 0 and not force:
            kdata_query.trajectories = kdata_output.trajectories

    # load kapture maps
    kdata_map = kapture_from_dir(map_plus_query_path)
    if kdata_map.rigs != None:
        rigs_remove_inplace(kdata_map.trajectories, kdata_map.rigs)
    kdata_map_gv = kapture_from_dir(map_plus_query_gv_path)
    if kdata_map_gv.rigs != None:
        rigs_remove_inplace(kdata_map_gv.trajectories, kdata_map_gv.rigs)

    # load pairsfile
    pairs = {}
    with open(pairsfile_path, 'r') as fid:
        table = table_from_file(fid)
        for img_query, img_map, score in table:
            if not img_query in pairs:
                pairs[img_query] = []
            pairs[img_query].append(img_map)

    kdata_sub_colmap_path = os.path.join(output_path_root, 'colmap')
    kdata_reg_query_path = os.path.join(output_path_root, 'query_registered')
    sub_kapture_pairsfile_path = os.path.join(output_path_root,
                                              'tmp_pairs_map.txt')
    query_img_kapture_pairsfile_path = os.path.join(output_path_root,
                                                    'tmp_pairs_query.txt')

    # loop over query images
    for img_query, img_list_map in pairs.items():
        if pose_found(kdata_query, img_query):
            logger.info(f'{img_query} already processed, skipping...')
            continue
        else:
            logger.info(f'processing {img_query}')

        # write pairsfile for sub-kapture
        map_pairs = write_pairfile_from_img_list(img_list_map,
                                                 sub_kapture_pairsfile_path)

        # write pairsfile for query_img_kapture
        query_pairs = write_pairfile_img_vs_img_list(
            img_query, img_list_map, query_img_kapture_pairsfile_path)

        # create sub-kapture
        kdata_sub = sub_kapture_from_img_list(kdata_map, map_plus_query_path,
                                              img_list_map, map_pairs)
        kdata_sub_gv = sub_kapture_from_img_list(kdata_map_gv,
                                                 map_plus_query_gv_path,
                                                 img_list_map, map_pairs)

        # match missing pairs for mapping
        compute_matches_from_loaded_data(map_plus_query_path, kdata_sub,
                                         map_pairs)

        # kdata_sub needs to be re-created to add the new matches
        kdata_sub = sub_kapture_from_img_list(kdata_map, map_plus_query_path,
                                              img_list_map, map_pairs)

        # run colmap gv on missing pairs
        if len(kdata_sub.matches) != len(kdata_sub_gv.matches):
            run_colmap_gv_from_loaded_data(kdata_sub, kdata_sub_gv,
                                           map_plus_query_path,
                                           map_plus_query_gv_path,
                                           colmap_binary, [], True)
            # kdata_sub_gv needs to be re-created to add the new matches
            kdata_sub_gv = sub_kapture_from_img_list(kdata_map_gv,
                                                     map_plus_query_gv_path,
                                                     img_list_map, map_pairs)

        # sanity check
        if len(map_pairs) != len(kdata_sub_gv.matches):
            logger.info(f'not all mapping matches available')

        # build COLMAP map
        try:
            colmap_build_map_from_loaded_data(kdata_sub_gv,
                                              map_plus_query_gv_path,
                                              kdata_sub_colmap_path,
                                              colmap_binary, False, [],
                                              ['model_converter'], True)
        except ValueError:
            logger.info(f'{img_query} was not localized')
            continue

        if not os.path.exists(
                os.path.join(kdata_sub_colmap_path,
                             'reconstruction/images.bin')):
            logger.info(
                f'colmap mapping for {img_query} did not work, image was not localized'
            )
            continue

        # create single image kapture (kdata_sub needs to be recreated because descriptors are deleted in build_colmap_model)
        kdata_sub = sub_kapture_from_img_list(kdata_map, map_plus_query_path,
                                              img_list_map, map_pairs)
        kdata_sub_gv = sub_kapture_from_img_list(kdata_map_gv,
                                                 map_plus_query_gv_path,
                                                 img_list_map, map_pairs)
        query_img_kapture = add_image_to_kapture(kdata_map,
                                                 map_plus_query_path,
                                                 kdata_sub, img_query,
                                                 query_pairs)
        query_img_kapture_gv = add_image_to_kapture(kdata_map_gv,
                                                    map_plus_query_gv_path,
                                                    kdata_sub_gv, img_query,
                                                    query_pairs)

        # match missing pairs for localization
        compute_matches_from_loaded_data(map_plus_query_path,
                                         query_img_kapture, query_pairs)

        # query_img_kapture needs to be re-created to add the new matches
        query_img_kapture = add_image_to_kapture(kdata_map,
                                                 map_plus_query_path,
                                                 kdata_sub, img_query,
                                                 query_pairs)

        # run colmap gv on missing pairs
        if len(query_img_kapture.matches) != len(query_img_kapture_gv.matches):
            run_colmap_gv_from_loaded_data(query_img_kapture,
                                           query_img_kapture_gv,
                                           map_plus_query_path,
                                           map_plus_query_gv_path,
                                           colmap_binary, [], True)
            # query_img_kapture_gv needs to be re-created to add the new matches
            query_img_kapture_gv = add_image_to_kapture(
                kdata_map_gv, map_plus_query_gv_path, kdata_sub_gv, img_query,
                query_pairs)

        # sanity check
        if len(query_pairs) != len(query_img_kapture_gv.matches):
            logger.info(f'not all query matches available')

        # localize in COLMAP map
        try:
            colmap_localize_from_loaded_data(
                query_img_kapture_gv, map_plus_query_gv_path,
                os.path.join(kdata_sub_colmap_path, 'registered'),
                os.path.join(kdata_sub_colmap_path, 'colmap.db'),
                os.path.join(kdata_sub_colmap_path, 'reconstruction'),
                colmap_binary, False, [
                    '--Mapper.ba_refine_focal_length', '0',
                    '--Mapper.ba_refine_principal_point', '0',
                    '--Mapper.ba_refine_extra_params', '0',
                    '--Mapper.min_num_matches', '4',
                    '--Mapper.init_min_num_inliers', '4',
                    '--Mapper.abs_pose_min_num_inliers', '4',
                    '--Mapper.abs_pose_min_inlier_ratio', '0.05',
                    '--Mapper.ba_local_max_num_iterations', '50',
                    '--Mapper.abs_pose_max_error', '20',
                    '--Mapper.filter_max_reproj_error', '12'
                ], [], True)
        except ValueError:
            logger.info(f'{img_query} was not localized')
            continue

        if not os.path.exists(
                os.path.join(os.path.join(kdata_sub_colmap_path, 'registered'),
                             'reconstruction/images.txt')):
            logger.info(
                f'colmap localization of {img_query} did not work, image was not localized'
            )
            continue

        # add to results kapture
        kdata_reg_query = import_colmap(
            kdata_reg_query_path,
            os.path.join(os.path.join(kdata_sub_colmap_path, 'registered'),
                         'colmap.db'),
            os.path.join(os.path.join(kdata_sub_colmap_path, 'registered'),
                         'reconstruction'), None, None, True, True, True,
            TransferAction.skip)

        if add_pose_to_query_kapture(kdata_reg_query, kdata_query, img_query):
            logger.info('successfully localized')

        # write results (after each image to see the progress)
        kapture_to_dir(output_path, kdata_query)

    # clean up (e.g. remove temporal files and folders)
    safe_remove_any_path(kdata_sub_colmap_path, True)
    safe_remove_any_path(kdata_reg_query_path, True)
    safe_remove_file(sub_kapture_pairsfile_path, True)
    safe_remove_file(query_img_kapture_pairsfile_path, True)

    logger.info('all done')
示例#12
0
def compute_image_pairs(mapping_path: str, query_path: str, output_path: str,
                        topk: int):
    """
    compute image pairs between query -> mapping from global features, and write the result in a text file

    :param mapping_path: input path to kapture input root directory
    :type mapping_path: str
    :param query_path: input path to a kapture root directory
    :type query_path: str
    :param output_path: output path to pairsfile
    :type output_path: str
    :param topk: the max number of top retained images
    :type topk: int
    """
    logger.info(f'compute_image_pairs. loading mapping: {mapping_path}')
    kdata_mapping = kapture_from_dir(mapping_path,
                                     None,
                                     skip_list=[
                                         kapture.Keypoints,
                                         kapture.Descriptors, kapture.Matches,
                                         kapture.Observations, kapture.Points3d
                                     ])
    assert kdata_mapping.sensors is not None
    assert kdata_mapping.records_camera is not None
    assert kdata_mapping.global_features is not None

    if mapping_path == query_path:
        kdata_query = kdata_mapping
    else:
        logger.info(f'compute_image_pairs. loading query: {query_path}')
        kdata_query = kapture_from_dir(query_path,
                                       None,
                                       skip_list=[
                                           kapture.Keypoints,
                                           kapture.Descriptors,
                                           kapture.Matches,
                                           kapture.Observations,
                                           kapture.Points3d
                                       ])
        assert kdata_query.sensors is not None
        assert kdata_query.records_camera is not None
        assert kdata_query.global_features is not None

    assert kdata_mapping.global_features is not None
    assert kdata_query.global_features is not None
    assert kdata_mapping.global_features.type_name == kdata_query.global_features.type_name
    assert kdata_mapping.global_features.dtype == kdata_query.global_features.dtype
    assert kdata_mapping.global_features.dsize == kdata_query.global_features.dsize
    global_features_config = ImageFeatureConfig(
        kdata_mapping.global_features.type_name,
        kdata_mapping.global_features.dtype,
        kdata_mapping.global_features.dsize)

    logger.info(
        f'computing pairs with {kdata_mapping.global_features.type_name}...')

    mapping_global_features_to_filepaths = global_features_to_filepaths(
        kdata_mapping.global_features, mapping_path)
    mapping_list = list(
        kapture.flatten(mapping_global_features_to_filepaths, is_sorted=True))
    mapping_stacked_features = stack_global_features(global_features_config,
                                                     mapping_list)

    if mapping_path == query_path:
        query_stacked_features = mapping_stacked_features
    else:
        query_global_features_to_filepaths = global_features_to_filepaths(
            kdata_query.global_features, query_path)
        query_list = list(
            kapture.flatten(query_global_features_to_filepaths,
                            is_sorted=True))
        query_stacked_features = stack_global_features(global_features_config,
                                                       query_list)

    similarity = get_similarity(query_stacked_features,
                                mapping_stacked_features)

    # get list of image pairs
    image_pairs = get_image_pairs(similarity, topk)

    logger.info('saving to file  ...')
    p = pathlib.Path(output_path)
    os.makedirs(str(p.parent.resolve()), exist_ok=True)
    with open(output_path, 'w') as fid:
        table_to_file(fid,
                      image_pairs,
                      header='# query_image, map_image, score')
    logger.info('all done')
def local_sfm_from_loaded_data(kdata_map: kapture.Kapture,
                               kdata_map_gv: kapture.Kapture,
                               kdata_query: kapture.Kapture,
                               map_plus_query_path: str,
                               map_plus_query_gv_path: str,
                               tar_handlers_map: Optional[TarCollection],
                               tar_handlers_map_gv: Optional[TarCollection],
                               descriptors_type: Optional[str],
                               pairsfile_path: str,
                               output_path_root: str,
                               colmap_binary: str,
                               force: bool):
    """
    Localize query images in a COLMAP model built from topk retrieved images.

    :param map_plus_query_path: path to the kapture data consisting of mapping and query data (sensors and reconstruction)
    :param map_plus_query_gv_path: path to the kapture data consisting of mapping and query data after geometric verification (sensors and reconstruction)
    :param query_path: path to the query kapture data (sensors)
    :param descriptors_type: type of descriptors, name of the descriptors subfolder
    :param pairsfile_path: path to the pairsfile that contains the topk retrieved mapping images for each query image
    :param output_path_root: root path where outputs should be stored
    :param colmap_binary: path to the COLMAP binary
    :param force: silently overwrite already existing results
    """

    # load query kapture (we use query kapture to reuse sensor_ids etc.)
    if kdata_query.trajectories:
        logger.warning("Query data contains trajectories: they will be ignored")
        kdata_query.trajectories.clear()
    else:
        kdata_query.trajectories = kapture.Trajectories()

    # clear query trajectories in map_plus_query
    kdata_map_cleared_trajectories = kapture.Trajectories()
    query_image_list = set(kdata_query.records_camera.data_list())
    for timestamp, subdict in kdata_map.records_camera.items():
        for sensor_id, image_name in subdict.items():
            if image_name in query_image_list:
                continue
            if (timestamp, sensor_id) in kdata_map.trajectories:
                pose = kdata_map.trajectories.get(timestamp)[sensor_id]
                kdata_map_cleared_trajectories.setdefault(timestamp, {})[sensor_id] = pose
    kdata_map.trajectories = kdata_map_cleared_trajectories

    # load output kapture
    output_path = os.path.join(output_path_root, 'localized')
    if os.path.exists(os.path.join(output_path, 'sensors/trajectories.txt')):
        kdata_output = kapture_from_dir(output_path)
        if kdata_query.records_camera == kdata_output.records_camera and len(
                kdata_output.trajectories) != 0 and not force:
            kdata_query.trajectories = kdata_output.trajectories

    if kdata_map.rigs is not None:
        rigs_remove_inplace(kdata_map.trajectories, kdata_map.rigs)
    if kdata_map_gv.rigs is not None:
        rigs_remove_inplace(kdata_map_gv.trajectories, kdata_map_gv.rigs)

    # load pairsfile
    pairs = {}
    with open(pairsfile_path, 'r') as fid:
        table = table_from_file(fid)
        for img_query, img_map, _ in table:
            if img_query not in pairs:
                pairs[img_query] = []
            pairs[img_query].append(img_map)

    kdata_sub_colmap_path = os.path.join(output_path_root, 'colmap')
    kdata_reg_query_path = os.path.join(output_path_root, 'query_registered')
    sub_kapture_pairsfile_path = os.path.join(output_path_root, 'tmp_pairs.txt')

    if descriptors_type is None:
        descriptors_type = try_get_only_key_from_collection(kdata_map.descriptors)
    assert descriptors_type is not None
    assert descriptors_type in kdata_map.descriptors
    keypoints_type = kdata_map.descriptors[descriptors_type].keypoints_type

    # init matches for kdata_map and kdata_map_gv
    if kdata_map.matches is None:
        kdata_map.matches = {}
    if keypoints_type not in kdata_map.matches:
        kdata_map.matches[keypoints_type] = kapture.Matches()
    if kdata_map_gv.matches is None:
        kdata_map_gv.matches = {}
    if keypoints_type not in kdata_map_gv.matches:
        kdata_map_gv.matches[keypoints_type] = kapture.Matches()

    # run all matching
    # loop over query images
    img_skip_list = set()
    for img_query, img_list_map in pairs.items():
        if pose_found(kdata_query, img_query):
            logger.info(f'{img_query} already processed, skipping...')
            img_skip_list.add(img_query)
            continue
        else:
            map_pairs = get_pairfile_from_img_list(img_list_map)
            query_pairs = get_pairfile_img_vs_img_list(img_query, img_list_map)
            with open(sub_kapture_pairsfile_path, 'w') as fid:
                logger.info(f'matching for {img_query}')
                table_to_file(fid, map_pairs)
                table_to_file(fid, query_pairs)

            pairs_all = map_pairs + query_pairs
            pairs_all = [(i, j) for i, j, _ in pairs_all]
            # match missing pairs
            # kdata_map.matches is being updated by compute_matches_from_loaded_data
            compute_matches_from_loaded_data(map_plus_query_path,
                                             tar_handlers_map,
                                             kdata_map,
                                             descriptors_type,
                                             pairs_all)

    # if kdata_map have matches in tar, they need to be switched to read mode
    matches_handler = retrieve_tar_handler_from_collection(kapture.Matches, keypoints_type, tar_handlers_map)
    if matches_handler is not None:
        matches_handler.close()
        tarfile_path = get_feature_tar_fullpath(kapture.Matches, keypoints_type, map_plus_query_path)
        tar_handlers_map.matches[keypoints_type] = TarHandler(tarfile_path, 'r')

    # run all gv
    # loop over query images
    for img_query, img_list_map in pairs.items():
        if img_query in img_skip_list:
            continue
        else:
            # recompute the pairs
            map_pairs = get_pairfile_from_img_list(img_list_map)
            query_pairs = get_pairfile_img_vs_img_list(img_query, img_list_map)
            with open(sub_kapture_pairsfile_path, 'w') as fid:
                logger.info(f'geometric verification of {img_query}')
                table_to_file(fid, map_pairs)
                table_to_file(fid, query_pairs)

            pairs_all = map_pairs + query_pairs
            pairs_all = [(i, j) for i, j, _ in pairs_all]

            if all(pair in kdata_map_gv.matches[keypoints_type] for pair in pairs_all):
                continue

            # create a sub kapture in order to minimize the amount of data exported to colmap
            # kdata_sub needs to be re-created to add the new matches
            kdata_sub = sub_kapture_from_img_list(kdata_map, img_list_map + [img_query], pairs_all,
                                                  keypoints_type, descriptors_type)

            kdata_sub_gv = sub_kapture_from_img_list(kdata_map_gv, img_list_map + [img_query], pairs_all,
                                                     keypoints_type, descriptors_type)
            # run colmap gv on missing pairs
            run_colmap_gv_from_loaded_data(kdata_sub,
                                           kdata_sub_gv,
                                           map_plus_query_path,
                                           map_plus_query_gv_path,
                                           tar_handlers_map,
                                           tar_handlers_map_gv,
                                           colmap_binary,
                                           keypoints_type,
                                           [],
                                           True)
            # update kdata_map_gv.matches
            kdata_map_gv.matches[keypoints_type].update(kdata_sub_gv.matches[keypoints_type])

    # if kdata_map_gv have matches in tar, they need to be switched to read mode
    matches_gv_handler = retrieve_tar_handler_from_collection(kapture.Matches, keypoints_type, tar_handlers_map_gv)
    if matches_gv_handler is not None:
        print(matches_gv_handler)
        matches_gv_handler.close()
        tarfile_path = get_feature_tar_fullpath(kapture.Matches, keypoints_type, map_plus_query_gv_path)
        tar_handlers_map_gv.matches[keypoints_type] = TarHandler(tarfile_path, 'r')

    # loop over query images
    for img_query, img_list_map in pairs.items():
        if img_query in img_skip_list:
            continue
        else:
            map_pairs = get_pairfile_from_img_list(img_list_map)
            with open(sub_kapture_pairsfile_path, 'w') as fid:
                logger.info(f'mapping and localization for {img_query}')
                table_to_file(fid, map_pairs)
            map_pairs = [(i, j) for i, j, _ in map_pairs]
            kdata_sub_gv = sub_kapture_from_img_list(kdata_map_gv, img_list_map, map_pairs,
                                                     keypoints_type, descriptors_type)
            # sanity check
            if len(map_pairs) != len(kdata_sub_gv.matches[keypoints_type]):
                logger.info(f'not all mapping matches available')

            # build COLMAP map
            try:
                colmap_build_map_from_loaded_data(
                    kdata_sub_gv,
                    map_plus_query_gv_path,
                    tar_handlers_map_gv,
                    kdata_sub_colmap_path,
                    colmap_binary,
                    keypoints_type,
                    False,
                    [],
                    ['model_converter'],
                    True)
            except ValueError:
                logger.info(f'{img_query} was not localized')
                continue

        if not os.path.exists(os.path.join(kdata_sub_colmap_path, 'reconstruction/images.bin')):
            logger.info(f'colmap mapping for {img_query} did not work, image was not localized')
            continue

        query_pairs = get_pairfile_img_vs_img_list(img_query, img_list_map)
        with open(sub_kapture_pairsfile_path, 'w') as fid:
            table_to_file(fid, query_pairs)
        query_pairs = [(i, j) for i, j, _ in query_pairs]
        query_img_kapture_gv = add_image_to_kapture(kdata_map_gv,
                                                    kdata_sub_gv, img_query, query_pairs,
                                                    keypoints_type, descriptors_type)
        # sanity check
        if len(query_pairs) != len(query_img_kapture_gv.matches[keypoints_type]):
            logger.info(f'not all query matches available')

        # localize in COLMAP map
        try:
            colmap_localize_from_loaded_data(
                query_img_kapture_gv,
                map_plus_query_gv_path,
                tar_handlers_map_gv,
                os.path.join(kdata_sub_colmap_path, 'registered'),
                os.path.join(kdata_sub_colmap_path, 'colmap.db'),
                os.path.join(kdata_sub_colmap_path, 'reconstruction'),
                colmap_binary,
                keypoints_type,
                False,
                ['--Mapper.ba_refine_focal_length', '0',
                 '--Mapper.ba_refine_principal_point', '0',
                 '--Mapper.ba_refine_extra_params', '0',
                 '--Mapper.min_num_matches', '4',
                 '--Mapper.init_min_num_inliers', '4',
                 '--Mapper.abs_pose_min_num_inliers', '4',
                 '--Mapper.abs_pose_min_inlier_ratio', '0.05',
                 '--Mapper.ba_local_max_num_iterations', '50',
                 '--Mapper.abs_pose_max_error', '20',
                 '--Mapper.filter_max_reproj_error', '12'],
                [],
                True)
        except ValueError:
            logger.info(f'{img_query} was not localized')
            continue

        if not os.path.exists(os.path.join(os.path.join(kdata_sub_colmap_path, 'registered'),
                                           'reconstruction/images.txt')):
            logger.info(f'colmap localization of {img_query} did not work, image was not localized')
            continue

        # add to results kapture
        kdata_reg_query = import_colmap(
            kdata_reg_query_path,
            os.path.join(os.path.join(kdata_sub_colmap_path, 'registered'), 'colmap.db'),
            os.path.join(os.path.join(kdata_sub_colmap_path, 'registered'),
                         'reconstruction'),
            None,
            None,
            True,
            True,
            True,
            TransferAction.skip)

        if add_pose_to_query_kapture(kdata_reg_query, kdata_query, img_query):
            logger.info('successfully localized')

        # write results (after each image to see the progress)
        kapture_to_dir(output_path, kdata_query)

    # clean up (e.g. remove temporal files and folders)
    safe_remove_any_path(kdata_sub_colmap_path, True)
    safe_remove_any_path(kdata_reg_query_path, True)
    safe_remove_file(sub_kapture_pairsfile_path, True)

    logger.info('all done')
示例#14
0
                    default=float("+inf"),
                    help='max number of keypoints save to disk')

args = parser.parse_args()

print(args)
with get_all_tar_handlers(args.kapture_root,
                          mode={
                              kapture.Keypoints: 'a',
                              kapture.Descriptors: 'a',
                              kapture.GlobalFeatures: 'r',
                              kapture.Matches: 'r'
                          }) as tar_handlers:
    kdata = kapture_from_dir(args.kapture_root,
                             skip_list=[
                                 kapture.GlobalFeatures, kapture.Matches,
                                 kapture.Points3d, kapture.Observations
                             ],
                             tar_handlers=tar_handlers)
    if kdata.keypoints is None:
        kdata.keypoints = {}
    if kdata.descriptors is None:
        kdata.descriptors = {}

    assert kdata.records_camera is not None
    image_list = [
        filename for _, _, filename in kapture.flatten(kdata.records_camera)
    ]
    if args.keypoints_type is None:
        args.keypoints_type = path.splitext(path.basename(args.model_file))[0]
        print(f'keypoints_type set to {args.keypoints_type}')
    if args.descriptors_type is None:
示例#15
0
def compute_image_pairs(mapping_path: str, query_path: str, output_path: str,
                        global_features_type: Optional[str], topk: int):
    """
    compute image pairs between query -> mapping from global features, and write the result in a text file

    :param mapping_path: input path to kapture input root directory
    :type mapping_path: str
    :param query_path: input path to a kapture root directory
    :type query_path: str
    :param output_path: output path to pairsfile
    :type output_path: str
    :param global_features_type: type of global_features, name of the global_features subfolder
    :param topk: the max number of top retained images
    :type topk: int
    """
    logger.info(f'compute_image_pairs. loading mapping: {mapping_path}')
    with get_all_tar_handlers(mapping_path) as mapping_tar_handlers:
        kdata_mapping = kapture_from_dir(mapping_path,
                                         None,
                                         skip_list=[
                                             kapture.Keypoints,
                                             kapture.Descriptors,
                                             kapture.Matches,
                                             kapture.Observations,
                                             kapture.Points3d
                                         ],
                                         tar_handlers=mapping_tar_handlers)
        assert kdata_mapping.sensors is not None
        assert kdata_mapping.records_camera is not None
        assert kdata_mapping.global_features is not None
        if global_features_type is None:
            global_features_type = try_get_only_key_from_collection(
                kdata_mapping.global_features)
        assert global_features_type is not None
        assert global_features_type in kdata_mapping.global_features

        global_features_config = GlobalFeaturesConfig(
            kdata_mapping.global_features[global_features_type].type_name,
            kdata_mapping.global_features[global_features_type].dtype,
            kdata_mapping.global_features[global_features_type].dsize,
            kdata_mapping.global_features[global_features_type].metric_type)

        logger.info(f'computing pairs with {global_features_type}...')

        mapping_global_features_to_filepaths = global_features_to_filepaths(
            kdata_mapping.global_features[global_features_type],
            global_features_type, mapping_path, mapping_tar_handlers)
        mapping_list = list(
            sorted(mapping_global_features_to_filepaths.items()))
        mapping_stacked_features = stack_global_features(
            global_features_config, mapping_list)

    if mapping_path == query_path:
        kdata_query = kdata_mapping
        query_stacked_features = mapping_stacked_features
    else:
        logger.info(f'compute_image_pairs. loading query: {query_path}')
        with get_all_tar_handlers(query_path) as query_tar_handlers:
            kdata_query = kapture_from_dir(query_path,
                                           None,
                                           skip_list=[
                                               kapture.Keypoints,
                                               kapture.Descriptors,
                                               kapture.Matches,
                                               kapture.Observations,
                                               kapture.Points3d
                                           ],
                                           tar_handlers=query_tar_handlers)
            assert kdata_query.sensors is not None
            assert kdata_query.records_camera is not None
            assert kdata_query.global_features is not None
            assert global_features_type in kdata_query.global_features

            kdata_mapping_gfeat = kdata_mapping.global_features[
                global_features_type]
            kdata_query_gfeat = kdata_query.global_features[
                global_features_type]
            assert kdata_mapping_gfeat.type_name == kdata_query_gfeat.type_name
            assert kdata_mapping_gfeat.dtype == kdata_query_gfeat.dtype
            assert kdata_mapping_gfeat.dsize == kdata_query_gfeat.dsize

            query_global_features_to_filepaths = global_features_to_filepaths(
                kdata_query_gfeat, global_features_type, query_path,
                query_tar_handlers)
            query_list = list(
                sorted(query_global_features_to_filepaths.items()))
            query_stacked_features = stack_global_features(
                global_features_config, query_list)

    similarity = get_similarity(query_stacked_features,
                                mapping_stacked_features)

    # get list of image pairs
    image_pairs = get_image_pairs(similarity, topk)

    logger.info('saving to file  ...')
    p = pathlib.Path(output_path)
    os.makedirs(str(p.parent.resolve()), exist_ok=True)
    with open(output_path, 'w') as fid:
        table_to_file(fid,
                      image_pairs,
                      header='# query_image, map_image, score')
    logger.info('all done')
示例#16
0
def export_colmap(kapture_dirpath: str,
                  colmap_database_filepath: str,
                  colmap_reconstruction_dirpath: Optional[str],
                  colmap_rig_filepath: str = None,
                  force_overwrite_existing: bool = False) -> None:
    """
    Exports kapture data to colmap database and or reconstruction text files.

    :param kapture_dirpath: kapture top directory
    :param colmap_database_filepath: path to colmap database file
    :param colmap_reconstruction_dirpath: path to colmap reconstruction directory
    :param colmap_rig_filepath: path to colmap rig file
    :param force_overwrite_existing: Silently overwrite colmap files if already exists.
    """

    os.makedirs(path.dirname(colmap_database_filepath), exist_ok=True)
    if colmap_reconstruction_dirpath:
        os.makedirs(colmap_reconstruction_dirpath, exist_ok=True)

    assert colmap_database_filepath
    if path.isfile(colmap_database_filepath):
        to_delete = force_overwrite_existing or (input(
            'database file already exist, would you like to delete it ? [y/N]'
        ).lower() == 'y')
        if to_delete:
            logger.info('deleting already existing {}'.format(
                colmap_database_filepath))
            os.remove(colmap_database_filepath)

    logger.info(
        'creating colmap database in {}'.format(colmap_database_filepath))
    db = COLMAPDatabase.connect(colmap_database_filepath)
    if not is_colmap_db_empty(db):
        raise ValueError(
            'the existing colmap database is not empty : {}'.format(
                colmap_database_filepath))

    logger.info('loading kapture files...')
    kapture_data = csv.kapture_from_dir(kapture_dirpath)
    assert isinstance(kapture_data, kapture.Kapture)

    # COLMAP does not fully support rigs.
    if kapture_data.rigs is not None:
        # make sure, rigs are not used in trajectories.
        logger.info('remove rigs notation.')
        rigs_remove_inplace(kapture_data.trajectories, kapture_data.rigs)

    # write colmap database
    kapture_to_colmap(kapture_data, kapture_dirpath, db)

    if colmap_reconstruction_dirpath:
        # create text files
        colmap_camera_ids = get_colmap_camera_ids_from_db(
            db, kapture_data.records_camera)
        colmap_image_ids = get_colmap_image_ids_from_db(db)
        export_to_colmap_txt(
            colmap_reconstruction_dirpath=colmap_reconstruction_dirpath,
            kapture_data=kapture_data,
            kapture_dirpath=kapture_dirpath,
            colmap_camera_ids=colmap_camera_ids,
            colmap_image_ids=colmap_image_ids)
        if colmap_rig_filepath:
            try:
                if kapture_data.rigs is None:
                    raise ValueError('No rig to export.')
                export_colmap_rigs(colmap_rig_filepath, kapture_data.rigs,
                                   kapture_data.records_camera,
                                   colmap_camera_ids)
            except Exception as e:
                warnings.warn(e)
                logger.warning(e)

    db.close()
def extract_kapture_global(kapture_root,
                           config,
                           output_dir='',
                           overwrite=False):
    logging.info('Extracting NetVLAD features with configuration:\n', config)
    # use kapture io to identify image paths and loop
    kdata = kapture_from_dir(kapture_root, matches_pairsfile_path=None,
                             skip_list= [kapture.Matches,
                                         kapture.Points3d,
                                         kapture.Observations,
                                         kapture.Keypoints,
                                         kapture.Descriptors])
    assert kdata.records_camera is not None

    export_dir = output_dir if output_dir else kapture_root  # root of output directory for features
    os.makedirs(export_dir, exist_ok=True)

    image_list = [filename for _, _, filename in kapture.flatten(kdata.records_camera)]

    # resume extraction if some features exist
    try:
        # load features if there are any
        kdata.global_features = global_features_from_dir(export_dir, None)
        if kdata.global_features is not None and not overwrite:
            image_list = [name for name in image_list if name not in kdata.global_features]
    except FileNotFoundError:
        pass
    except:
        logging.exception("Error with importing existing global features.")

    # clear features first if overwriting
    if overwrite: delete_existing_kapture_files(export_dir, True, only=[kapture.GlobalFeatures])

    if len(image_list) == 0:
        print('All features were already extracted')
        return
    else:
        print(f'Extracting NetVLAD features for {len(image_list)} images')

    # for the global descriptor type specification
    global_dtype = None if kdata.global_features is None else kdata.global_features.dtype
    global_dsize = None if kdata.global_features is None else kdata.global_features.dsize

    # setup network
    tf.reset_default_graph()
    if config['grayscale']:
        tf_batch = tf.placeholder(
                dtype=tf.float32, shape=[None, None, None, 1])
    else:
        tf_batch = tf.placeholder(
                dtype=tf.float32, shape=[None, None, None, 3])
    # load network and checkpoint
    net = nets.vgg16NetvladPca(tf_batch)
    saver = tf.train.Saver()
    sess = tf.Session()
    checkpoint = chkpt_path + '/' + config['checkpoint']
    saver.restore(sess, checkpoint)

    for image_name in image_list:
        img_path = get_image_fullpath(kapture_root, image_name)
        if img_path.endswith('.txt'):
            args.images = open(img_path).read().splitlines() + args.images
            continue

        print(f"\nExtracting features for {img_path}")

        if config['grayscale']:
            image = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
            image = np.expand_dims(
                np.expand_dims(image, axis=0), axis=-1)
        else:
            image = cv2.imread(img_path, cv2.COLOR_BGR2RGB)
            image = np.expand_dims(image, axis=0)
        descriptor = sess.run(net, feed_dict={tf_batch: image})[:, :config['pca_dim']]
        descriptor = np.squeeze(descriptor)


        # write global descriptor type specification
        if global_dtype is None:
            global_dtype = descriptor.dtype
            global_dsize = len(descriptor)

            kdata.global_features = kapture.GlobalFeatures('netvlad', global_dtype, global_dsize)

            global_descriptors_config_abs_path = get_csv_fullpath(kapture.GlobalFeatures, export_dir)
            descriptors_to_file(global_descriptors_config_abs_path, kdata.global_features)
        else:
            assert kdata.global_features.type_name == "netvlad"
            assert kdata.global_features.dtype == descriptor.dtype
            assert kdata.global_features.dsize == len(descriptor)
        # get output paths
        global_descriptors_abs_path = get_global_features_fullpath(export_dir, image_name)

        image_global_features_to_file(global_descriptors_abs_path, descriptor)
        kdata.global_features.add(image_name)
    # sess.close()  # close session before initializing again for next submap

    if not global_features_check_dir(kdata.global_features, export_dir):
        print('global feature extraction ended successfully but not all files were saved')