o
    oiZ                     @   s
  U d dl mZmZmZmZmZ d dlZd dlm  m	Z
 d dlmZ d dlmZ d dlmZmZmZmZmZ d dlmZmZ d dlmZ d dlmZ d	Zeed
< ddgZee ed< g dZee ed< g dZee ed< eeedZ ee!ee f ed< dd dD Z"ee!e!f ed< d6de#dee!ef fddZ$de#de#defdd Z%G d!d" d"ej&Z'G d#d$ d$ej&Z(G d%d& d&ej&Z)d'e!d(ee!ef defd)d*Z*G d+d, d,ej&Z+G d-d. d.ej&Z,G d/d0 d0ej&Z-d'e!d1e!dee!ef fd2d3Z.G d4d5 d5ej&Z/dS )7    )AnyDictListTupleUnionN)nn)pi)Tensorcossintensorzeros)GaussianBlur2dSpatialGradient)cart2pol)create_meshgridg;f?sqrt2gpu?g "?COEFFS_N1_K1)"g#[?x@ٔ+?K'"?COEFFS_N2_K8)r   r   r   gˈfF?COEFFS_N3_K8)xyrhophithetaCOEFFSc                 C   s   i | ]	}|d | dqS )zChttps://github.com/manyids2/mkd_pytorch/raw/master/mkd_pytorch/mkd-z-64.pth ).0kr   r   F/home/ubuntu/.local/lib/python3.10/site-packages/kornia/feature/mkd.py
<dictcomp>%   s    r!   )cartpolarconcaturls    
patch_sizereturnc                 C   s^   t | | dd}|ddddddf }|ddddddf }t||\}}||||d}|S )z1Get cartesian and polar parametrizations of grid.Theightwidthnormalized_coordinatesr   N   )xyrhophi)r   r   )r'   kgridr.   r/   r0   r1   	grid_dictr   r   r    get_grid_dict+   s   r4   d1d2c                 C   sF   t jt | t |dd\}}t j||gdddd}|t jS )z&Get order for doing kronecker product.ij)indexing   dim)torchmeshgridarangestackreshapetoint64)r5   r6   grid_d1grid_d2
kron_orderr   r   r    get_kron_order5   s    rG   c                       sB   e Zd ZdZd fddZdedefddZdefd	d
Z  Z	S )MKDGradientsa  Module, which computes gradients of given patches, stacked as [magnitudes, orientations].

    Given gradients $g_x$, $g_y$ with respect to $x$, $y$ respectively,
      - $\mathbox{mags} = $\sqrt{g_x^2 + g_y^2 + eps}$
      - $\mathbox{oris} = $\mbox{tan}^{-1}(\nicefrac{g_y}{g_x})$.

    Args:
        patch_size: Input patch size in pixels.

    Returns:
        gradients of given patches.

    Shape:
        - Input: (B, 1, patch_size, patch_size)
        - Output: (B, 2, patch_size, patch_size)

    Example:
        >>> patches = torch.rand(23, 1, 32, 32)
        >>> gradient = MKDGradients()
        >>> g = gradient(patches) # 23x2x32x32

    r(   Nc                    s$   t    d| _tdddd| _d S )N:0yE>diffr-   F)modeorder
normalized)super__init__epsr   gradself	__class__r   r    rO   T   s   
zMKDGradients.__init__r.   c                 C   s   t |tstdt| t|jdkstd|j | | }|d d d d dd d d d f }|d d d d dd d d d f }tj	t
||| jdd}|S )N Input type is not a Tensor. Got    -Invalid input shape, we expect Bx1xHxW. Got: r   r-   r:   )
isinstancer	   	TypeErrortypelenshape
ValueErrorrQ   r=   catr   rP   )rS   r.   grads_xygxgyr/   r   r   r    forwardZ   s   
""zMKDGradients.forwardc                 C   s   | j jS N)rU   __name__rR   r   r   r    __repr__f   s   zMKDGradients.__repr__r(   N)
re   
__module____qualname____doc__rO   r	   rc   strrf   __classcell__r   r   rT   r    rH   <   s
    rH   c                	       sr   e Zd ZdZdedeeeeef  eeeef df f ddf fddZ	d	e
