예제 #1
0
def compute_mean_re_te(pred_transes, pred_rots, gt_transes, gt_rots):
    pred_transes = pred_transes.detach().cpu().numpy()
    pred_rots = pred_rots.detach().cpu().numpy()
    gt_transes = gt_transes.detach().cpu().numpy()
    gt_rots = gt_rots.detach().cpu().numpy()

    bs = pred_rots.shape[0]
    R_errs = np.zeros((bs,), dtype=np.float32)
    T_errs = np.zeros((bs,), dtype=np.float32)
    for i in range(bs):
        R_errs[i] = re(pred_rots[i], gt_rots[i])
        T_errs[i] = te(pred_transes[i], gt_transes[i])
    return R_errs.mean(), T_errs.mean()
예제 #2
0
    def _eval_predictions_precision(self):
        """NOTE: eval precision instead of recall
        Evaluate self._predictions on 6d pose.
        Return results with the metrics of the tasks.
        """
        self._logger.info("Eval results ...")
        cfg = self.cfg
        method_name = f"{cfg.EXP_ID.replace('_', '-')}"
        cache_path = osp.join(self._output_dir,
                              f"{method_name}_{self.dataset_name}_preds.pkl")
        if osp.exists(cache_path) and self.use_cache:
            self._logger.info("load cached predictions")
            self._predictions = mmcv.load(cache_path)
        else:
            if hasattr(self, "_predictions"):
                mmcv.dump(self._predictions, cache_path)
            else:
                raise RuntimeError("Please run inference first")

        precisions = OrderedDict()
        errors = OrderedDict()
        self.get_gts()

        error_names = ["ad", "re", "te", "proj"]
        metric_names = [
            "ad_2",
            "ad_5",
            "ad_10",
            "rete_2",
            "rete_5",
            "rete_10",
            "re_2",
            "re_5",
            "re_10",
            "te_2",
            "te_5",
            "te_10",
            "proj_2",
            "proj_5",
            "proj_10",
        ]

        for obj_name in self.gts:
            if obj_name not in self._predictions:
                continue
            cur_label = self.obj_names.index(obj_name)
            if obj_name not in precisions:
                precisions[obj_name] = OrderedDict()
                for metric_name in metric_names:
                    precisions[obj_name][metric_name] = []

            if obj_name not in errors:
                errors[obj_name] = OrderedDict()
                for err_name in error_names:
                    errors[obj_name][err_name] = []

            #################
            obj_gts = self.gts[obj_name]
            obj_preds = self._predictions[obj_name]
            for file_name, gt_anno in obj_gts.items():
                # compute precision as in DPOD paper
                if file_name not in obj_preds:  # no pred found
                    # NOTE: just ignore undetected
                    continue
                # compute each metric
                R_pred = obj_preds[file_name]["R"]
                t_pred = obj_preds[file_name]["t"]

                R_gt = gt_anno["R"]
                t_gt = gt_anno["t"]

                t_error = te(t_pred, t_gt)

                if obj_name in cfg.DATASETS.SYM_OBJS:
                    R_gt_sym = get_closest_rot(
                        R_pred, R_gt, self._metadata.sym_infos[cur_label])
                    r_error = re(R_pred, R_gt_sym)

                    proj_2d_error = arp_2d(
                        R_pred,
                        t_pred,
                        R_gt_sym,
                        t_gt,
                        pts=self.models_3d[cur_label]["pts"],
                        K=gt_anno["K"])

                    ad_error = adi(R_pred,
                                   t_pred,
                                   R_gt,
                                   t_gt,
                                   pts=self.models_3d[self.obj_names.index(
                                       obj_name)]["pts"])
                else:
                    r_error = re(R_pred, R_gt)

                    proj_2d_error = arp_2d(
                        R_pred,
                        t_pred,
                        R_gt,
                        t_gt,
                        pts=self.models_3d[cur_label]["pts"],
                        K=gt_anno["K"])

                    ad_error = add(R_pred,
                                   t_pred,
                                   R_gt,
                                   t_gt,
                                   pts=self.models_3d[self.obj_names.index(
                                       obj_name)]["pts"])

                #########
                errors[obj_name]["ad"].append(ad_error)
                errors[obj_name]["re"].append(r_error)
                errors[obj_name]["te"].append(t_error)
                errors[obj_name]["proj"].append(proj_2d_error)
                ############
                precisions[obj_name]["ad_2"].append(
                    float(ad_error < 0.02 * self.diameters[cur_label]))
                precisions[obj_name]["ad_5"].append(
                    float(ad_error < 0.05 * self.diameters[cur_label]))
                precisions[obj_name]["ad_10"].append(
                    float(ad_error < 0.1 * self.diameters[cur_label]))
                # deg, cm
                precisions[obj_name]["rete_2"].append(
                    float(r_error < 2 and t_error < 0.02))
                precisions[obj_name]["rete_5"].append(
                    float(r_error < 5 and t_error < 0.05))
                precisions[obj_name]["rete_10"].append(
                    float(r_error < 10 and t_error < 0.1))

                precisions[obj_name]["re_2"].append(float(r_error < 2))
                precisions[obj_name]["re_5"].append(float(r_error < 5))
                precisions[obj_name]["re_10"].append(float(r_error < 10))

                precisions[obj_name]["te_2"].append(float(t_error < 0.02))
                precisions[obj_name]["te_5"].append(float(t_error < 0.05))
                precisions[obj_name]["te_10"].append(float(t_error < 0.1))
                # px
                precisions[obj_name]["proj_2"].append(float(proj_2d_error < 2))
                precisions[obj_name]["proj_5"].append(float(proj_2d_error < 5))
                precisions[obj_name]["proj_10"].append(
                    float(proj_2d_error < 10))

        # summarize
        obj_names = sorted(list(precisions.keys()))
        header = ["objects"] + obj_names + [f"Avg({len(obj_names)})"]
        big_tab = [header]
        for metric_name in metric_names:
            line = [metric_name]
            this_line_res = []
            for obj_name in obj_names:
                res = precisions[obj_name][metric_name]
                if len(res) > 0:
                    line.append(f"{100 * np.mean(res):.2f}")
                    this_line_res.append(np.mean(res))
                else:
                    line.append(0.0)
                    this_line_res.append(0.0)
            # mean
            if len(obj_names) > 0:
                line.append(f"{100 * np.mean(this_line_res):.2f}")
            big_tab.append(line)

        for error_name in ["re", "te"]:
            line = [error_name]
            this_line_res = []
            for obj_name in obj_names:
                res = errors[obj_name][error_name]
                if len(res) > 0:
                    line.append(f"{np.mean(res):.2f}")
                    this_line_res.append(np.mean(res))
                else:
                    line.append(float("nan"))
                    this_line_res.append(float("nan"))
            # mean
            if len(obj_names) > 0:
                line.append(f"{np.mean(this_line_res):.2f}")
            big_tab.append(line)
        ### log big table
        self._logger.info("precisions")
        res_log_tab_str = tabulate(
            big_tab,
            tablefmt="plain",
            # floatfmt=floatfmt
        )
        self._logger.info("\n{}".format(res_log_tab_str))
        errors_cache_path = osp.join(
            self._output_dir, f"{method_name}_{self.dataset_name}_errors.pkl")
        recalls_cache_path = osp.join(
            self._output_dir,
            f"{method_name}_{self.dataset_name}_precisions.pkl")
        self._logger.info(f"{errors_cache_path}")
        self._logger.info(f"{recalls_cache_path}")
        mmcv.dump(errors, errors_cache_path)
        mmcv.dump(precisions, recalls_cache_path)

        dump_tab_name = osp.join(
            self._output_dir,
            f"{method_name}_{self.dataset_name}_tab_precisions.txt")
        with open(dump_tab_name, "w") as f:
            f.write("{}\n".format(res_log_tab_str))
        if self._distributed:
            self._logger.warning(
                "\n The current evaluation on multi-gpu is not correct, run with single-gpu instead."
            )
        return {}
