o
    oi[                     @   s  d dl mZmZmZmZmZmZ d dlZd dlm	Z	m
Z
mZ d dlmZmZ d dlmZ d dlmZ d dlmZ dd	lmZmZ d
e
de
de
fddZdeeef fddZd2de
de
dee
 de
fddZde
dee
e
f fddZd2de
de
dee
 dee
e
f fddZd2de
de
dee
 dee
e
f fddZd3de
de
dedee
 dee
e
f f
dd Z d4de
de
dedee
 dee
e
f f
d"d#Z!		$	%	d5de
de
d&e
d'e
ded(ed)e"dee
 dee
e
f fd*d+Z#G d,d- d-e	Z$G d.d/ d/e	Z%G d0d1 d1e	Z&dS )6    )AnyClassVarDictListOptionalTupleN)ModuleTensorconcatenate)KORNIA_CHECK_DM_DESCKORNIA_CHECK_SHAPE)get_laf_center)DiscreteSteerer)is_mps_tensor_safe   )get_adalam_default_configmatch_adalamd1d2returnc                 C   s   t | st |st| |S | d jddd}|d jddd}|d|d|d| d  d|  |   }|jdd }|S )	zManual `torch.cdist` for M1.   r   T)dimkeepdimr   g       @g        )min)	r   torchcdistsumrepeatsizetclampsqrt)r   r   d1_sqd2_sqdm r%   K/home/ubuntu/.local/lib/python3.10/site-packages/kornia/feature/matching.py_cdist   s   8r'   c                  C   s   dddd} | S )Ng333333?F      $@)thmutual
spatial_thr%   configr%   r%   r&   _get_default_fginn_params*   s   r.   desc1desc2dm_c                 C   s*   |du rt | |}|S t| || |}|S )a  Check validity of provided distance matrix, or calculates L2-distance matrix if dm is not provided.

    Args:
        desc1: Batch of descriptors of a shape :math:`(B1, D)`.
        desc2: Batch of descriptors of a shape :math:`(B2, D)`.
        dm_: Tensor containing the distances from each descriptor in desc1
          to each descriptor in desc2, shape of :math:`(B1, B2)`.

    N)r'   r   )r/   r0   r1   r$   r%   r%   r&   _get_lazy_distance_matrix/   s   

r2   r$   c                 C   s4   t jdd| j| jd}t jdd| jt jd}||fS )zOutput empty tensors.

    Returns:
            - Descriptor distance of matching descriptors, shape of :math:`(0, 1)`.
            - Long tensor indexes of matching descriptors in desc1 and desc2, shape of :math:`(0, 2)`.

    r   r   )devicedtyper   )r   emptyr3   r4   long)r$   distsidxsr%   r%   r&   	_no_matchA   s   r9   c                 C   s   t | ddg t |ddg t| dkst|dkrt| S t| ||}tj|dd\}}tjd|d|jd}t	|
dd|
ddgd}|
dd|
ddfS )	ai  Find nearest neighbors in desc2 for each vector in desc1.

    If the distance matrix dm is not provided, :py:func:`torch.cdist` is used.

    Args:
        desc1: Batch of descriptors of a shape :math:`(B1, D)`.
        desc2: Batch of descriptors of a shape :math:`(B2, D)`.
        dm: Tensor containing the distances from each descriptor in desc1
          to each descriptor in desc2, shape of :math:`(B1, B2)`.

    Returns:
        - Descriptor distance of matching descriptors, shape of :math:`(B1, 1)`.
        - Long tensor indexes of matching descriptors in desc1 and desc2, shape of :math:`(B1, 2)`.

    BDIMr   r   r   r3   r   )r   lenr9   r2   r   r   aranger   r3   r
   view)r/   r0   r$   distance_matrixmatch_dists	idxs_in_2idxs_in1matches_idxsr%   r%   r&   match_nnN   s   rG   c                 C   s<  t | ddg t |ddg t| dkst|dkrt| S t| ||}t|d|d}tj|dd\}}tj|dd\}}tj||jd}	|d|dkrs|	|| d| k}