de
fd
dZdefddZ  ZS )VonMisesKernela  Module, which computes parameters of Von Mises kernel given coefficients, and embeds given patches.

    Args:
        patch_size: Input patch size in pixels.
        coeffs: List of coefficients. Some examples are hardcoded in COEFFS,

    Returns:
        Von Mises embedding of given parametrization.

    Shape:
        - Input: (B, 1, patch_size, patch_size)
        - Output: (B, d, patch_size, patch_size)

    Examples:
        >>> oris = torch.rand(23, 1, 32, 32)
        >>> vm = VonMisesKernel(patch_size=32,
        ...                     coeffs=[0.14343168,
        ...                             0.268285,
        ...                             0.21979234])
        >>> emb = vm(oris) # 23x7x32x32

    r'   coeffs.r(   Nc                    s   t    || _t|}| d| t|d }|| _d| d | _t	dd||g}t
|d }|ddd}td| d g}t||d |d < t|dd  ||d d < |ddd}| d| | d| | d| d S )Nrn   r-   r9   r<   emb0frangeweights)rN   rO   r'   r   register_bufferr\   ndr=   onesr?   rA   r   sqrt)rS   r'   rn   b_coeffsrs   ro   rp   rq   rT   r   r    rO      s"   
zVonMisesKernel.__init__r.   c                 C   s   t |tstdt| t|jdkr|jd dkr$td|j t | jts3tdt| | j|	|
dddd}| j|| }t|}t|}tj|||gdd}| j| }|S )NrV   rW   r-   rX   zEmb0 type is not a Tensor. Got r   r:   )rY   r	   rZ   r[   r\   r]   r^   ro   rB   repeatsizerp   r
   r   r=   r_   rq   )rS   r.   ro   rp   emb1emb2	embeddingr   r   r    rc      s   

zVonMisesKernel.forwardc              
   C   s.   | j j d| j d| j d| j d| j d
S )N(patch_size=z, n=z, d=z	, coeffs=))rU   re   r'   rs   rt   rn   rR   r   r   r    rf      s   .zVonMisesKernel.__repr__)re   rh   ri   rj   intr   r   floatr   rO   r	   rc   rk   rf   rl   r   r   rT   r    rm   j   s
    >rm   c                       sb   e Zd ZdZddededdf fdd	Zd
edefddZdedefddZ	de
fddZ  ZS )EmbedGradientsa=  Module that computes gradient embedding, weighted by sqrt of magnitudes of given patches.

    Args:
        patch_size: Input patch size in pixels.
        relative: absolute or relative gradients.

    Returns:
        Gradient embedding.

    Shape:
        - Input: (B, 2, patch_size, patch_size)
        - Output: (B, 7, patch_size, patch_size)

    Examples:
        >>> grads = torch.rand(23, 2, 32, 32)
        >>> emb_grads = EmbedGradients(patch_size=32,
        ...                            relative=False)
        >>> emb = emb_grads(grads) # 23x7x32x32

    r&   Fr'   relativer(   Nc                    s   t    || _|| _d| _t|td d| _t||dd}t	|d d d d d d df |d d d d d d df \}}| 
d| d S )	NrI   r   r'   rn   Tr)   r   r-   r1   )rN   rO   r'   r   rP   rm   r   kernelr   r   rr   )rS   r'   r   r2   _r1   rT   r   r    rO      s   
>zEmbedGradients.__init__magsc                 C   s   t || j }|S )z@Embed square roots of magnitudes with eps for numerical reasons.)r=   rv   rP   )rS   r   r   r   r    emb_mags   s   zEmbedGradients.emb_magsgradsc                 C   s   t |tstdt| t|jdkstd|j |d d d dd d d d f }|d d dd d d d d f }| jrH|| j	| }| 
|| | }|S )NrV   rW   z-Invalid input shape, we expect Bx2xHxW. Got: r-   )rY   r	   rZ   r[   r\   r]   r^   r   r1   rB   r   r   )rS   r   r   orisr/   r   r   r    rc      s   
  zEmbedGradients.forwardc                 C   s   | j j d| j d| j dS )Nr}   z, relative=r~   )rU   re   r'   r   rR   r   r   r    rf      s   zEmbedGradients.__repr__)r&   F)re   rh   ri   rj   r   boolrO   r	   r   rc   rk   rf   rl   r   r   rT   r    r      s    r   kernel_typegridsc                    s  dt t t d t d d | dkrd}ddg}n
