import os import sys import cv2 from pathlib import Path import numpy as np import torch import torch.utils.data as data import tqdm from copy import deepcopy from torchvision.transforms import ToTensor import torch.nn.functional as F import json import scipy.io as scio import poselib import argparse import datetime parser=argparse.ArgumentParser(description='MegaDepth dataset evaluation script') parser.add_argument('--name',type=str,default='LiftFeat',help='experiment name') parser.add_argument('--gpu',type=str,default='0',help='GPU ID') args=parser.parse_args() os.environ["CUDA_VISIBLE_DEVICES"] = args.gpu sys.path.append(os.path.join(os.path.dirname(__file__),'../')) from models.liftfeat_wrapper import LiftFeat from evaluation.eval_utils import * from torch.utils.data import Dataset,DataLoader use_cuda = torch.cuda.is_available() device = "cuda" if use_cuda else "cpu" DATASET_ROOT = os.path.join(os.path.dirname(__file__),'../data/megadepth_test_1500') DATASET_JSON = os.path.join(os.path.dirname(__file__),'../data/megadepth_1500.json') class MegaDepth1500(Dataset): """ Streamlined MegaDepth-1500 dataloader. The camera poses & metadata are stored in a formatted json for facilitating the download of the dataset and to keep the setup as simple as possible. """ def __init__(self, json_file, root_dir): # Load the info & calibration from the JSON with open(json_file, 'r') as f: self.data = json.load(f) self.root_dir = root_dir if not os.path.exists(self.root_dir): raise RuntimeError( f"Dataset {self.root_dir} does not exist! \n \ > If you didn't download the dataset, use the downloader tool: python3 -m modules.dataset.download -h") def __len__(self): return len(self.data) def __getitem__(self, idx): data = deepcopy(self.data[idx]) h1, w1 = data['size0_hw'] h2, w2 = data['size1_hw'] # Here we resize the images to max_dim = 1200, as described in the paper, and adjust the image such that it is divisible by 32 # following the protocol of the LoFTR's Dataloader (intrinsics are corrected accordingly). # For adapting this with different resolution, you would need to re-scale intrinsics below. image0 = cv2.resize(cv2.imread(f"{self.root_dir}/{data['pair_names'][0]}"),(w1, h1)) image1 = cv2.resize(cv2.imread(f"{self.root_dir}/{data['pair_names'][1]}"),(w2, h2)) data['image0'] = torch.tensor(image0.astype(np.float32)/255).permute(2,0,1) data['image1'] = torch.tensor(image1.astype(np.float32)/255).permute(2,0,1) for k,v in data.items(): if k not in ('dataset_name', 'scene_id', 'pair_id', 'pair_names', 'size0_hw', 'size1_hw', 'image0', 'image1'): data[k] = torch.tensor(np.array(v, dtype=np.float32)) return data if __name__ == "__main__": weights=os.path.join(os.path.dirname(__file__),'../weights/LiftFeat.pth') liftfeat=LiftFeat(weight=weights) dataset = MegaDepth1500(json_file = DATASET_JSON, root_dir = DATASET_ROOT) loader = DataLoader(dataset, batch_size=1, shuffle=False) metrics = {} R_errs = [] t_errs = [] inliers = [] results=[] cur_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') for d in tqdm.tqdm(loader, desc="processing"): error_infos = compute_pose_error(liftfeat.match_liftfeat,d) results.append(error_infos) print(f'\n==={cur_time}==={args.name}===') d_err_auc,errors=compute_maa(results) for s_k,s_v in d_err_auc.items(): print(f'{s_k}: {s_v*100}')