| import cv2 |
| import numpy as np |
| import torch |
| import os |
|
|
| import sys |
|
|
| ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) |
| sys.path.insert(0, ROOT_DIR) |
|
|
| from superpoint import SuperPoint |
|
|
|
|
| def resize(img, resize): |
| img_h, img_w = img.shape[0], img.shape[1] |
| cur_size = max(img_h, img_w) |
| if len(resize) == 1: |
| scale1, scale2 = resize[0] / cur_size, resize[0] / cur_size |
| else: |
| scale1, scale2 = resize[0] / img_h, resize[1] / img_w |
| new_h, new_w = int(img_h * scale1), int(img_w * scale2) |
| new_img = cv2.resize(img.astype("float32"), (new_w, new_h)).astype("uint8") |
| scale = np.asarray([scale2, scale1]) |
| return new_img, scale |
|
|
|
|
| class ExtractSIFT: |
| def __init__(self, config, root=True): |
| self.num_kp = config["num_kpt"] |
| self.contrastThreshold = config["det_th"] |
| self.resize = config["resize"] |
| self.root = root |
|
|
| def run(self, img_path): |
| self.sift = cv2.xfeatures2d.SIFT_create( |
| nfeatures=self.num_kp, contrastThreshold=self.contrastThreshold |
| ) |
| img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) |
| scale = [1, 1] |
| if self.resize[0] != -1: |
| img, scale = resize(img, self.resize) |
| cv_kp, desc = self.sift.detectAndCompute(img, None) |
| kp = np.array( |
| [ |
| [_kp.pt[0] / scale[1], _kp.pt[1] / scale[0], _kp.response] |
| for _kp in cv_kp |
| ] |
| ) |
| index = np.flip(np.argsort(kp[:, 2])) |
| kp, desc = kp[index], desc[index] |
| if self.root: |
| desc = np.sqrt( |
| abs(desc / (np.linalg.norm(desc, axis=-1, ord=1)[:, np.newaxis] + 1e-8)) |
| ) |
| return kp[: self.num_kp], desc[: self.num_kp] |
|
|
|
|
| class ExtractSuperpoint(object): |
| def __init__(self, config): |
| default_config = { |
| "descriptor_dim": 256, |
| "nms_radius": 4, |
| "detection_threshold": config["det_th"], |
| "max_keypoints": config["num_kpt"], |
| "remove_borders": 4, |
| "model_path": "../weights/sp/superpoint_v1.pth", |
| } |
| self.superpoint_extractor = SuperPoint(default_config) |
| self.superpoint_extractor.eval(), self.superpoint_extractor.cuda() |
| self.num_kp = config["num_kpt"] |
| if "padding" in config.keys(): |
| self.padding = config["padding"] |
| else: |
| self.padding = False |
| self.resize = config["resize"] |
|
|
| def run(self, img_path): |
| img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) |
| scale = 1 |
| if self.resize[0] != -1: |
| img, scale = resize(img, self.resize) |
| with torch.no_grad(): |
| result = self.superpoint_extractor( |
| torch.from_numpy(img / 255.0).float()[None, None].cuda() |
| ) |
| score, kpt, desc = ( |
| result["scores"][0], |
| result["keypoints"][0], |
| result["descriptors"][0], |
| ) |
| score, kpt, desc = score.cpu().numpy(), kpt.cpu().numpy(), desc.cpu().numpy().T |
| kpt = np.concatenate([kpt / scale, score[:, np.newaxis]], axis=-1) |
| |
| if self.padding: |
| if len(kpt) < self.num_kp: |
| res = int(self.num_kp - len(kpt)) |
| pad_x, pad_desc = np.random.uniform(size=[res, 2]) * ( |
| img.shape[0] + img.shape[1] |
| ) / 2, np.random.uniform(size=[res, 256]) |
| pad_kpt, pad_desc = ( |
| np.concatenate([pad_x, np.zeros([res, 1])], axis=-1), |
| pad_desc / np.linalg.norm(pad_desc, axis=-1)[:, np.newaxis], |
| ) |
| kpt, desc = np.concatenate([kpt, pad_kpt], axis=0), np.concatenate( |
| [desc, pad_desc], axis=0 |
| ) |
| return kpt, desc |
|
|