hpatches_sequences_homog_benchmark.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. from PIL import Image
  2. import numpy as np
  3. import torch
  4. import os
  5. from tqdm import tqdm
  6. from romatch.utils import pose_auc
  7. import cv2
  8. class HpatchesHomogBenchmark:
  9. """Hpatches grid goes from [0,n-1] instead of [0.5,n-0.5]"""
  10. def __init__(self, dataset_path) -> None:
  11. seqs_dir = "hpatches-sequences-release"
  12. self.seqs_path = os.path.join(dataset_path, seqs_dir)
  13. self.seq_names = sorted(os.listdir(self.seqs_path))
  14. # Ignore seqs is same as LoFTR.
  15. self.ignore_seqs = set(
  16. [
  17. "i_contruction",
  18. "i_crownnight",
  19. "i_dc",
  20. "i_pencils",
  21. "i_whitebuilding",
  22. "v_artisans",
  23. "v_astronautis",
  24. "v_talent",
  25. ]
  26. )
  27. def convert_coordinates(self, im_A_coords, im_A_to_im_B, wq, hq, wsup, hsup):
  28. offset = 0.5 # Hpatches assumes that the center of the top-left pixel is at [0,0] (I think)
  29. im_A_coords = (
  30. torch.stack(
  31. (
  32. wq * (im_A_coords[..., 0] + 1) / 2,
  33. hq * (im_A_coords[..., 1] + 1) / 2,
  34. ),
  35. axis=-1,
  36. )
  37. - offset
  38. )
  39. im_A_to_im_B = (
  40. torch.stack(
  41. (
  42. wsup * (im_A_to_im_B[..., 0] + 1) / 2,
  43. hsup * (im_A_to_im_B[..., 1] + 1) / 2,
  44. ),
  45. axis=-1,
  46. )
  47. - offset
  48. )
  49. return im_A_coords, im_A_to_im_B
  50. def benchmark(self, model, model_name = None):
  51. n_matches = []
  52. homog_dists = []
  53. for seq_idx, seq_name in tqdm(
  54. enumerate(self.seq_names), total=len(self.seq_names)
  55. ):
  56. im_A_path = os.path.join(self.seqs_path, seq_name, "1.ppm")
  57. im_A = Image.open(im_A_path)
  58. w1, h1 = im_A.size
  59. for im_idx in range(2, 7):
  60. im_B_path = os.path.join(self.seqs_path, seq_name, f"{im_idx}.ppm")
  61. im_B = Image.open(im_B_path)
  62. w2, h2 = im_B.size
  63. H = np.loadtxt(
  64. os.path.join(self.seqs_path, seq_name, "H_1_" + str(im_idx))
  65. )
  66. dense_matches, dense_certainty = model.match(
  67. im_A_path, im_B_path
  68. )
  69. good_matches, _ = model.sample(dense_matches, dense_certainty, 5000)
  70. pos_a, pos_b = self.convert_coordinates(
  71. good_matches[:, :2], good_matches[:, 2:], w1, h1, w2, h2
  72. )
  73. try:
  74. H_pred, inliers = cv2.findHomography(
  75. pos_a.cpu().numpy(),
  76. pos_b.cpu().numpy(),
  77. method = cv2.RANSAC,
  78. confidence = 0.99999,
  79. ransacReprojThreshold = 3 * min(w2, h2) / 480,
  80. )
  81. except:
  82. H_pred = None
  83. if H_pred is None:
  84. H_pred = np.zeros((3, 3))
  85. H_pred[2, 2] = 1.0
  86. corners = np.array(
  87. [[0, 0, 1], [0, h1 - 1, 1], [w1 - 1, 0, 1], [w1 - 1, h1 - 1, 1]]
  88. )
  89. real_warped_corners = np.dot(corners, np.transpose(H))
  90. real_warped_corners = (
  91. real_warped_corners[:, :2] / real_warped_corners[:, 2:]
  92. )
  93. warped_corners = np.dot(corners, np.transpose(H_pred))
  94. warped_corners = warped_corners[:, :2] / warped_corners[:, 2:]
  95. mean_dist = np.mean(
  96. np.linalg.norm(real_warped_corners - warped_corners, axis=1)
  97. ) / (min(w2, h2) / 480.0)
  98. homog_dists.append(mean_dist)
  99. n_matches = np.array(n_matches)
  100. thresholds = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  101. auc = pose_auc(np.array(homog_dists), thresholds)
  102. return {
  103. "hpatches_homog_auc_3": auc[2],
  104. "hpatches_homog_auc_5": auc[4],
  105. "hpatches_homog_auc_10": auc[9],
  106. }