o
    oiO                     @   s0  d dl mZ d dlmZmZmZmZ d dlmZ d dl	Z	d dl
m  mZ d dlmZ d dlmZmZmZ eeeeef Zeeeef ef Zeeef Zd(ded	ed
efddZ	d)deeeeef f deeeeef f deeeeeef f  d
efddZG dd deZG dd deZdeeef deeef deeef d
efddZ		 	d*dedeeeeef f deeeeef f deeeeef f ded	eded
efddZdedeed f d!eed f d
efd"d#Z 	$	 	d+dedeeeeef f deeeeef f ded%ed
efd&d'Z!dS ),    )ceil)OptionalTupleUnioncast)warnN)_pair)ModuleTensorpadFpadding	unpaddingreturnc                 C   s   t tt| } t| dvrt|rdnd dt| dkr+t| d }t| d }n| dd }| dd }t t|| } | S )	zCreate argument for padding op.)      	UnpaddingPaddingz? must be either an int, tuple of two ints or tuple of four intsr   r      N)r   TuplePadTyper   lenAssertionErrorFullPadType)r   r   pad_vertpad_horz r   R/home/ubuntu/.local/lib/python3.10/site-packages/kornia/contrib/extract_patches.pycreate_padding_tuple!   s   r   original_sizewindow_sizestridec                 C   s.  t tttf t| } t tttf t|}|du r|}t tttf t|}| d |d  |d  }| d |d  |d  }|dkrJ|d | }nd}|dkrW|d | }nd}|d dkrf|d  }}n
|d }t|d }|d dkr}|d  }	}
n
|d }	t|d }
t|t|t|	t|
f}|S )ay  Compute required padding to ensure chaining of :func:`extract_tensor_patches` and
    :func:`combine_tensor_patches` produces expected result.

    Args:
        original_size: the size of the original tensor.
        window_size: the size of the sliding window used while extracting patches.
        stride: The stride of the sliding window. Optional: if not specified, window_size will be used.

    Return:
        The required padding as a tuple of four ints: (top, bottom, left, right)

    Example:
        >>> image = torch.arange(12).view(1, 1, 4, 3)
        >>> padding = compute_padding((4,3), (3,3))
        >>> out = extract_tensor_patches(image, window_size=(3, 3), stride=(3, 3), padding=padding)
        >>> combine_tensor_patches(out, original_size=(4, 3), window_size=(3, 3), stride=(3, 3), unpadding=padding)
        tensor([[[[ 0,  1,  2],
                  [ 3,  4,  5],
                  [ 6,  7,  8],
                  [ 9, 10, 11]]]])

    .. note::
        This function will be implicitly used in :func:`extract_tensor_patches` and :func:`combine_tensor_patches` if
        `allow_auto_(un)padding` is set to True.

    Nr   r   r   )r   r   intr   r   )r   r   r   remainder_verticalremainder_horizontalvertical_paddinghorizontal_paddingtop_paddingbottom_paddingleft_paddingright_paddingr   r   r   r   compute_padding5   s.   r)   c                       sp   e Zd ZdZ			ddeeeeef f deeeeef f deded	d
f
 fddZ	de