| dkr"d	}d
dg}t| }||d  jd } fdd| D }dd | D }t|t| d}t|t| d}|||d   }	|||d   }
t	|j
|j
}|	d|dddf |
d|dddf  }|S )z<Compute embeddings for cartesian and polar parametrizations.      ?r9   )r1   r0   r.   r/   r"   r   r.   r/   r#   r   r1   r0   r   r<   c                    s   i | ]\}}|| |  qS r   r   r   r   vfactorsr   r    r!      s    z,spatial_kernel_embedding.<locals>.<dictcomp>c                 S   s&   i | ]\}}|| d  d  qS )r   )	unsqueezer   r   r   r   r    r!      s   & r   r-   N)r   r   listkeysr]   itemsrm   r   squeezerG   rt   index_select)r   r   coeffs_params_r   r'   grids_normedvm_avm_bemb_aemb_brF   spatial_kernelr   r   r    spatial_kernel_embedding   s$   
0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ede	fddZ
dee	e	f fddZde	de	fddZdefddZ  ZS )ExplicitSpacialEncodinga  Module that computes explicit cartesian or polar embedding.

    Args:
        kernel_type: Parametrization of kernel ``'polar'`` or ``'cart'``.
        fmap_size: Input feature map size in pixels.
        in_dims: Dimensionality of input feature map.
        do_gmask: Apply gaussian mask.
        do_l2: Apply l2-normalization.

    Returns:
        Explicit cartesian or polar embedding.

    Shape:
        - Input: (B, in_dims, fmap_size, fmap_size)
        - Output: (B, out_dims, fmap_size, fmap_size)

    Example:
        >>> emb_ori = torch.rand(23, 7, 32, 32)
        >>> ese = ExplicitSpacialEncoding(kernel_type='polar',
        ...                               fmap_size=32,
        ...                               in_dims=7,
        ...                               do_gmask=True,
        ...                               do_l2=True)
        >>> desc = ese(emb_ori) # 23x175x32x32

    r#   r&      Tr   	fmap_sizein_dimsdo_gmaskdo_l2r(   Nc           	         s   t    |dvrt| d|| _|| _|| _|| _|| _t|| _	d | _
t| j| j	}| jr=| jdd| _
|| j
 }| d|d |jd | _| j| j | _| j| _|  \}}| d| | d| d S )	N)r#   r"   z" is not valid, use polar or cart).r   )sigmaembr   r{   idx1)rN   rO   NotImplementedErrorr   r   r   r   r   r4   gridgmaskr   	get_gmaskrr   r   r]   d_embout_dimsodims	init_kron)	rS   r   r   r   r   r   r   r{   r   rT   r   r    rO   $  s*   


z ExplicitSpacialEncoding.__init__r   c                 C   s6   | j d | j d   }td|d  |d  }|S )zCompute Gaussian mask.r0   r<   r9   )r   maxr=   exp)rS   r   norm_rhor   r   r   r    r   L  s   z!ExplicitSpacialEncoding.get_gmaskc                 C   sL   t | j| j}tjt| j}t|d|dddf }||dddf fS )z3Initialize helper variables to calculate kronecker.r-   Nr   )	rG   r   r   r=   jitannotater	   r   r   )rS   kron_embr{   r   r   r    r   R  s   z!ExplicitSpacialEncoding.init_kronr.   c                 C   s   t |tstdt| t|jdk|jd | jkB s)td| j d|j tj	
t| j}t|d|}|| j }|jdd}| jrMtj|dd}|S )NrV   rW   r-   z!Invalid input shape, we expect BxzxHxW. Got: )r9      r:   )rY   r	   rZ   r[   r\   r]   r   r^   r=   r   r   r   r   r{   sumr   F	normalize)rS   r.   r   rz   outputr   r   r    rc   Y  s   