예제 #3
0
    def process_net_and_pnp(self, inputs, outputs, out_dict, pnp_type="iter"):
        """Initialize with network prediction (learned PnP) + iter PnP
        Args:
            inputs: the inputs to a model.
                It is a list of dict. Each dict corresponds to an image and
                contains keys like "height", "width", "file_name", "image_id", "scene_id".
            pnp_type: iter | ransac (use ransac+EPnP)
            outputs:
        """
        cfg = self.cfg
        out_coor_x = out_dict["coor_x"].detach()
        out_coor_y = out_dict["coor_y"].detach()
        out_coor_z = out_dict["coor_z"].detach()
        out_xyz = get_out_coor(cfg, out_coor_x, out_coor_y, out_coor_z)
        out_xyz = out_xyz.to(self._cpu_device).numpy()

        out_mask = get_out_mask(cfg, out_dict["mask"].detach())
        out_mask = out_mask.to(self._cpu_device).numpy()

        out_rots = out_dict["rot"].detach().to(self._cpu_device).numpy()
        out_transes = out_dict["trans"].detach().to(self._cpu_device).numpy()

        out_i = -1
        for i, (_input, output) in enumerate(zip(inputs, outputs)):
            start_process_time = time.perf_counter()
            for inst_i in range(len(_input["roi_img"])):
                out_i += 1

                bbox_center_i = _input["bbox_center"][inst_i]
                cx_i, cy_i = bbox_center_i
                scale_i = _input["scale"][inst_i]

                coord_2d_i = _input["roi_coord_2d"][inst_i].cpu().numpy(
                ).transpose(1, 2, 0)  # CHW->HWC
                im_H = _input["im_H"][inst_i].item()
                im_W = _input["im_W"][inst_i].item()

                scene_im_id_split = _input["scene_im_id"][inst_i].split("/")
                K = _input["cam"][inst_i].cpu().numpy().copy()

                roi_label = _input["roi_cls"][inst_i]  # 0-based label
                score = _input["score"][inst_i]
                roi_label, cls_name = self._maybe_adapt_label_cls_name(
                    roi_label)
                if cls_name is None:
                    continue

                # scene_id = int(scene_im_id_split[0])
                scene_id = scene_im_id_split[0]
                im_id = int(scene_im_id_split[1])

                # get pose
                xyz_i = out_xyz[out_i].transpose(1, 2, 0)
                mask_i = np.squeeze(out_mask[out_i])

                img_points, model_points = self.get_img_model_points_with_coords2d(
                    mask_i,
                    xyz_i,
                    coord_2d_i,
                    im_H=im_H,
                    im_W=im_W,
                    extent=_input["roi_extent"][inst_i].cpu().numpy(),
                    mask_thr=cfg.MODEL.CDPN.ROT_HEAD.MASK_THR_TEST,
                )

                rot_est_net = out_rots[out_i]
                trans_est_net = out_transes[out_i]

                num_points = len(img_points)
                if num_points >= 4:
                    dist_coeffs = np.zeros(shape=[8, 1], dtype="float64")
                    points_2d = np.ascontiguousarray(
                        img_points.astype(np.float64))
                    points_3d = np.ascontiguousarray(
                        model_points.astype(np.float64))
                    camera_matrix = K.astype(np.float64)

                    rvec0, _ = cv2.Rodrigues(rot_est_net)

                    if pnp_type in ["ransac", "ransac_rot"]:
                        points_3d = np.expand_dims(points_3d, 0)
                        points_2d = np.expand_dims(points_2d, 0)
                        _, rvec, t_est, _ = cv2.solvePnPRansac(
                            objectPoints=points_3d,
                            imagePoints=points_2d,
                            cameraMatrix=camera_matrix,
                            distCoeffs=dist_coeffs,
                            flags=cv2.SOLVEPNP_EPNP,
                            useExtrinsicGuess=True,
                            rvec=rvec0,
                            tvec=trans_est_net,
                            reprojectionError=3.0,  # default 8.0
                            iterationsCount=20,
                        )
                    else:  # iter PnP
                        # points_3d = np.expand_dims(points_3d, 0)  # uncomment for EPNP
                        # points_2d = np.expand_dims(points_2d, 0)
                        _, rvec, t_est = cv2.solvePnP(
                            objectPoints=points_3d,
                            imagePoints=points_2d,
                            cameraMatrix=camera_matrix,
                            distCoeffs=dist_coeffs,
                            flags=cv2.SOLVEPNP_ITERATIVE,
                            # flags=cv2.SOLVEPNP_EPNP,
                            useExtrinsicGuess=True,
                            rvec=rvec0,
                            tvec=trans_est_net,
                        )
                    rot_est, _ = cv2.Rodrigues(rvec)
                    if pnp_type not in ["ransac_rot"]:
                        diff_t_est = te(t_est, trans_est_net)
                        if diff_t_est > 1:  # diff too large
                            self._logger.warning(
                                "translation error too large: {}".format(
                                    diff_t_est))
                            t_est = trans_est_net
                    else:
                        t_est = trans_est_net
                    pose_est = np.concatenate(
                        [rot_est, t_est.reshape((3, 1))], axis=-1)
                else:
                    self._logger.warning("num points: {}".format(
                        len(img_points)))
                    pose_est_net = np.hstack(
                        [rot_est_net, trans_est_net.reshape(3, 1)])
                    pose_est = pose_est_net

                output["pose_est"] = pose_est
                output["time"] += time.perf_counter() - start_process_time

                # result
                file_name = _input["file_name"][inst_i]

                if cls_name not in self._predictions:
                    self._predictions[cls_name] = OrderedDict()

                result = {
                    "score": score,
                    "R": pose_est[:3, :3],
                    "t": pose_est[:3, 3],
                    "time": output["time"]
                }
                self._predictions[cls_name][file_name] = result
