from mast3r.model import AsymmetricMASt3R from mast3r.fast_nn import fast_reciprocal_NNs import mast3r.utils.path_to_dust3r from dust3r.inference import inference from dust3r.utils.image import load_images if __name__ == '__main__': device = 'cuda' schedule = 'cosine' lr = 0.01 niter = 300 model_name = "naver/MASt3R_ViTLarge_BaseDecoder_512_catmlpdpt_metric" # you can put the path to a local checkpoint in model_name if needed model = AsymmetricMASt3R.from_pretrained(model_name).to(device) images = load_images(['dust3r/croco/assets/Chateau1.png', 'dust3r/croco/assets/Chateau2.png'], size=512) output = inference([tuple(images)], model, device, batch_size=1, verbose=False) # at this stage, you have the raw dust3r predictions view1, pred1 = output['view1'], output['pred1'] view2, pred2 = output['view2'], output['pred2'] desc1, desc2 = pred1['desc'].squeeze(0).detach(), pred2['desc'].squeeze(0).detach() # find 2D-2D matches between the two images matches_im0, matches_im1 = fast_reciprocal_NNs(desc1, desc2, subsample_or_initxy1=8, device=device, dist='dot', block_size=2**13) # ignore small border around the edge H0, W0 = view1['true_shape'][0] valid_matches_im0 = (matches_im0[:, 0] >= 3) & (matches_im0[:, 0] < int(W0) - 3) & ( matches_im0[:, 1] >= 3) & (matches_im0[:, 1] < int(H0) - 3) H1, W1 = view2['true_shape'][0] valid_matches_im1 = (matches_im1[:, 0] >= 3) & (matches_im1[:, 0] < int(W1) - 3) & ( matches_im1[:, 1] >= 3) & (matches_im1[:, 1] < int(H1) - 3) valid_matches = valid_matches_im0 & valid_matches_im1 matches_im0, matches_im1 = matches_im0[valid_matches], matches_im1[valid_matches] # visualize a few matches import numpy as np import torch import torchvision.transforms.functional from matplotlib import pyplot as pl n_viz = 20 num_matches = matches_im0.shape[0] match_idx_to_viz = np.round(np.linspace(0, num_matches - 1, n_viz)).astype(int) viz_matches_im0, viz_matches_im1 = matches_im0[match_idx_to_viz], matches_im1[match_idx_to_viz] image_mean = torch.as_tensor([0.5, 0.5, 0.5], device='cpu').reshape(1, 3, 1, 1) image_std = torch.as_tensor([0.5, 0.5, 0.5], device='cpu').reshape(1, 3, 1, 1) viz_imgs = [] for i, view in enumerate([view1, view2]): rgb_tensor = view['img'] * image_std + image_mean viz_imgs.append(rgb_tensor.squeeze(0).permute(1, 2, 0).cpu().numpy()) H0, W0, H1, W1 = *viz_imgs[0].shape[:2], *viz_imgs[1].shape[:2] img0 = np.pad(viz_imgs[0], ((0, max(H1 - H0, 0)), (0, 0), (0, 0)), 'constant', constant_values=0) img1 = np.pad(viz_imgs[1], ((0, max(H0 - H1, 0)), (0, 0), (0, 0)), 'constant', constant_values=0) img = np.concatenate((img0, img1), axis=1) pl.figure() pl.imshow(img) cmap = pl.get_cmap('jet') for i in range(n_viz): (x0, y0), (x1, y1) = viz_matches_im0[i].T, viz_matches_im1[i].T pl.plot([x0, x1 + W0], [y0, y1], '-+', color=cmap(i / (n_viz - 1)), scalex=False, scaley=False) pl.show(block=True)