o
    oir=                     @  s  d dl mZ d dlZd dlZd dlm  mZ d dlm	Z	m
Z
mZmZmZmZmZ d dlmZmZmZ d dlmZmZ g dZd-d	d
ZG dd de	ZG dd de	ZG dd de	Zd.d/ddZd0d1ddZ	d0d2d"d#Zd3d%d&Zd4d'd(Z 	d0d2d)d*Z!d5d+d,Z"dS )6    )annotationsN)ModuleTensoronespadstacktensorzeros)KORNIA_CHECKKORNIA_CHECK_IS_TENSORKORNIA_CHECK_SHAPE)filter2dgaussian_blur2d)PyrDownPyrUpScalePyramidbuild_laplacian_pyramidbuild_pyramidpyrdownpyrupupscale_doublereturnr   c                   C  s,   t g dg dg dg dg dggd S )z&Return a pre-computed gaussian kernel.)      ?      @      @r   r   )r         0@      8@r   r   )r   r   g      B@r   r   g      p@)r    r   r   U/home/ubuntu/.local/lib/python3.10/site-packages/kornia/geometry/transform/pyramid.py_get_pyramid_gaussian_kernel)   s   r   c                      s.   e Zd ZdZdd fddZdddZ  ZS )r   a3  Blur a tensor and downsamples it.

    Args:
        border_type: the padding mode to be applied before convolving.
          The expected modes are: ``'constant'``, ``'reflect'``,
          ``'replicate'`` or ``'circular'``.
        align_corners: interpolation flag.
        factor: the downsampling factor

    Return:
        the downsampled tensor.

    Shape:
        - Input: :math:`(B, C, H, W)`
        - Output: :math:`(B, C, H / 2, W / 2)`

    Examples:
        >>> input = torch.rand(1, 2, 4, 4)
        >>> output = PyrDown()(input)  # 1x2x2x2

    reflectF       @border_typestralign_cornersboolfactorfloatr   Nonec                   s    t    || _|| _|| _d S N)super__init__r"   r$   r&   )selfr"   r$   r&   	__class__r   r   r+   R   s   

zPyrDown.__init__inputr   c                 C  s   t || j| j| jS r)   )r   r"   r$   r&   r,   r/   r   r   r   forwardX   s   zPyrDown.forwardr    Fr!   )r"   r#   r$   r%   r&   r'   r   r(   r/   r   r   r   __name__
__module____qualname____doc__r+   r1   __classcell__r   r   r-   r   r   ;   s    r   c                      s.   e Zd ZdZdd fd
dZdddZ  ZS )r   a	  Upsample a tensor and then blurs it.

    Args:
        borde_type: the padding mode to be applied before convolving.
          The expected modes are: ``'constant'``, ``'reflect'``,
          ``'replicate'`` or ``'circular'``.
        align_corners: interpolation flag.

    Return:
        the upsampled tensor.

    Shape:
        - Input: :math:`(B, C, H, W)`
        - Output: :math:`(B, C, H * 2, W * 2)`

    Examples:
        >>> input = torch.rand(1, 2, 4, 4)
        >>> output = PyrUp()(input)  # 1x2x8x8

    r    Fr"   r#   r$   r%   r   r(   c                   s   t    || _|| _d S r)   )r*   r+   r"   r$   )r,   r"   r$   r-   r   r   r+   r   s   

zPyrUp.__init__r/   r   c                 C  s   t || j| jS r)   )r   r"   r$   r0   r   r   r   r1   w      zPyrUp.forwardr    F)r"   r#   r$   r%   r   r(   r3   r4   r   r   r-   r   r   \   s    r   c                      sN   e Zd ZdZ	d d! fddZd"ddZd#ddZd$ddZd%ddZ  Z	S )&r   a  Create an scale pyramid of image, usually used for local feature detection.

    Images are consequently smoothed with Gaussian blur and downscaled.

    Args:
        n_levels: number of the levels in octave.
        init_sigma: initial blur level.
        min_size: the minimum size of the octave in pixels.
        double_image: add 2x upscaled image as 1st level of pyramid. OpenCV SIFT does this.

    Returns:
        1st output: images
        2nd output: sigmas (coefficients for scale conversion)
        3rd output: pixelDists (coefficients for coordinate conversion)

    Shape:
        - Input: :math:`(B, C, H, W)`
        - Output 1st: :math:`[(B, C, NL, H, W), (B, C, NL, H/2, W/2), ...]`
        - Output 2nd: :math:`[(B, NL), (B, NL), (B, NL), ...]`
        - Output 3rd: :math:`[(B, NL), (B, NL), (B, NL), ...]`

    Examples:
        >>> input = torch.rand(2, 4, 100, 100)
        >>> sp, sigmas, pds = ScalePyramid(3, 15)(input)

       皙?   Fn_levelsint
