Align3R / dust3r /image_pairs.py
cyun9286's picture
Add application file
f53b39e
# Copyright (C) 2024-present Naver Corporation. All rights reserved.
# Licensed under CC BY-NC-SA 4.0 (non-commercial use only).
#
# --------------------------------------------------------
# utilities needed to load image pairs
# --------------------------------------------------------
import numpy as np
import torch
def make_pairs(imgs, scene_graph='complete', prefilter=None, symmetrize=True):
pairs = []
if scene_graph == 'complete': # complete graph
for i in range(len(imgs)):
for j in range(i):
pairs.append((imgs[i], imgs[j]))
elif scene_graph.startswith('swin'):
iscyclic = not scene_graph.endswith('noncyclic')
try:
winsize = int(scene_graph.split('-')[1])
except Exception as e:
winsize = 3
pairsid = set()
if scene_graph.startswith('swinstride'):
stride = 2
elif scene_graph.startswith('swin2stride'):
stride = 3
else:
stride = 1
print(stride)
for i in range(len(imgs)):
for j in range(1, stride*winsize + 1, stride):
idx = (i + j)
if iscyclic:
idx = idx % len(imgs) # explicit loop closure
if idx >= len(imgs):
continue
pairsid.add((i, idx) if i < idx else (idx, i))
for i, j in pairsid:
pairs.append((imgs[i], imgs[j]))
elif scene_graph.startswith('logwin'):
iscyclic = not scene_graph.endswith('noncyclic')
try:
winsize = int(scene_graph.split('-')[1])
except Exception as e:
winsize = 3
offsets = [2**i for i in range(winsize)]
pairsid = set()
for i in range(len(imgs)):
ixs_l = [i - off for off in offsets] #[i-1,i-2,i-4]
ixs_r = [i + off for off in offsets] #[i+1,i+2,i+4]
for j in ixs_l + ixs_r:#[i-1,i-2,i-4,i+1,i+2,i+4]
if iscyclic:
j = j % len(imgs) # Explicit loop closure
if j < 0 or j >= len(imgs) or j == i:
continue
pairsid.add((i, j) if i < j else (j, i))
for i, j in pairsid:
pairs.append((imgs[i], imgs[j]))
elif scene_graph.startswith('oneref'):
refid = int(scene_graph.split('-')[1]) if '-' in scene_graph else 0
for j in range(len(imgs)):
if j != refid:
pairs.append((imgs[refid], imgs[j]))
if symmetrize:
pairs += [(img2, img1) for img1, img2 in pairs]
# now, remove edges
if isinstance(prefilter, str) and prefilter.startswith('seq'):
pairs = filter_pairs_seq(pairs, int(prefilter[3:]))
if isinstance(prefilter, str) and prefilter.startswith('cyc'):
pairs = filter_pairs_seq(pairs, int(prefilter[3:]), cyclic=True)
return pairs
def sel(x, kept):
if isinstance(x, dict):
return {k: sel(v, kept) for k, v in x.items()}
if isinstance(x, (torch.Tensor, np.ndarray)):
return x[kept]
if isinstance(x, (tuple, list)):
return type(x)([x[k] for k in kept])
def _filter_edges_seq(edges, seq_dis_thr, cyclic=False):
# number of images
n = max(max(e) for e in edges) + 1
kept = []
for e, (i, j) in enumerate(edges):
dis = abs(i - j)
if cyclic:
dis = min(dis, abs(i + n - j), abs(i - n - j))
if dis <= seq_dis_thr:
kept.append(e)
return kept
def filter_pairs_seq(pairs, seq_dis_thr, cyclic=False):
edges = [(img1['idx'], img2['idx']) for img1, img2 in pairs]
kept = _filter_edges_seq(edges, seq_dis_thr, cyclic=cyclic)
return [pairs[i] for i in kept]
def filter_edges_seq(view1, view2, pred1, pred2, seq_dis_thr, cyclic=False):
edges = [(int(i), int(j)) for i, j in zip(view1['idx'], view2['idx'])]
kept = _filter_edges_seq(edges, seq_dis_thr, cyclic=cyclic)
print(f'>> Filtering edges more than {seq_dis_thr} frames apart: kept {len(kept)}/{len(edges)} edges')
return sel(view1, kept), sel(view2, kept), sel(pred1, kept), sel(pred2, kept)