d	e
fddZ  ZS )ExtractTensorPatchesa<
  Module that extract patches from tensors and stack them.

    In the simplest case, the output value of the operator with input size
    :math:`(B, C, H, W)` is :math:`(B, N, C, H_{out}, W_{out})`.

    where
      - :math:`B` is the batch size.
      - :math:`N` denotes the total number of extracted patches stacked in
      - :math:`C` denotes the number of input channels.
      - :math:`H`, :math:`W` the input height and width of the input in pixels.
      - :math:`H_{out}`, :math:`W_{out}` denote to denote to the patch size
        defined in the function signature.
        left-right and top-bottom order.

    * :attr:`window_size` is the size of the sliding window and controls the
      shape of the output tensor and defines the shape of the output patch.
    * :attr:`stride` controls the stride to apply to the sliding window and
      regulates the overlapping between the extracted patches.
    * :attr:`padding` controls the amount of implicit zeros-paddings on both
      sizes at each dimension.
    * :attr:`allow_auto_padding` allows automatic calculation of the padding required
      to fit the window and stride into the image.

    The parameters :attr:`window_size`, :attr:`stride` and :attr:`padding` can
    be either:

        - a single ``int`` -- in which case the same value is used for the
          height and width dimension.
        - a ``tuple`` of two ints -- in which case, the first `int` is used for
          the height dimension, and the second `int` for the width dimension.

    :attr:`padding` can also be a ``tuple`` of four ints -- in which case, the
    first two ints are for the height dimension while the last two ints are for
    the width dimension.

    Args:
        input: tensor image where to extract the patches with shape :math:`(B, C, H, W)`.
        window_size: the size of the sliding window and the output patch size.
        stride: stride of the sliding window.
        padding: Zero-padding added to both side of the input.
        allow_auto_adding: whether to allow automatic padding if the window and stride do not fit into the image.

    Shape:
        - Input: :math:`(B, C, H, W)`
        - Output: :math:`(B, N, C, H_{out}, W_{out})`

    Returns:
        the tensor with the extracted patches.

    Examples:
        >>> input = torch.arange(9.).view(1, 1, 3, 3)
        >>> patches = extract_tensor_patches(input, (2, 3))
        >>> input
        tensor([[[[0., 1., 2.],
                  [3., 4., 5.],
                  [6., 7., 8.]]]])
        >>> patches[:, -1]
        tensor([[[[3., 4., 5.],
                  [6., 7., 8.]]]])

    r   r   Fr   r   r   allow_auto_paddingr   Nc                    s&   t    || _|| _|| _|| _d S N)super__init__r   r   r   r+   )selfr   r   r   r+   	__class__r   r   r.      s
   

zExtractTensorPatches.__init__inputc                 C   s   t || j| j| j| jdS )N)r   r   r+   )extract_tensor_patchesr   r   r   r+   r/   r2   r   r   r   forward   s   zExtractTensorPatches.forwardr   r   F)__name__
__module____qualname____doc__r   r    r   PadTypeboolr.   r
   r5   __classcell__r   r   r0   r   r*   y   s"    Ar*   c                       s   e Zd ZdZ			ddeeef deeeeef f deeeeeef f  ded	e	d