init_sigmar'   min_sizedouble_imager%   r   r(   c                   sN   t    || _d| _|| _|| _|d d | _ddt| j  | _|| _	d S )Nr<         r   )
r*   r+   r?   extra_levelsrA   rB   borderr'   
sigma_steprC   )r,   r?   rA   rB   rC   r-   r   r   r+      s   

zScalePyramid.__init__r#   c                 C  sF   | j j d| j d| j d| j d| j d| j d| j d| j dS )	Nz
(n_levels=z, init_sigma=z, min_size=z, extra_levels=z	, border=z, sigma_step=z, double_image=))	r.   r5   r?   rA   rB   rF   rG   rH   rC   )r,   r   r   r   __repr__   s    
zScalePyramid.__repr__sigmac                 C  s(   t d| d }|d dkr|d7 }|S )Ng       @r   rD   r   rE   )r@   )r,   rK   ksizer   r   r   get_kernel_size   s   zScalePyramid.get_kernel_sizer/   r   tuple[Tensor, float, float]c                 C  s   d}d}| j rt|}d}|d9 }n|}| j|kr;tt| jd |d  d}| |}t|||f||f}| j}n|}|||fS )Nr   g      ?r!   rD   g{Gz?)rC   r   rA   maxmathsqrtrM   r   )r,   r/   pixel_distance	cur_sigmaxrK   rL   	cur_levelr   r   r   get_first_level   s   



zScalePyramid.get_first_levelrT   /tuple[list[Tensor], list[Tensor], list[Tensor]]c                 C  s  |  \}}}}| |\}}}|t|| j| j |j|j g}|t|| j| j |j|j g}|gg}	d}
	 |	d d }td| j| j D ]S}|t	
| jd d  }| |}t|| d| d}|d dkrw|d7 }t|||f||f}|| j9 }|	d | ||d d d |f< ||d d d |f< qN|	d | j  }|d d d d d d dd d df }|d9 }| j}t| d| d| jkrn1|	|g ||t|| j| j |j  ||t|| j| j |j  |
d7 }
q?d	d
 |	D }|||fS )Nr   TrE   rD   r   r<   r!   c                 S  s   g | ]}t |d qS )rD   )r   ).0ir   r   r   
