示例#1
0
 def test_non_matching_stats_keys(self):
     r1 = result.Result()
     r1.add_stats({"bla": 1., "blub": 2.})
     r2 = result.Result()
     r2.add_stats({"foo": 1., "bar": 2.})
     with self.assertRaises(result.ResultException):
         result.merge_results([r1, r2])
示例#2
0
 def test_non_matching_np_arrays_keys(self):
     r1 = result.Result()
     r1.add_np_array("test", np.array([]))
     r1.add_np_array("test_2", np.array([]))
     r2 = result.Result()
     r2.add_np_array("test", np.array([]))
     with self.assertRaises(result.ResultException):
         result.merge_results([r1, r2])
示例#3
0
 def test_merge_strategy_average(self):
     r1 = result.Result()
     r1.add_np_array("test", np.array([1., 2., 3.]))
     r1.add_stats({"bla": 1., "blub": 2.})
     r2 = result.Result()
     r2.add_np_array("test", np.array([0., 0., 0.]))
     r2.add_stats({"bla": 0., "blub": 0.})
     merged = result.merge_results([r1, r2])
     self.assertTrue(
         np.array_equal(merged.np_arrays["test"], np.array([0.5, 1., 1.5])))
     self.assertEqual(merged.stats, {"bla": 0.5, "blub": 1.})
示例#4
0
def load_res_file(zip_path, load_trajectories: bool = False) -> result.Result:
    """
    load contents of a result .zip file saved with save_res_file(...)
    :param zip_path: path to zip file
    :param load_trajectories: set to True to load also the (backup) trajectories
    :return: evo.core.result.Result instance
    """
    logger.debug("Loading result from {} ...".format(zip_path))
    result_obj = result.Result()
    with zipfile.ZipFile(zip_path, mode='r') as archive:
        file_list = archive.namelist()
        if not {"info.json", "stats.json"} <= set(file_list):
            raise FileInterfaceException(
                "{} is not a valid result file".format(zip_path))
        result_obj.info = json.loads(archive.read("info.json").decode("utf-8"))
        result_obj.stats = json.loads(
            archive.read("stats.json").decode("utf-8"))

        # Compatibility: previous evo versions wrote .npz, although it was .npy
        # In any case, np.load() supports both file formats.
        np_files = [f for f in file_list if f.endswith((".npy", ".npz"))]
        for filename in np_files:
            with io.BytesIO(archive.read(filename)) as array_buffer:
                array = np.load(array_buffer)
                name = os.path.splitext(os.path.basename(filename))[0]
                result_obj.add_np_array(name, array)
        if load_trajectories:
            tum_files = [f for f in file_list if f.endswith(".tum")]
            for filename in tum_files:
                with io.TextIOWrapper(archive.open(filename,
                                                   mode='r')) as traj_buffer:
                    traj = read_tum_trajectory_file(traj_buffer)
                    name = os.path.splitext(os.path.basename(filename))[0]
                    result_obj.add_trajectory(name, traj)
            kitti_files = [f for f in file_list if f.endswith(".kitti")]
            for filename in kitti_files:
                with io.TextIOWrapper(archive.open(filename,
                                                   mode='r')) as path_buffer:
                    path = read_kitti_poses_file(path_buffer)
                    name = os.path.splitext(os.path.basename(filename))[0]
                    result_obj.add_trajectory(name, path)
    return result_obj
示例#5
0
def load_res_file(zip_path, load_trajectories=False):
    """
    load contents of a result .zip file saved with save_res_file(...)
    :param zip_path: path to zip file
    :param load_trajectories: set to True to load also the (backup) trajectories
    :return: evo.core.result.Result instance
    """
    logging.debug("loading result from {} ...".format(zip_path))
    result_obj = result.Result()
    with zipfile.ZipFile(zip_path, mode='r') as archive:
        file_list = archive.namelist()
        if not {"error_array.npz", "info.json", "stats.json"
                } <= set(file_list):
            logging.warning(
                "{} has incorrect zip file structure for evo_res".format(
                    zip_path))
        npz_files = [n for n in archive.namelist() if n.endswith(".npz")]
        for filename in npz_files:
            with io.BytesIO(archive.read(filename)) as f:
                array = np.load(f)
                name = os.path.splitext(os.path.basename(filename))[0]
                result_obj.add_np_array(name, array)
        if load_trajectories:
            tum_files = [n for n in archive.namelist() if n.endswith(".tum")]
            for filename in tum_files:
                with io.TextIOWrapper(archive.open(filename, mode='r')) as f:
                    traj = read_tum_trajectory_file(f)
                    name = os.path.splitext(os.path.basename(filename))[0]
                    result_obj.add_trajectory(name, traj)
            kitti_files = [
                n for n in archive.namelist() if n.endswith(".kitti")
            ]
            for filename in kitti_files:
                with io.TextIOWrapper(archive.open(filename, mode='r')) as f:
                    traj = read_kitti_poses_file(f)
                    name = os.path.splitext(os.path.basename(filename))[0]
                    result_obj.add_trajectory(name, traj)
        result_obj.info = json.loads(archive.read("info.json").decode("utf-8"))
        result_obj.stats = json.loads(
            archive.read("stats.json").decode("utf-8"))
    return result_obj
