import numpy as np import sys import os ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) sys.path.insert(0, ROOT_DIR) from utils import evaluation_utils, metrics, fm_utils import cv2 class auc_eval: def __init__(self, config): self.config = config self.err_r, self.err_t, self.err = [], [], [] self.ms = [] self.precision = [] def run(self, info): E, r_gt, t_gt = info["e"], info["r_gt"], info["t_gt"] K1, K2, img1, img2 = info["K1"], info["K2"], info["img1"], info["img2"] corr1, corr2 = info["corr1"], info["corr2"] corr1, corr2 = evaluation_utils.normalize_intrinsic( corr1, K1 ), evaluation_utils.normalize_intrinsic(corr2, K2) size1, size2 = max(img1.shape), max(img2.shape) scale1, scale2 = self.config["rescale"] / size1, self.config["rescale"] / size2 # ransac ransac_th = 4.0 / ( (K1[0, 0] + K1[1, 1]) * scale1 + (K2[0, 0] + K2[1, 1]) * scale2 ) R_hat, t_hat, E_hat = self.estimate(corr1, corr2, ransac_th) # get pose error err_r, err_t = metrics.evaluate_R_t(r_gt, t_gt, R_hat, t_hat) err = max(err_r, err_t) if len(corr1) > 1: inlier_mask = metrics.compute_epi_inlier( corr1, corr2, E, self.config["inlier_th"] ) precision = inlier_mask.mean() ms = inlier_mask.sum() / len(info["x1"]) else: ms = precision = 0 return { "err_r": err_r, "err_t": err_t, "err": err, "ms": ms, "precision": precision, } def res_inqueue(self, res): self.err_r.append(res["err_r"]), self.err_t.append( res["err_t"] ), self.err.append(res["err"]) self.ms.append(res["ms"]), self.precision.append(res["precision"]) def estimate(self, corr1, corr2, th): num_inlier = -1 if corr1.shape[0] >= 5: E, mask_new = cv2.findEssentialMat( corr1, corr2, method=cv2.RANSAC, threshold=th, prob=1 - 1e-5 ) if E is None: E = [np.eye(3)] for _E in np.split(E, len(E) / 3): _num_inlier, _R, _t, _ = cv2.recoverPose( _E, corr1, corr2, np.eye(3), 1e9, mask=mask_new ) if _num_inlier > num_inlier: num_inlier = _num_inlier R = _R t = _t E = _E else: E, R, t = np.eye(3), np.eye(3), np.zeros(3) return R, t, E def parse(self): ths = np.arange(7) * 5 approx_auc = metrics.approx_pose_auc(self.err, ths) exact_auc = metrics.pose_auc(self.err, ths) mean_pre, mean_ms = np.mean(np.asarray(self.precision)), np.mean( np.asarray(self.ms) ) print("auc th: ", ths[1:]) print("approx auc: ", approx_auc) print("exact auc: ", exact_auc) print("mean match score: ", mean_ms * 100) print("mean precision: ", mean_pre * 100) class FMbench_eval: def __init__(self, config): self.config = config self.pre, self.pre_post, self.sgd = [], [], [] self.num_corr, self.num_corr_post = [], [] def run(self, info): corr1, corr2 = info["corr1"], info["corr2"] F = info["f"] img1, img2 = info["img1"], info["img2"] if len(corr1) > 1: pre_bf = fm_utils.compute_inlier_rate( corr1, corr2, np.flip(img1.shape[:2]), np.flip(img2.shape[:2]), F, th=self.config["inlier_th"], ).mean() F_hat, mask_F = cv2.findFundamentalMat( corr1, corr2, method=cv2.FM_RANSAC, ransacReprojThreshold=1, confidence=1 - 1e-5, ) if F_hat is None: F_hat = np.ones([3, 3]) mask_F = np.ones([len(corr1)]).astype(bool) else: mask_F = mask_F.squeeze().astype(bool) F_hat = F_hat[:3] pre_af = fm_utils.compute_inlier_rate( corr1[mask_F], corr2[mask_F], np.flip(img1.shape[:2]), np.flip(img2.shape[:2]), F, th=self.config["inlier_th"], ).mean() num_corr_af = mask_F.sum() num_corr = len(corr1) sgd = fm_utils.compute_SGD( F, F_hat, np.flip(img1.shape[:2]), np.flip(img2.shape[:2]) ) else: pre_bf, pre_af, sgd = 0, 0, 1e8 num_corr, num_corr_af = 0, 0 return { "pre": pre_bf, "pre_post": pre_af, "sgd": sgd, "num_corr": num_corr, "num_corr_post": num_corr_af, } def res_inqueue(self, res): self.pre.append(res["pre"]), self.pre_post.append( res["pre_post"] ), self.sgd.append(res["sgd"]) self.num_corr.append(res["num_corr"]), self.num_corr_post.append( res["num_corr_post"] ) def parse(self): for seq_index in range(len(self.config["seq"])): seq = self.config["seq"][seq_index] offset = seq_index * 1000 pre = np.asarray(self.pre)[offset : offset + 1000].mean() pre_post = np.asarray(self.pre_post)[offset : offset + 1000].mean() num_corr = np.asarray(self.num_corr)[offset : offset + 1000].mean() num_corr_post = np.asarray(self.num_corr_post)[ offset : offset + 1000 ].mean() f_recall = ( np.asarray(self.sgd)[offset : offset + 1000] < self.config["sgd_inlier_th"] ).mean() print(seq, "results:") print("F_recall: ", f_recall) print("precision: ", pre) print("precision_post: ", pre_post) print("num_corr: ", num_corr) print("num_corr_post: ", num_corr_post, "\n")