<listcomp>   s    z(ScalePyramid.forward.<locals>.<listcomp>)sizerV   r   r?   rF   todevicedtyperangerP   rQ   rH   rM   minr   appendrA   rB   torch)r,   rT   bs_rU   rS   rR   sigmaspixel_distspyroct_idx	level_idxrK   rL   _pyrnextOctaveFirstLevel
output_pyrr   r   r   r1      s@   ((

$&&
zScalePyramid.forward)r<   r=   r>   F)
r?   r@   rA   r'   rB   r@   rC   r%   r   r(   )r   r#   )rK   r'   r   r@   )r/   r   r   rN   )rT   r   r   rW   )
r5   r6   r7   r8   r+   rJ   rM   rV   r1   r9   r   r   r-   r   r   {   s    


r   r    Fr!   r/   r"   r#   r$   r%   r&   r'   c           
      C  s`   t | g d t }| j\}}}}t| ||}tj|tt|| tt|| fd|d}	|	S )a  Blur a tensor and downsamples it.

    .. image:: _static/img/pyrdown.png

    Args:
        input: the tensor to be downsampled.
        border_type: the padding mode to be applied before convolving.
          The expected modes are: ``'constant'``, ``'reflect'``,
          ``'replicate'`` or ``'circular'``.
        align_corners: interpolation flag.
        factor: the downsampling factor

    Return:
        the downsampled tensor.

    Examples:
        >>> input = torch.arange(16, dtype=torch.float32).reshape(1, 1, 4, 4)
        >>> pyrdown(input, align_corners=True)
        tensor([[[[ 3.7500,  5.2500],
                  [ 9.7500, 11.2500]]]])

    BCHWbilinearr\   moder$   )r   r   shaper   Finterpolater@   r'   )
r/   r"   r$   r&   kernelre   heightwidthx_bluroutr   r   r   r      s   r   c           	      C  sP   t | g d t }| j\}}}}tj| |d |d fd|d}t|||}|S )a  Upsample a tensor and then blurs it.

    .. image:: _static/img/pyrup.png

    Args:
        input: the tensor to be downsampled.
        border_type: the padding mode to be applied before convolving.
          The expected modes are: ``'constant'``, ``'reflect'``, ``'replicate'`` or ``'circular'``.
        align_corners: interpolation flag.

    Return:
        the downsampled tensor.

    Examples:
        >>> input = torch.arange(4, dtype=torch.float32).reshape(1, 1, 2, 2)
        >>> pyrup(input, align_corners=True)
        tensor([[[[0.7500, 0.8750, 1.1250, 1.2500],
                  [1.0000, 1.1250, 1.3750, 1.5000],
                  [1.5000, 1.6250, 1.8750, 2.0000],
                  [1.7500, 1.8750, 2.1250, 2.2500]]]])

    rn   rD   rs   rt   )r   r   rv   rw   rx   r   )	r/   r"   r$   ry   re   rz   r{   x_upr|   r   r   r   r   #  s   r   	max_levelr@   list[Tensor]c                 C  sn   t | g d tt|tp|dk d|  g }||  t|d D ]}|d }t|||}|| q#|S )a  Construct the Gaussian pyramid for a tensor image.

    .. image:: _static/img/build_pyramid.png

    The function constructs a vector of images and builds the Gaussian pyramid
    by recursively applying pyrDown to the previously built pyramid layers.

    Args:
        input : the tensor to be used to construct the pyramid.
        max_level: 0-based index of the last (the smallest) pyramid layer.
          It must be non-negative.
        border_type: the padding mode to be applied before convolving.
          The expected modes are: ``'constant'``, ``'reflect'``,
          ``'replicate'`` or ``'circular'``.
        align_corners: interpolation flag.

    Shape:
        - Input: :math:`(B, C, H, W)`
        - Output :math:`[(B, C, H, W), (B, C, H/2, W/2), ...]`

    rn   r   7Invalid max_level, it must be a positive integer. Got: rE   rX   )r   r
   
isinstancer@   rb   r`   r   )r/   r   r"   r$   pyramidre   img_currimg_downr   r   r   r   G  s   
r   rT   c                 C  s   t | o
| | d @  S NrE   )r%   rT   r   r   r   is_powerof_twor  s   r   c                 C  s   d| d   > S r   )
bit_lengthr   r   r   r   find_next_powerof_twow  r:   r   c                 C  s   t | g d tt|tp|dk d|  |  d }|  d }t|p)t| }|rAdt|| dt|| f}t| |d} t| |||}g }	t	|d D ]}
t
||
d  ||}||
 | }|	| qP|	|d  |	S )	a7  Construct the Laplacian pyramid for a tensor image.

    The function constructs a vector of images and builds the Laplacian pyramid
    by recursively computing the difference after applying
    pyrUp to the adjacent layer in its Gaussian pyramid.

    See :cite:`burt1987laplacian` for more details.

    Args:
        input : the tensor to be used to construct the pyramid with shape :math:`(B, C, H, W)`.
        max_level: 0-based index of the last (the smallest) pyramid layer.
          It must be non-negative.
        border_type: the padding mode to be applied before convolving.
          The expected modes are: ``'constant'``, ``'reflect'``,
          ``'replicate'`` or ``'circular'``.
        align_corners: interpolation flag.

    Return:
        Output: :math:`[(B, C, H, W), (B, C, H/2, W/2), ...]`

    rn   r   r   rD   r<   r    rE   rX   )r   r
   r   r@   r\   r   r   r   r   r`   r   rb   )r/   r   r"   r$   hwrequire_paddingpaddinggaussian_pyramidlaplacian_pyramidrZ   
img_expand	laplacianr   r   r   r   {  s&   r   c                 C  s  t |  t| g d | jdd | jd d | jd d f }t|| j| jd}| |dddddddf< |dddddddf dddf |dddddddf  d |dddddddf dddf< |dddddf |dddddf< |ddddddf dddddf |ddddddf  d |ddddddf dddddf< |ddddf |ddddf< |S )	a  Upscale image by the factor of 2, even indices maps to original indices.

    Odd indices are linearly interpolated from the even ones.

    Args:
        x: input image.

    Shape:
        - Input: :math:`(*, H, W)`
        - Output :math:`(*, H, W)`

    )*rq   rr   NrD   rX   )r^   r_   .rE   )r   r   rv   r	   r^   r_   )rT   double_shapeupscaledr   r   r   r     s   *f$l r   )r   r   r2   )
r/   r   r"   r#   r$   r%   r&   r'   r   r   r;   )r/   r   r"   r#   r$   r%   r   r   )
r/   r   r   r@   r"   r#   r$   r%   r   r   )rT   r@   r   r%   )rT   r@   r   r@   )rT   r   r   r   )#
__future__r   rP   rc   torch.nn.functionalnn
functionalrw   kornia.corer   r   r   r   r   r   r	   kornia.core.checkr
   r   r   kornia.filtersr   r   __all__r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   <module>   s*   $
!)%
+
6