t	|	
dd|
ddgd|
 }||
 }n|	|| d| k}
t	|
dd|	
ddgd|
 }||
 }|
dd|
dd	fS )
a  Find mutual nearest neighbors in desc2 for each vector in desc1.

    If the distance matrix dm is not provided, :py:func:`torch.cdist` is used.

    Args:
        desc1: Batch of descriptors of a shape :math:`(B1, D)`.
        desc2: Batch of descriptors of a shape :math:`(B2, D)`.
        dm: Tensor containing the distances from each descriptor in desc1
          to each descriptor in desc2, shape of :math:`(B1, B2)`.

    Return:
        - Descriptor distance of matching descriptors, shape of. :math:`(B3, 1)`.
        - Long tensor indexes of matching descriptors in desc1 and desc2, shape of :math:`(B3, 2)`,
          where 0 <= B3 <= min(B1, B2)

    r:   r;   r   r   r<   r=   Nr>   r   )r   r?   r9   r2   r   r   r   r@   r3   r
   rA   )r/   r0   r$   rB   msrC   rD   match_dists2	idxs_in_1minsize_idxs
mutual_nnsrF   r%   r%   r&   	match_mnni   s"   "
"rM   皙?r)   c                 C   s   t | ddg t |ddg |jd dk rt| S t| ||}tj|dddd\}}|dddf |dddf  }||k}|| }	t|	dkrLt|S tjd|d|j	d	| }
|dddf | }t
|
d
d|d
dgd}|	d
d|d
dfS )a  Find nearest neighbors in desc2 for each vector in desc1.

    The method satisfies first to second nearest neighbor distance <= th.

    If the distance matrix dm is not provided, :py:func:`torch.cdist` is used.

    Args:
        desc1: Batch of descriptors of a shape :math:`(B1, D)`.
        desc2: Batch of descriptors of a shape :math:`(B2, D)`.
        th: distance ratio threshold.
        dm: Tensor containing the distances from each descriptor in desc1
          to each descriptor in desc2, shape of :math:`(B1, B2)`.

    Return:
        - Descriptor distance of matching descriptors, shape of :math:`(B3, 1)`.
        - Long tensor indexes of matching descriptors in desc1 and desc2. Shape: :math:`(B3, 2)`,
          where 0 <= B3 <= B1.

    r:   r;   r   r   r   Fr   largestNr=   r>   )r   shaper9   r2   r   topkr?   r@   r   r3   r
   rA   )r/   r0   r)   r$   rB   valsrD   ratiomaskrC   rE   rF   r%   r%   r&   	match_snn   s    rV   ffffff?c                 C   s  t | ddg t |ddg | jd dk s|jd dk r t| S t| ||}t| |||\}}t|| || \}}t|dkrt|dkr|d}t|s\t	j
| | dd}	n-|| j|ddd}
|||dd|
  jdd}	|	|d|d}	|	jddd d	k }|	jddd d	k }||d
 }||d
 }||d
 }||d
 }t	|dddf \}}t	|dddf \}}|| }t	|| || }|}|d
d|d
d}}||fS t|\}}||fS )a  Find mutual nearest neighbors in desc2 for each vector in desc1.

    the method satisfies first to second nearest neighbor distance <= th.

    If the distance matrix dm is not provided, :py:func:`torch.cdist` is used.

    Args:
        desc1: Batch of descriptors of a shape :math:`(B1, D)`.
        desc2: Batch of descriptors of a shape :math:`(B2, D)`.
        th: distance ratio threshold.
        dm: Tensor containing the distances from each descriptor in desc1
          to each descriptor in desc2, shape of :math:`(B1, B2)`.

    Return:
        - Descriptor distance of matching descriptors, shape of. :math:`(B3, 1)`.
        - Long tensor indexes of matching descriptors in desc1 and desc2,
          shape of :math:`(B3, 2)` where 0 <= B3 <= B1.

    r:   r;   r   r   r   g      ?)pr<   g:0yE>r>   N)r   rQ   r9   r2   rV   r   r?   flipr   r   r   floattorepeat_interleaver   r   absr   reshaper   rA   sortmax)r/   r0   r)   r$   rB   dists1idx1dists2idx2idxs_dm	idxs1_repmutual_idxs1mutual_idxs2
