Spaces:
Running
Running
File size: 4,556 Bytes
a80d6bb |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# Copyright 2020 Toyota Research Institute. All rights reserved.
# Adapted from: https://github.com/rpautrat/SuperPoint/blob/master/superpoint/evaluations/detector_evaluation.py
import random
from glob import glob
from os import path as osp
import cv2
import numpy as np
from utils import warp_keypoints
def compute_repeatability(data, keep_k_points=300, distance_thresh=3):
"""
Compute the repeatability metric between 2 sets of keypoints inside data.
Parameters
----------
data: dict
Input dictionary containing:
image_shape: tuple (H,W)
Original image shape.
homography: numpy.ndarray (3,3)
Ground truth homography.
prob: numpy.ndarray (N,3)
Keypoint vector, consisting of (x,y,probability).
warped_prob: numpy.ndarray (N,3)
Warped keypoint vector, consisting of (x,y,probability).
keep_k_points: int
Number of keypoints to select, based on probability.
distance_thresh: int
Distance threshold in pixels for a corresponding keypoint to be considered a correct match.
Returns
-------
N1: int
Number of true keypoints in the first image.
N2: int
Number of true keypoints in the second image.
repeatability: float
Keypoint repeatability metric.
loc_err: float
Keypoint localization error.
"""
def filter_keypoints(points, shape):
""" Keep only the points whose coordinates are inside the dimensions of shape. """
mask = (points[:, 0] >= 0) & (points[:, 0] < shape[0]) &\
(points[:, 1] >= 0) & (points[:, 1] < shape[1])
return points[mask, :]
def keep_true_keypoints(points, H, shape):
""" Keep only the points whose warped coordinates by H are still inside shape. """
warped_points = warp_keypoints(points[:, [1, 0]], H)
warped_points[:, [0, 1]] = warped_points[:, [1, 0]]
mask = (warped_points[:, 0] >= 0) & (warped_points[:, 0] < shape[0]) &\
(warped_points[:, 1] >= 0) & (warped_points[:, 1] < shape[1])
return points[mask, :]
def select_k_best(points, k):
""" Select the k most probable points (and strip their probability).
points has shape (num_points, 3) where the last coordinate is the probability. """
sorted_prob = points[points[:, 2].argsort(), :2]
start = min(k, points.shape[0])
return sorted_prob[-start:, :]
H = data['homography']
shape = data['image_shape']
# # Filter out predictions
keypoints = data['prob'][:, :2].T
keypoints = keypoints[::-1]
prob = data['prob'][:, 2]
warped_keypoints = data['warped_prob'][:, :2].T
warped_keypoints = warped_keypoints[::-1]
warped_prob = data['warped_prob'][:, 2]
keypoints = np.stack([keypoints[0], keypoints[1]], axis=-1)
warped_keypoints = np.stack([warped_keypoints[0], warped_keypoints[1], warped_prob], axis=-1)
warped_keypoints = keep_true_keypoints(warped_keypoints, np.linalg.inv(H), shape)
# Warp the original keypoints with the true homography
true_warped_keypoints = warp_keypoints(keypoints[:, [1, 0]], H)
true_warped_keypoints = np.stack([true_warped_keypoints[:, 1], true_warped_keypoints[:, 0], prob], axis=-1)
true_warped_keypoints = filter_keypoints(true_warped_keypoints, shape)
# Keep only the keep_k_points best predictions
warped_keypoints = select_k_best(warped_keypoints, keep_k_points)
true_warped_keypoints = select_k_best(true_warped_keypoints, keep_k_points)
# Compute the repeatability
N1 = true_warped_keypoints.shape[0]
N2 = warped_keypoints.shape[0]
true_warped_keypoints = np.expand_dims(true_warped_keypoints, 1)
warped_keypoints = np.expand_dims(warped_keypoints, 0)
# shapes are broadcasted to N1 x N2 x 2:
norm = np.linalg.norm(true_warped_keypoints - warped_keypoints, ord=None, axis=2)
count1 = 0
count2 = 0
le1 = 0
le2 = 0
if N2 != 0:
min1 = np.min(norm, axis=1)
correct1 = (min1 <= distance_thresh)
count1 = np.sum(correct1)
le1 = min1[correct1].sum()
if N1 != 0:
min2 = np.min(norm, axis=0)
correct2 = (min2 <= distance_thresh)
count2 = np.sum(correct2)
le2 = min2[correct2].sum()
if N1 + N2 > 0:
repeatability = (count1 + count2) / (N1 + N2)
loc_err = (le1 + le2) / (count1 + count2)
else:
repeatability = -1
loc_err = -1
return N1, N2, repeatability, loc_err
|