o
    oi#*                     @   s   U d dl Z d dlZd dlmZmZ d dlZd dlmZ d dlmZ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mZmZ i Zeeef ed	< d
ed< G dd dejZG dd dejZG dd dejZdS )    N)DictOptional)nn)KORNIA_CHECK_LAFKORNIA_CHECK_SHAPE)get_gaussian_kernel2d)SpatialGradient   )ellipse_to_lafextract_patches_from_pyramidget_laf_orientationget_laf_scalemake_upright	scale_lafset_laf_orientationurlszEhttps://github.com/ducha-aiki/affnet/raw/master/pretrained/AffNet.pthaffnetc                       sT   e Zd ZdZddededdf fdd	Zdefd
dZde	j
de	j
fddZ  ZS )PatchAffineShapeEstimatora  Module, which estimates the second moment matrix of the patch gradients.

    The method determines the affine shape of the local feature as in :cite:`baumberg2000`.

    Args:
        patch_size: the input image patch size.
        eps: for safe division.

       绽|=
patch_sizeepsreturnNc                    sT   t    || _tdd| _|| _t| jtd }t	| j| jf||fd| _
d S )Nsobelr	   g       @T)super__init__r   r   gradientr   floatmathsqrtr   	weighting)selfr   r   sigma	__class__ O/home/ubuntu/.local/lib/python3.10/site-packages/kornia/feature/affine_shape.pyr   6   s   
z"PatchAffineShapeEstimator.__init__c                 C   s   | j j d| j d| j dS )N(patch_size=z, eps=))r$   __name__r   r   r!   r%   r%   r&   __repr__>   s   z"PatchAffineShapeEstimator.__repr__patchc                 C   s6  t |g d | j|j|j| _| || j }|dddddf }|dddddf }tj|dj	ddj	ddd|| j	ddj	ddd|dj	ddj	dddgdd}|| j
k  jddddk|j}tg d	|j|jddd
}|d|  ||  }||jdddd  }|S )zRun forward.

        Args:
            patch: :math:`(B, 1, H, W)`

        Returns:
            torch.Tensor: ellipse_shape :math:`(B, 1, 3)`

        B1HWNr   r	      dimTr4   keepdim)      ?g        r7      r7   )r   r    todtypedevicer   torchcatpowmeanr   r   sumtensorviewmax)r!   r,   gradsgxgyellipse_shapebad_maskcircular_shaper%   r%   r&   forwardA   s"   
$
(z!PatchAffineShapeEstimator.forward)r   r   )r)   
__module____qualname____doc__intr   r   strr+   r<   TensorrJ   __classcell__r%   r%   r#   r&   r   +   s
    
r   c                	       sf   e Zd ZdZ	ddedeej deddf fd	d
Z	de
fddZdejdejdejfddZ  ZS )LAFAffineShapeEstimatoraw  Module, which extracts patches using input images and local affine frames (LAFs).

    Then runs :class:`~kornia.feature.PatchAffineShapeEstimator` on patches to estimate LAFs shape.

    Then original LAF shape is replaced with estimated one. The original LAF orientation is not preserved,
    so it is recommended to first run LAFAffineShapeEstimator and then LAFOrienter,


    Args:
        patch_size: the input image patch size.
        affine_shape_detector: Patch affine shape estimator, :class:`~kornia.feature.PatchAffineShapeEstimator`.
        preserve_orientation: if True, the original orientation is preserved.

        NTr   affine_shape_detectorpreserve_orientationr   c                    sB   t    || _|pt| j| _|| _|rtjdtdd d S d S )Nz`LAFAffineShapeEstimator` default behaviour is changed and now it does preserve original LAF orientation. Make sure your code accounts for this.r2   
stacklevel)	r   r   r   r   rT   rU   warningswarnDeprecationWarning)r!   r   rT   rU   r#   r%   r&   r   u   s   

