Spaces:
Running
Running
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") | |