def main_rpe_for_each(traj_ref, traj_est, pose_relation, mode, bins, rel_tols,
                      align=False, correct_scale=False, ref_name="", est_name="",
                      show_plot=False, save_plot=None, save_results=None, no_warnings=False,
                      serialize_plot=None):

    from evo.core import metrics, result
    from evo.core import filters
    from evo.core import trajectory
    from evo.tools import file_interface
    from evo.tools.settings import SETTINGS

    if not bins or not rel_tols:
        raise RuntimeError("bins and tolerances must have more than one element")
    if len(bins) != len(rel_tols):
        raise RuntimeError("bins and tolerances must have the same number of elements")
    if mode in {"speed", "angular_speed"} and traj_est is trajectory.PosePath3D:
        raise RuntimeError("timestamps are required for mode: " + mode)

    bin_unit = None
    if mode == "speed":
        bin_unit = metrics.VelUnit.meters_per_sec
    elif mode == "path":
        bin_unit = metrics.Unit.meters
    elif mode == "angle":
        bin_unit = metrics.Unit.degrees
    elif mode == "angular_speed":
        bin_unit = metrics.VelUnit.degrees_per_sec

    rpe_unit = None
    if pose_relation is metrics.PoseRelation.translation_part:
        rpe_unit = metrics.Unit.meters
    elif pose_relation is metrics.PoseRelation.rotation_angle_deg:
        rpe_unit = metrics.Unit.degrees
    elif pose_relation is metrics.PoseRelation.rotation_angle_rad:
        rpe_unit = metrics.Unit.radians

    correct_only_scale = correct_scale and not align
    if align or correct_scale:
        logger.debug(SEP)
        if correct_only_scale:
            logger.debug("Correcting scale...")
        else:
            logger.debug("Aligning using Umeyama's method..."
                         + (" (with scale correction)" if correct_scale else ""))
        traj_est = trajectory.align_trajectory(traj_est, traj_ref, correct_scale,
                                               correct_only_scale)

    results = []
    for bin, rel_tol, in zip(bins, rel_tols):
        logger.debug(SEP)
        logger.info(
            "Calculating RPE for each sub-sequence of " + str(bin) + " (" + bin_unit.value + ")")

        tol = bin * rel_tol
        id_pairs = []
        if mode == "path":
            id_pairs = filters.filter_pairs_by_path(traj_ref.poses_se3, bin, tol, all_pairs=True)
        elif mode == "angle":
            id_pairs = filters.filter_pairs_by_angle(traj_ref.poses_se3, bin, tol, degrees=True)
        elif mode == "speed":
            id_pairs = filters.filter_pairs_by_speed(traj_ref.poses_se3, traj_ref.timestamps,
                                                     bin, tol)
        elif mode == "angular_speed":
            id_pairs = filters.filter_pairs_by_angular_speed(traj_ref.poses_se3,
                                                             traj_ref.timestamps, bin, tol, True)

        if len(id_pairs) == 0:
            raise RuntimeError("bin " + str(bin) + " (" + str(bin_unit.value) + ") "
                               + "produced empty index list - try other values")

        # calculate RPE with all IDs (delta 1 frames)
        data = (traj_ref, traj_est)
        # the delta here has nothing to do with the bin - 1f delta just to use all poses of the bin
        rpe_metric = metrics.RPE(pose_relation, delta=1, delta_unit=metrics.Unit.frames,
                                 all_pairs=True)
        rpe_metric.process_data(data, id_pairs)
        mean = rpe_metric.get_statistic(metrics.StatisticsType.mean)
        results.append(mean)

    if SETTINGS.plot_usetex:
        mode.replace("_", "\_")
    title = "mean RPE w.r.t. " + pose_relation.value + "\nfor different " + mode + " sub-sequences"
    if align and not correct_scale:
        title += "\n(with SE(3) Umeyama alignment)"
    elif align and correct_scale:
        title += "\n(with Sim(3) Umeyama alignment)"
    elif correct_only_scale:
        title += "\n(scale corrected)"
    else:
        title += "\n(not aligned)"

    rpe_for_each_result = result.Result()
    rpe_for_each_result.add_info({
        "label": "RPE ({})".format(rpe_unit.value),
        "est_name": est_name,
        "ref_name": ref_name,
        "title": title,
        "xlabel": "{} sub-sequences ({})".format(mode, bin_unit.value)
    })
    rpe_for_each_result.add_stats({bin: result for bin, result in zip(bins, results)})
    # TODO use a more suitable name than seconds
    rpe_for_each_result.add_np_array("seconds_from_start", bins)
    rpe_for_each_result.add_np_array("error_array", results)

    logger.debug(SEP)
    logger.info(rpe_for_each_result.pretty_str())

    if show_plot or save_plot or serialize_plot:
        from evo.tools import plot
        import matplotlib.pyplot as plt
        plot_collection = plot.PlotCollection(title)
        fig = plt.figure(figsize=(SETTINGS.plot_figsize[0], SETTINGS.plot_figsize[1]))
        plot.error_array(fig, results, x_array=bins,
                         name="mean RPE" + (" (" + rpe_unit.value + ")") if rpe_unit else "",
                         marker="o", title=title,
                         xlabel=mode + " sub-sequences " + " (" + bin_unit.value + ")")
        # info text
        if SETTINGS.plot_info_text and est_name and ref_name:
            ax = fig.gca()
            ax.text(0, -0.12, "estimate:  " + est_name + "\nreference: " + ref_name,
                    transform=ax.transAxes, fontsize=8, color="gray")
        plt.title(title)
        plot_collection.add_figure("raw", fig)
        if show_plot:
            plot_collection.show()
        if save_plot:
            plot_collection.export(save_plot, confirm_overwrite=not no_warnings)
        if serialize_plot:
            logger.debug(SEP)
            plot_collection.serialize(serialize_plot, confirm_overwrite=not no_warnings)

    if save_results:
        logger.debug(SEP)
        if SETTINGS.save_traj_in_zip:
            rpe_for_each_result.add_trajectory("traj_ref", traj_ref)
            rpe_for_each_result.add_trajectory("traj_est", traj_est)
        file_interface.save_res_file(save_results, rpe_for_each_result,
                                     confirm_overwrite=not no_warnings)

    return rpe_for_each_result