z LAFAffineShapeEstimator.__init__c                 C   s&   | j j d| j d| j d| j dS )Nr'   z, affine_shape_detector=z, preserve_orientation=r(   )r$   r)   r   rT   rU   r*   r%   r%   r&   r+      s   
z LAFAffineShapeEstimator.__repr__lafimgc                 C   s   t | t|g d |jdd \}}| j}t|t||ddd||}| |}tj	|dddd 
d|gdd	||d
}t|}	| jrNt|}
t|}t|}t||	| }| jret||
}|S )Run forward.

        Args:
            laf: :math:`(B, N, 2, 3)`
            img: :math:`(B, 1, H, W)`

        Returns:
            LAF_out: :math:`(B, N, 2, 3)`

        r-   Nr2   Tr	   r8   ).r2   r3      )r   r   shaper   r   r   rB   rT   r<   r=   	unsqueezer   rU   r   r
   r   r   )r!   r[   r\   r.   NPSpatchesrG   ellipses
scale_origori_origlaf_outellipse_scaler%   r%   r&   rJ      s    
0
zLAFAffineShapeEstimator.forward)rS   NT)r)   rK   rL   rM   rN   r   r   Moduleboolr   rO   r+   r<   rP   rJ   rQ   r%   r%   r#   r&   rR   e   s    $rR   c                       sl   e Zd ZdZddededdf fdd	Zeddejde	dejfddZ
dejdejdejfddZ  ZS )LAFAffNetShapeEstimatora]  Module, which extracts patches using input images and local affine frames (LAFs).

    Then runs AffNet on patches to estimate LAFs shape. This is based on the original code from paper
    "Repeatability Is Not Enough: Learning Discriminative Affine Regions via Discriminability"".
    See :cite:`AffNet2018` for more details.

    Then original LAF shape is replaced with estimated one. The original LAF orientation is not preserved,
    so it is recommended to first run LAFAffineShapeEstimator and then LAFOrienter.

    Args:
        pretrained: Download and set pretrained weights to the model.

    FT
pretrainedrU   r   Nc                    s|  t    ttjddddddtjdddt tjdddddddtjdddt tjdddd	dddtjdddt tjdddddddtjdddt tjdd
dd	dddtjd
ddt tjd
d
dddddtjd
ddt tdtjd
ddddddt t	d| _
d| _|rtjjtd tdd}| j|d dd || _|rtjdtd	d |   d S )Nr	      r8   F)kernel_sizepaddingbias)affine)ro   striderp   rq   rS   r2   @   g      ?   r   Tr   cpu)map_location
state_dict)strictz`LAFAffNetShapeEstimator` default behaviour is changed and now it does preserve original LAF orientation. Make sure your code accounts for this.rV   )r   r   r   
SequentialConv2dBatchNorm2dReLUDropoutTanhAdaptiveAvgPool2dfeaturesr   r<   hubload_state_dict_from_urlr   r;   load_state_dictrU   rX   rY   rZ   eval)r!   rm   rU   pretrained_dictr#   r%   r&   r      sJ   
z LAFAffNetShapeEstimator.__init__ư>xr   c                 C   s,   t j| ddd\}}| |  | |  S )zNormalize the input by batch.)r^   Tr5   )r<   std_meandetach)r   r   spmpr%   r%   r&   _normalize_input   s   z(LAFAffNetShapeEstimator._normalize_inputr[   r\   c                 C   s|  t | t|g d |jdd \}}| j}t|t||ddd||}| | |dd}t	j
d|ddd	f ddd d	|ddd	f ddd gdd
}t	j
|dddf dddd|dddf ddd gdd
}	t	j
||	gdd
||dd}
t	j
|
|ddddddddf gdd
}t|}| jrt|}t|}tt||| }| jrt||}|S )r]   r-   Nr2   Tr^   r	   r8   r7   r   r3   )r   r   r`   r   r   r   rB   r   r   r<   r=   reshaper   rU   r   r   r   )r!   r[   r\   r.   rb   rc   rd   xya1a2new_laf_no_centernew_lafrf   rg   ri   rh   r%   r%   r&   rJ      s$   FB.
zLAFAffNetShapeEstimator.forward)FT)r   )r)   rK   rL   rM   rk   r   staticmethodr<   rP   r   r   rJ   rQ   r%   r%   r#   r&   rl      s    *$rl   )r   rX   typingr   r   r<   r   kornia.core.checkr   r   kornia.filters.kernelsr   kornia.filters.sobelr   r[   r
   r   r   r   r   r   r   r   rO   __annotations__rj   r   rR   rl   r%   r%   r%   r&   <module>   s   
$
:E