PUMP / datasets /utils.py
Philippe Weinzaepfel
huggingface demo
3ef85e9
# Copyright 2022-present NAVER Corp.
# CC BY-NC-SA 4.0
# Available only for non-commercial use
from pdb import set_trace as bb
import numpy as np
import torch
class DatasetWithRng:
""" Make sure that RNG is distributed properly when torch.dataloader() is used
"""
def __init__(self, seed=None):
self.seed = seed
self.rng = np.random.default_rng(seed)
self._rng_children = set()
def with_same_rng(self, dataset=None):
if dataset is not None:
assert isinstance(dataset, DatasetWithRng) and hasattr(dataset, 'rng'), bb()
self._rng_children.add( dataset )
# update all registered children
for db in self._rng_children:
db.rng = self.rng
db.with_same_rng() # recursive call
return dataset
def init_worker(self, tid):
if self.seed is None:
self.rng = np.random.default_rng()
else:
self.rng = np.random.default_rng(self.seed + tid)
class WorkerWithRngInit:
" Dataset inherits from datasets.DatasetWithRng() and has an init_worker() function "
def __call__(self, tid):
torch.utils.data.get_worker_info().dataset.init_worker(tid)
def corres_from_homography(homography, W, H, grid=64):
s = max(1, min(W, H) // grid) # at least `grid` points in smallest dim
sx, sy = [slice(s//2, l, s) for l in (W, H)]
grid1 = np.mgrid[sy, sx][::-1].reshape(2,-1).T # (x1,y1) grid
grid2 = applyh(homography, grid1)
scale = np.sqrt(np.abs(np.linalg.det(jacobianh(homography, grid1).T)))
corres = np.c_[grid1, grid2, np.ones_like(scale), np.zeros_like(scale), scale]
return corres
def invh( H ):
return np.linalg.inv(H)
def applyh(H, p, ncol=2, norm=True):
""" Apply the homography to a list of 2d points in homogeneous coordinates.
H: Homography (...x3x3 matrix/tensor)
p: numpy/torch/tuple of coordinates. Shape must be (...,2) or (...,3)
Returns an array of projected 2d points.
"""
if isinstance(H, np.ndarray):
p = np.asarray(p)
elif isinstance(H, torch.Tensor):
p = torch.as_tensor(p, dtype=H.dtype)
if p.shape[-1]+1 == H.shape[-1]:
H = H.swapaxes(-1,-2) # transpose H
p = p @ H[...,:-1,:] + H[...,-1:,:]
else:
p = H @ p.T
if p.ndim >= 2: p = p.swapaxes(-1,-2)
if norm:
p /= p[...,-1:]
return p[...,:ncol]
def jacobianh(H, p):
""" H is an homography that maps: f_H(x,y) --> (f_1, f_2)
So the Jacobian J_H evaluated at p=(x,y) is a 2x2 matrix
Output shape = (2, 2, N) = (f_, xy, N)
Example of derivative:
numx a*X + b*Y + c*Z
since x = ----- = ---------------
denom u*X + v*Y + w*Z
numx' * denom - denom' * numx a*denom - u*numx
dx/dX = ----------------------------- = ----------------
denom**2 denom**2
"""
(a, b, c), (d, e, f), (u, v, w) = H
numx, numy, denom = applyh(H, p, ncol=3, norm=False).T
# column x column x
J = np.float32(((a*denom - u*numx, b*denom - v*numx), # row f_1
(d*denom - u*numy, e*denom - v*numy))) # row f_2
return J / np.where(denom, denom*denom, np.nan)