예제 #4
0
                            proj_2d_err = pose_error.arp_2d_sym(
                                R_e, t_e, R_g, t_g, pts=models[obj_id]["pts"], K=K, syms=models_sym[obj_id]
                            )
                            e = [proj_2d_err]

                        elif p["error_type"] == "cus":
                            if sphere_projections_overlap:
                                e = [
                                    pose_error.cus(R_e, t_e, R_g, t_g, K, ren, obj_id, renderer_type=p["renderer_type"])
                                ]
                            else:
                                e = [1.0]

                        elif p["error_type"] == "rete":
                            r_err = pose_error.re(R_e, R_g)
                            t_err = pose_error.te(t_e, t_g) / 10  # mm to cm
                            e = [r_err, t_err]

                        elif p["error_type"] == "reteS":
                            r_err = pose_error.re_sym(R_e, R_g, syms=models_sym[obj_id])
                            t_err = pose_error.te_sym(t_e, t_g, R_gt=R_g, syms=models_sym[obj_id]) / 10
                            e = [r_err, t_err]

                        elif p["error_type"] == "re":
                            r_err = pose_error.re(R_e, R_g)
                            e = [r_err]

                        elif p["error_type"] == "reS":
                            r_err = pose_error.re_sym(R_e, R_g, syms=models_sym[obj_id])
                            e = [r_err]