# Source code for kornia.geometry.homography

import warnings

import torch
from typing import Tuple, Optional

import kornia
from kornia.geometry.epipolar import normalize_points

TupleTensor = Tuple[torch.Tensor, torch.Tensor]

[docs]def find_homography_dlt(
points1: torch.Tensor, points2: torch.Tensor, weights: Optional[torch.Tensor] = None) -> torch.Tensor:
r"""Computes the homography matrix using the DLT formulation.

The linear system is solved by using the Weighted Least Squares Solution for the 4 Points algorithm.

Args:
points1 (torch.Tensor): A set of points in the first image with a tensor shape :math:(B, N, 2).
points2 (torch.Tensor): A set of points in the second image with a tensor shape :math:(B, N, 2).
weights (torch.Tensor, optional): Tensor containing the weights per point correspondence with a shape of
:math:(B, N). Defaults to all ones.

Returns:
torch.Tensor: the computed homography matrix with shape :math:(B, 3, 3).
"""
assert points1.shape == points2.shape, points1.shape
assert len(points1.shape) >= 1 and points1.shape[-1] == 2, points1.shape
assert points1.shape >= 4, points1.shape

eps: float = 1e-8
points1_norm, transform1 = normalize_points(points1)
points2_norm, transform2 = normalize_points(points2)

x1, y1 = torch.chunk(points1_norm, dim=-1, chunks=2)  # BxNx1
x2, y2 = torch.chunk(points2_norm, dim=-1, chunks=2)  # BxNx1
ones, zeros = torch.ones_like(x1), torch.zeros_like(x1)

# DIAPO 11: https://www.uio.no/studier/emner/matnat/its/nedlagte-emner/UNIK4690/v16/forelesninger/lecture_4_3-estimating-homographies-from-feature-correspondences.pdf  # noqa: E501
ax = torch.cat([zeros, zeros, zeros, -x1, -y1, -ones, y2 * x1, y2 * y1, y2], dim=-1)
ay = torch.cat([x1, y1, ones, zeros, zeros, zeros, -x2 * x1, -x2 * y1, -x2], dim=-1)
A = torch.cat((ax, ay), dim=-1).reshape(ax.shape, -1, ax.shape[-1])

if weights is None:
# All points are equally important
A = A.transpose(-2, -1) @ A
else:
# We should use provided weights
assert len(weights.shape) == 2 and weights.shape == points1.shape[:2], weights.shape
w_diag = torch.diag_embed(weights.unsqueeze(dim=-1).repeat(1, 1, 2).reshape(weights.shape, -1))
A = A.transpose(-2, -1) @ w_diag @ A

try:
U, S, V = torch.svd(A)
except:
warnings.warn('SVD did not converge', RuntimeWarning)

H = V[..., -1].view(-1, 3, 3)
H = transform2.inverse() @ (H @ transform1)
H_norm = H / (H[..., -1:, -1:] + eps)
return H_norm

[docs]def find_homography_dlt_iterated(points1: torch.Tensor,
points2: torch.Tensor,
weights: torch.Tensor,
soft_inl_th: float = 3.0,
n_iter: int = 5) -> torch.Tensor:
r"""Computes the homography matrix using the iteratively-reweighted least squares (IRWLS).

The linear system is solved by using the Reweighted Least Squares Solution for the 4 Points algorithm.

Args:
points1 (torch.Tensor): A set of points in the first image with a tensor shape :math:(B, N, 2).
points2 (torch.Tensor): A set of points in the second image with a tensor shape :math:(B, N, 2).
weights (torch.Tensor): Tensor containing the weights per point correspondence with a shape of :math:(B, N).
Used for the first iteration of the IRWLS.
soft_inl_th (float): Soft inlier threshold used for weight calculation.
n_iter (int): number of iterations. Default is 5.

Returns:
torch.Tensor: the computed homography matrix with shape :math:(B, 3, 3).
"""

'''Function, which finds homography via iteratively-reweighted