df fddZ
ded
efddZ  ZS )CombineTensorPatchesaJ  Module that combines patches back into full tensors.

    In the simplest case, the output value of the operator with input size
    :math:`(B, N, C, H_{out}, W_{out})` is :math:`(B, C, H, W)`.

    where
      - :math:`B` is the batch size.
      - :math:`N` denotes the total number of extracted patches stacked in
      - :math:`C` denotes the number of input channels.
      - :math:`H`, :math:`W` the input height and width of the input in pixels.
      - :math:`H_{out}`, :math:`W_{out}` denote to denote to the patch size
        defined in the function signature.
        left-right and top-bottom order.


    * :attr:`original_size` is the size of the original image prior to
      extracting tensor patches and defines the shape of the output patch.
    * :attr:`window_size` is the size of the sliding window used while
      extracting tensor patches.
    * :attr:`stride` controls the stride to apply to the sliding window and
      regulates the overlapping between the extracted patches.
    * :attr:`unpadding` is the amount of padding to be removed. If specified,
      this value must be the same as padding used while extracting tensor patches.
    * :attr:`allow_auto_unpadding` allows automatic calculation of the padding required
      to fit the window and stride into the image. This must be used if the
      `allow_auto_padding` flag was used for extracting the patches.


    The parameters :attr:`original_size`, :attr:`window_size`, :attr:`stride`, and :attr:`unpadding` can
    be either:

        - a single ``int`` -- in which case the same value is used for the
          height and width dimension.
        - a ``tuple`` of two ints -- in which case, the first `int` is used for
          the height dimension, and the second `int` for the width dimension.

    :attr:`unpadding` can also be a ``tuple`` of four ints -- in which case, the
    first two ints are for the height dimension while the last two ints are for
    the width dimension.

    Args:
        patches: patched tensor with shape :math:`(B, N, C, H_{out}, W_{out})`.
        original_size: the size of the original tensor and the output size.
        window_size: the size of the sliding window used while extracting patches.
        stride: stride of the sliding window.
        unpadding: remove the padding added to both side of the input.
        allow_auto_unpadding: whether to allow automatic unpadding of the input
            if the window and stride do not fit into the original_size.
        eps: small value used to prevent division by zero.

    Shape:
        - Input: :math:`(B, N, C, H_{out}, W_{out})`
        - Output: :math:`(B, C, H, W)`

    Example:
        >>> out = extract_tensor_patches(torch.arange(16).view(1, 1, 4, 4), window_size=(2, 2), stride=(2, 2))
        >>> combine_tensor_patches(out, original_size=(4, 4), window_size=(2, 2), stride=(2, 2))
        tensor([[[[ 0,  1,  2,  3],
                  [ 4,  5,  6,  7],
                  [ 8,  9, 10, 11],
                  [12, 13, 14, 15]]]])

    .. note::
        This function is supposed to be used in conjunction with :class:`ExtractTensorPatches`.

    Nr   Fr   r   r   r   allow_auto_unpaddingr   c                    s8   t    || _|| _|d ur|n|| _|| _|| _d S r,   )r-   r.   r   r   r   r   r?   )r/   r   r   r   r   r?   r0   r   r   r.     s   

zCombineTensorPatches.__init__r2   c                 C   s   t || j| j| j| j| jdS )N)r   r   r?   )combine_tensor_patchesr   r   r   r   r?   r4   r   r   r   r5   "  s   zCombineTensorPatches.forward)Nr   F)r7   r8   r9   r:   r   r    r   r   r;   r<   r.   r
   r5   r=   r   r   r0   r   r>      s&    G
r>   c                 C   sH   | d |d  |d  }| d |d  |d  }|dks |dkr"dS dS )Nr   r   FTr   )r   r   r   r!   r"   r   r   r   _check_patch_fit-  s
   rA   :0yE>patchesr?   epsc                 C   s  | j dkrtd| j ttttf t|}ttttf t|}ttttf t|}|d |d k|d |d kB rItd| d| d|skt|||sk|sdt	d| d	| d
| ddd nt
|||d}|rqt|}tj| jd | jd |d |d | j| jd}|rt||d}|jdd }| ddddd} | | jd d| jd } d}	t| sd}	| j}
|  } | }tj|||d}tj||||d}|rt|dd |D }tj| |||d}|rt|dd |D }|||  }|	r||
}|S )a  Restore input from patches.

    See :class:`~kornia.contrib.CombineTensorPatches` for details.

    Args:
        patches: patched tensor with shape :math:`(B, N, C, H_{out}, W_{out})`.
        original_size: the size of the original tensor and the output size.
        window_size: the size of the sliding window used while extracting patches.
        stride: stride of the sliding window.
        unpadding: remove the padding added to both side of the input.
        allow_auto_unpadding: whether to allow automatic unpadding of the input
            if the window and stride do not fit into the original_size.
        eps: small value used to prevent division by zero.

    Return:
        The combined patches in an image tensor with shape :math:`(B, C, H, W)`.

    Example:
        >>> out = extract_tensor_patches(torch.arange(16).view(1, 1, 4, 4), window_size=(2, 2), stride=(2, 2))
        >>> combine_tensor_patches(out, original_size=(4, 4), window_size=(2, 2), stride=(2, 2))
        tensor([[[[ 0,  1,  2,  3],
                  [ 4,  5,  6,  7],
                  [ 8,  9, 10, 11],
                  [12, 13, 14, 15]]]])

    .. note::
        This function is supposed to be used in conjunction with :func:`extract_tensor_patches`.

       z/Invalid input shape, we expect BxNxCxHxW. Got: r   r   zStride=z- should be less than or equal to Window size=z, information is missing6The window will not fit into the image. 