good_idxs1
good_idxs2dists1_gooddists2_good_idx_upl1idx_upl2rC   rF   r%   r%   r&   
match_smnn   s:   
(rp   r(   Flafs1lafs2r+   r*   c                 C   s  t | ddg t |ddg d}t| ||}	|	j}
|jd dk r$t|	S tdtd|jd }tj|	|ddd	\}}|d
d
df }t	|
dd}|| }tj||dd  ddd}|d
d
dd
f |d
d
dd
f |k |
|  }|jdd\}}|}|d
d
df }|| }||k}|| }t|dkrt|	S tjd|d|	jd| }|| }t|
dd|
ddgd}|
dd|
dd}}|s||fS tj|	dd\}}|d
d
df ||d
d
df  k}|| || fS )af  Find nearest neighbors in desc2 for each vector in desc1.

    The method satisfies first to second nearest neighbor distance <= th,
    and assures 2nd nearest neighbor is geometrically inconsistent with the 1st one
    (see :cite:`MODS2015` for more details)

    If the distance matrix dm is not provided, :py:func:`torch.cdist` is used.

    Args:
        desc1: Batch of descriptors of a shape :math:`(B1, D)`.
        desc2: Batch of descriptors of a shape :math:`(B2, D)`.
        lafs1: LAFs of a shape :math:`(1, B1, 2, 3)`.
        lafs2: LAFs of a shape :math:`(1, B2, 2, 3)`.

        th: distance ratio threshold.
        spatial_th: minimal distance in pixels to 2nd nearest neighbor.
        mutual: also perform mutual nearest neighbor check
        dm: Tensor containing the distances from each descriptor in desc1
          to each descriptor in desc2, shape of :math:`(B1, B2)`.

    Return:
        - Descriptor distance of matching descriptors, shape of :math:`(B3, 1)`.
        - Long tensor indexes of matching descriptors in desc1 and desc2. Shape: :math:`(B3, 2)`,
          where 0 <= B3 <= B1.

    r:   r;   g    .Ar   r   
   r   FrO   Nr>   )rX   r   r<   r=   )r   r2   r4   rQ   r9   r`   r   r   rR   r   rA   normr[   r?   r@   r   r3   r
   )r/   r0   rq   rr   r)   r+   r*   r$   
BIG_NUMBERrB   r4   num_candidates	vals_candrD   rS   xy2candidates_xykdist
fginn_valsfginn_vals_best_fginn_idxs_bestvals_2ndrT   rU   rC   rE   rF   rm   idxs_in_1_mut	good_maskr%   r%   r&   match_fginn   s>   $6$r   c                       sN   e Zd ZdZddededdf fdd	Zd
ededeeef fddZ	  Z
S )DescriptorMatcherar  Module version of matching functions.

    See :func:`~kornia.feature.match_nn`, :func:`~kornia.feature.match_snn`,
        :func:`~kornia.feature.match_mnn` or :func:`~kornia.feature.match_smnn` for more details.

    Args:
        match_mode: type of matching, can be `nn`, `snn`, `mnn`, `smnn`.
        th: threshold on distance ratio, or other quality measure.

    snnrN   
match_moder)   r   Nc                    sJ   t    | }g d| _|| jvrt| d| j || _|| _d S )Nnnmnnr   smnn is not supported. Try one of )super__init__lowerknown_modesNotImplementedErrorr   r)   )selfr   r)   _match_mode	__class__r%   r&   r   F  s   



zDescriptorMatcher.__init__r/   r0   c                 C   sl   | j dkrt||}|S | j dkrt||}|S | j dkr&t||| j}|S | j dkr4t||| j}|S t)a  Run forward.

        Args:
            desc1: Batch of descriptors of a shape :math:`(B1, D)`.
            desc2: Batch of descriptors of a shape :math:`(B2, D)`.

        Returns:
            - Descriptor distance of matching descriptors, shape of :math:`(B3, 1)`.
            - Long tensor indexes of matching descriptors in desc1 and desc2,
                shape of :math:`(B3, 2)` where :math:`0 <= B3 <= B1`.

        r   r   r   r   r   rG   rM   rV   r)   rp   r   )r   r/   r0   outr%   r%   r&   forwardO  s   

	



zDescriptorMatcher.forward)r   rN   )__name__
__module____qualname____doc__strrZ   r   r	   r   r   __classcell__r%   r%   r   r&   r   :  s    &	r   c                       s   e Zd ZdZ			ddedededed	ed
df fddZdde	de	de
e	 d
ee	e	f fddZ		dde	de	dede
e d
ee	e	e
e f f
ddZ  ZS )DescriptorMatcherWithSteerera  Matching that is invariant under rotations, using Steerers.

    Args:
        steerer: An instance of :func:`kornia.feature.steerers.DiscreteSteerer`.
        steerer_order: order of discretisation of rotation angles, e.g. 4 leads to quarter rotations.
        steer_mode: can be `global`, `local`.
            `global` means that the we output matches from the global rotation with most matches.
            `local` means that we output matches from a distance matrix
            where the distance between each descriptor pair is the minimal over rotations.
        match_mode: type of matching, can be `nn`, `snn`, `mnn`, `smnn`.
            WARNING: using steer_mode `global` with match_mode `nn` will lead to bad results
            since `nn` doesn't generate different amount of matches depending on goodness of fit.
        th: threshold on distance ratio, or other quality measure.

    Example:
        >>> import kornia as K
        >>> import kornia.feature as KF
        >>> device = K.utils.get_cuda_or_mps_device_if_available()
        >>> img1 = torch.randn([1, 3, 768, 768], device=device)
        >>> img2 = torch.randn([1, 3, 768, 768], device=device)
        >>> dedode = KF.DeDoDe.from_pretrained(detector_weights="L-C4-v2", descriptor_weights="B-SO2").to(device)
        >>> steerer_order = 8  # discretisation order of rotation angles
        >>> steerer = KF.steerers.DiscreteSteerer.create_dedode_default(
        ... generator_type="SO2", steerer_order=steerer_order
        ... )
        >>> steerer = steerer.to(device)
        >>> matcher = KF.matching.DescriptorMatcherWithSteerer(
        ... steerer=steerer, steerer_order=steerer_order, steer_mode="global", match_mode="smnn", th=0.98
        ... )
        >>> with torch.inference_mode():
        ...     kps1, scores1, descs1 = dedode(img1, n=20_000)
        ...     kps2, scores2, descs2 = dedode(img2, n=20_000)
        ...     kps1, kps2, descs1, descs2 = kps1[0], kps2[0], descs1[0], descs2[0]
        ...     dists, idxs, num_rot = matcher(
        ...         descs1, descs2, normalize=True, subset_size=1000,
        ...     )
        >>> # print(f"{idxs.shape[0]} tentative matches with steered DeDoDe")
        >>> # print(f"at rotation of {num_rot * 360 / steerer_order} degrees")

    globalr   rN   steerersteerer_order
steer_moder   r)   r   Nc                    s   t    || _|| _| }ddg| _|| jvr#t| d| j || _| }g d| _|| jvr>t| d| j || _	|| _
d S )Nr   localr   r   )r   r   r   r   r   known_steer_modesr   r   r   r   r)   )r   r   r   r   r   r)   _steer_moder   r   r%   r&   r     s   





z%DescriptorMatcherWithSteerer.__init__r   r   r$   c                 C   sl   | j dkrt|||dS | j dkrt|||dS | j dkr&t||| j|dS | j dkr4t||| j|dS t)Nr   )r$   r   r   r   r   )r   r   r   r$   r%   r%   r&   matching_function  s   



z.DescriptorMatcherWithSteerer.matching_functionFr/   r0   	normalizesubset_sizec                 C   s  d}|rt jjj|dd}t jjj|dd}| jdkr|dur\t |jd d| }t |jd d| }| || || |d\}}}| jj|||d}| 	||d\}	}
|	|
|fS | 	||d\}	}
d}t
d| jD ]%}| jj||d}| 	||d\}}|jd |
jd kr|||}	}
}qmn2| jd	krt||}t
d| jD ]}| jj||d}t||}t ||}q| 	|||\}	}
nt|	|
|fS )
a  Run forward.

        Args:
            desc1: Batch of descriptors of a shape :math:`(B1, D)`.
            desc2: Batch of descriptors of a shape :math:`(B2, D)`.
            normalize: bool to decide whether to normalize descriptors to unit norm.
            subset_size: If set, the subset size to use for determining optimal
                number of rotations. Smaller subset size leads to faster but less
                accurate matching. Only used when `self.steer_mode` is `"global"`.

        Returns:
            - Descriptor distance of matching descriptors, shape of :math:`(B3, 1)`.
            - Long tensor indexes of matching descriptors in desc1 and desc2,
                shape of :math:`(B3, 2)` where :math:`0 <= B3 <= B1`.
            - Number of global rotations from desc1 to desc2, in terms of `self.steerer_order`
                (will be `None` if `self.steer_mode` is `local`).

        Nr>   r<   r   r   )r   )steerer_powerr   r   r   )r   r   
functionalr   r   randpermrQ   r   steer_descriptionsr   ranger   r'   minimumr   )r   r/   r0   r   r   rot1to2
subsample1
subsample2rm   distidxrdist_newidx_newr$   dm_newr%   r%   r&   r     sL   





z$DescriptorMatcherWithSteerer.forward)r   r   rN   N)FN)r   r   r   r   r   intr   rZ   r   r	   r   r   r   boolr   r   r%   r%   r   r&   r   i  s@    -(r   c                       s|   e Zd ZU dZddgZeee  ed< ddede	e
eef  ddf fd	d
Zdededededeeef f
ddZ  ZS )GeometryAwareDescriptorMatchera_  Module version of matching functions.

    See :func:`~kornia.feature.match_nn`, :func:`~kornia.feature.match_snn`,
        :func:`~kornia.feature.match_mnn` or :func:`~kornia.feature.match_smnn` for more details.

    Args:
        match_mode: type of matching, can be `fginn`.
        th: threshold on distance ratio, or other quality measure.

    fginnadalamr   Nr   paramsr   c                    sD   t    | }|| jvrt| d| j || _|pi | _d S )Nr   )r   r   r   r   r   r   r   )r   r   r   r   r   r%   r&   r     s   

z'GeometryAwareDescriptorMatcher.__init__r/   r0   rq   rr   c              	   C   sv   | j dkr t }|| j t|||||d |d |d }|S | j dkr9t }|| j t|||||d}|S t)a  Run forward.

        Args:
            desc1: Batch of descriptors of a shape :math:`(B1, D)`.
            desc2: Batch of descriptors of a shape :math:`(B2, D)`.
            lafs1: LAFs of a shape :math:`(1, B1, 2, 3)`.
            lafs2: LAFs of a shape :math:`(1, B2, 2, 3)`.

        Returns:
            - Descriptor distance of matching descriptors, shape of :math:`(B3, 1)`.
            - Long tensor indexes of matching descriptors in desc1 and desc2,
                shape of :math:`(B3, 2)` where :math:`0 <= B3 <= B1`.

        r   r)   r+   r*   r   r,   )r   r.   updater   r   r   r   r   )r   r/   r0   rq   rr   r   r   _paramsr%   r%   r&   r     s   
 
z&GeometryAwareDescriptorMatcher.forward)r   N)r   r   r   r   r   r   r   r   __annotations__r   r   r	   r   r   r   r   r%   r%   r   r&   r     s
   
 (.r   r   )rN   N)rW   N)rN   r(   FN)'typingr   r   r   r   r   r   r   kornia.corer   r	   r
   kornia.core.checkr   r   kornia.feature.lafr   kornia.feature.steerersr   kornia.utils.helpersr   r   r   r   r'   r   r.   r2   r9   rG   rM   rZ   rV   rp   r   r   r   r   r   r%   r%   r%   r&   <module>   sV     ((,&,&<
	
N/ 