zExplicitSpacialEncoding.forwardc                 C   s>   | j j d| j d| j d| j d| j d| j d| j dS )Nz(kernel_type=z, fmap_size=
, in_dims=z, out_dims=z, do_gmask=z, do_l2=r~   )rU   re   r   r   r   r   r   r   rR   r   r   r    rf   f  s   
z ExplicitSpacialEncoding.__repr__)r#   r&   r   TT)re   rh   ri   rj   rk   r   r   rO   r   r	   r   r   r   rc   rf   rl   r   r   rT   r    r     s0    (r   c                       s   e Zd ZdZ			ddedeeeeeef f df ded	ed
ede	ddf fddZ
deeeeef f ddfddZdddZdddZdddZdddZdedefddZdefddZ  ZS ) 	WhiteningaB  Module, performs supervised or unsupervised whitening.

    This is based on the paper "Understanding and Improving Kernel Local Descriptors".
    See :cite:`mukundan2019understanding` for more details.

    Args:
        xform: Variant of whitening to use. None, 'lw', 'pca', 'pcaws', 'pcawt'.
        whitening_model: Dictionary with keys 'mean', 'eigvecs', 'eigvals' holding Tensors.
        in_dims: Dimensionality of input descriptors.
        output_dims: (int) Dimensionality reduction.
        keval: Shrinkage parameter.
        t: Attenuation parameter.

    Returns:
        l2-normalized, whitened descriptors.

    Shape:
        - Input: (B, in_dims, fmap_size, fmap_size)
        - Output: (B, out_dims, fmap_size, fmap_size)

    Examples:
        >>> descs = torch.rand(23, 238)
        >>> whitening_model = {'pca': {'mean': torch.zeros(238),
        ...                            'eigvecs': torch.eye(238),
        ...                            'eigvals': torch.ones(238)}}
        >>> whitening = Whitening(xform='pcawt',
        ...                       whitening_model=whitening_model,
        ...                       in_dims=238,
        ...                       output_dims=128,
        ...                       keval=40,
        ...                       t=0.7)
        >>> wdescs = whitening(descs) # 23x128

       (   ffffff?xformwhitening_modelNr   output_dimskevaltr(   c                    s   t    || _|| _|| _|| _d| _t||}|| _t	j
t|dd| _t	j
t|d d d |f dd| _t	j
t|d | dd| _|d urS| | d S d S )Nr   T)requires_grad)rN   rO   r   r   r   r   pvalminr   r   	Parameterr   meanr=   eyeevecsru   evalsload_whitening_parameters)rS   r   r   r   r   r   r   rT   r   r    rO     s   
	
&zWhitening.__init__c                 C   s   | j dkrdnd}|| }|d | j_|d d d d | jf | j_|d d | j | j_| j| j| j| j	d}|| j    d S )Nlwpcar   eigvecseigvals)r   r   pcawspcawt)
r   r   datar   r   r   _modify_pca
_modify_lw_modify_pcaws_modify_pcawt)rS   r   algowh_modelmodificationsr   r   r    r     s   z#Whitening.load_whitening_parametersc                 C   s
   d| _ dS )zModify powerlaw parameter.g      ?N)r   rR   r   r   r    r     s   
zWhitening._modify_pcac                 C   s   dS )zNo modification required.Nr   rR   r   r   r    r     s    zWhitening._modify_lwc                 C   s>   | j | j }d| | j  | }| jtt|d | j_dS )zShrinkage for eigenvalues.r-         N)r   r   r   r=   diagpowr   )rS   alphar   r   r   r    r     s    zWhitening._modify_pcawsc                 C   s,   d| j  }| jtt| j| | j_dS )zAttenuation for eigenvalues.r   N)r   r   r=   r   r   r   r   )rS   mr   r   r    r     s   
"zWhitening._modify_pcawtr.   c                 C   sz   t |tstdt| t|jdkstd|j || j }|| j }t	
|t	t	|| j }tj|ddS )NrV   r9   z)Invalid input shape, we expect NxD. Got: r-   r:   )rY   r	   rZ   r[   r\   r]   r^   r   r   r=   signr   absr   r   r   rS   r.   r   r   r    rc     s   