Window size: 	
Stride: 
Image size: aH  
This means we probably cannot correctly recombine patches. By enabling `allow_auto_unpadding`, the input will be unpadded to fit the window and stride.
If the patches have been obtained through `extract_tensor_patches` with the correct padding or the argument `allow_auto_padding`, this will result in a correct reconstruction.
stacklevelr   r   r   r   )devicedtype)r   N   r   )kernel_sizer   )r2   output_sizerP   r   c                 S      g | ]}| qS r   r   .0ir   r   r   
<listcomp>      z*combine_tensor_patches.<locals>.<listcomp>c                 S   rR   r   r   rS   r   r   r   rV     rW   )ndim
ValueErrorshaper   r   r    r   r   rA   r   r)   r   torchonesrL   rM   r   permutereshapeis_floating_pointfloatFunfoldfoldto)rC   r   r   r   r?   r   rD   r\   restored_sizeint_flagrM   unfold_onesnorm_mapsaturated_restored_tensorrestored_tensorr   r   r   r@   :  sf   
& 
	

r@   r2   window_sizes.stridesc                    s   |   d d \}}td|   t ||D ]\}}}| |||} q| jdg d fdd D R   } | j|d|g|R  S )Nr   r   r   c                 3   s    | ]	}|t   V  qd S r,   )r   )rT   dimdimsr   r   	<genexpr>  s    z,_extract_tensor_patchesnd.<locals>.<genexpr>rO   )sizerangerm   ziprb   r]   
contiguousview)r2   rk   rl   
batch_sizenum_channelsrm   
patch_sizer   r   rn   r   _extract_tensor_patchesnd  s   ,ry   r   r+   c                 C   s   t | stdt|  t| jdkrtd| j ttt	t	f t
|}ttt	t	f t
|}| jd | jd f}|s_t|||s_|sXtd| d| d| d	d
d nt|||d}|rjt|}t| |} t| ||S )a  Extract patches from tensors and stacks them.

    See :class:`~kornia.contrib.ExtractTensorPatches` for details.

    Args:
        input: tensor image where to extract the patches with shape :math:`(B, C, H, W)`.
        window_size: the size of the sliding window and the output patch size.
        stride: stride of the sliding window.
        padding: Zero-padding added to both side of the input.
        allow_auto_padding: whether to allow automatic padding if the window and stride do not fit into the image.

    Returns:
        the tensor with the extracted patches with shape :math:`(B, N, C, H_{out}, W_{out})`.

    Examples:
        >>> input = torch.arange(9.).view(1, 1, 3, 3)
        >>> patches = extract_tensor_patches(input, (2, 3))
        >>> input
        tensor([[[[0., 1., 2.],
                  [3., 4., 5.],
                  [6., 7., 8.]]]])
        >>> patches[:, -1]
        tensor([[[[3., 4., 5.],
                  [6., 7., 8.]]]])

    z&Input input type is not a Tensor. Got r   z-Invalid input shape, we expect BxCxHxW. Got: rO   rF   rG   rH   z
This means that the final incomplete patches will be dropped. By enabling `allow_auto_padding`, the input will be padded to fit the window and stride.r   rI   rK   )r[   	is_tensor	TypeErrortyper   rZ   rY   r   r   r    r   rA   r   r)   r   r   ry   )r2   r   r   r   r+   r   r   r   r   r3     s*   
!
r3   )Fr,   )Fr   rB   r6   )"mathr   typingr   r   r   r   warningsr   r[   torch.nn.functionalnn
functionalra   torch.nn.modules.utilsr   kornia.corer	   r
   r   r    r   r   r;   r<   r   r)   r*   r>   rA   r`   r@   ry   r3   r   r   r   r   <module>   sz   
DV2^
*o