zWhitening.forwardc                 C   s&   | j j d| j d| j d| j dS )Nz(xform=r   , output_dims=r~   )rU   re   r   r   r   rR   r   r   r    rf     s   &zWhitening.__repr__)r   r   r   rg   )re   rh   ri   rj   rk   r   r   r	   r   r   rO   r   r   r   r   r   rc   rf   rl   r   r   rT   r    r   r  s6    ("




r   c                       sf   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edefddZdefddZ	  Z
S )MKDDescriptora  Module that computes Multiple Kernel local descriptors.

    This is based on the paper "Understanding and Improving Kernel Local Descriptors".
    See :cite:`mukundan2019understanding` for more details.

    Args:
        patch_size: Input patch size in pixels.
        kernel_type: Parametrization of kernel ``'concat'``, ``'cart'``, ``'polar'``.
        whitening: Whitening transform to apply ``None``, ``'lw'``, ``'pca'``, ``'pcawt'``, ``'pcaws'``.
        training_set: Set that model was trained on ``'liberty'``, ``'notredame'``, ``'yosemite'``.
        output_dims: Dimensionality reduction.

    Returns:
        Explicit cartesian or polar embedding.

    Shape:
        - Input: :math:`(B, in_{dims}, fmap_{size}, fmap_{size})`.
        - Output: :math:`(B, out_{dims}, fmap_{size}, fmap_{size})`,

    Examples:
        >>> patches = torch.rand(23, 1, 32, 32)
        >>> mkd = MKDDescriptor(patch_size=32,
        ...                     kernel_type='concat',
        ...                     whitening='pcawt',
        ...                     training_set='liberty',
        ...                     output_dims=128)
        >>> desc = mkd(patches) # 23x128

    r&   r$   r   libertyr   r'   r   	whiteningtraining_setr   r(   Nc                    s@  t    || _|| _|| _|| _d|d  | _td| j| jfd| _t	 | _
d}d}| jdkr4||gn| jg| _d| _|d	|d
i}i | _| jD ]$}	t|||	 d}
t|	||
jjd}t|
|| j|	< |  j|j7  _qHt|| j| _| jd urtjjt| j tdd}|| }t||| j| jd| _| j| _|   d S )Nffffff?@      r   	replicater#   r"   r$   r   TFr'   r   r   r   r   cpumap_locationr   r   )rN   rO   r'   r   r   r   r   r   	smoothingrH   	gradientsparametrizationsr   featsr   r   r   rt   r   
Sequentialr   r   r=   hubload_state_dict_from_urlr%   devicer   whitening_layereval)rS   r'   r   r   r   r   polar_scart_srelative_orientationsparametrizationgradient_embeddingspatial_encodingwhitening_modelsr   rT   r   r    rO     s@   



zMKDDescriptor.__init__patchesc                 C   s   t |tstdt| t|jdkstd|j | |}| |}g }| j	D ]}| j
| |j || j
| | q,tj|dd}tj|dd}| jd urZ| |}|S )NrV   rW   rX   r-   r:   )rY   r	   rZ   r[   r\   r]   r^   r   r   r   r   rB   r   appendr=   r_   r   r   r   r   )rS   r  gfeaturesr  r/   r   r   r    rc   5  s   





zMKDDescriptor.forwardc                 C   s6   | j j d| j d| j d| j d| j d| j dS )Nr}   z, kernel_type=z, whitening=z, training_set=r   r~   )rU   re   r'   r   r   r   r   rR   r   r   r    rf   P  s   
zMKDDescriptor.__repr__)r&   r$   r   r   r   )re   rh   ri   rj   r   rk   rO   r	   rc   rf   rl   r   r   rT   r    r     s,     2r   r   c                 C   s&   t jjt|  t dd}|| }|S )zLoad whitening model.r   r   )r=   r   r   r%   r   )r   r   r  r   r   r   r    load_whitening_model[  s   r  c                       sX   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edefddZ  Z	S )SimpleKDz+Example to write custom Kernel Descriptors.r&   r#   r   r   r   r'   r   r   r   r   r(   Nc                    s   t    |dk}d|d  }|| _td||fd}t }	t||d}
t|||
jjd}t	|t
|||j|d}t||	|
||| _d S )	Nr#   r   r   r   r   r   r   r   )rN   rO   r'   r   rH   r   r   r   rt   r   r  r   r   r   r  )rS   r'   r   r   r   r   r   r   r   r   oriesewhrT   r   r    rO   e  s   
zSimpleKD.__init__r.   c                 C   s
   |  |S rd   )r  r   r   r   r    rc   }  s   
zSimpleKD.forward)r&   r#   r   r   r   )
re   rh   ri   rj   r   rk   rO   r	   rc   rl   r   r   rT   r    r  b  s*    r  )r&   )0typingr   r   r   r   r   r=   torch.nn.functionalr   
functionalr   kornia.constantsr   kornia.corer	   r
   r   r   r   kornia.filtersr   r   kornia.geometry.conversionsr   kornia.utilsr   r   r   __annotations__r   r   r   r   rk   r%   r   r4   rG   ModulerH   rm   r   r   r   r   r   r  r  r   r   r   r    <module>   s8    
.F9jrw