a
    dL                     @   s   d dl mZmZ d dlmZmZmZmZmZm	Z	 d dl
Z
d dlmZ d dl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 d	lmZ d
gZG dd deZG dd
 d
eZdS )    )cycleislice)IteratorList
NamedTupleOptionalTupleUnionN)MixAugmentationBase)MixAugmentationBaseV2)_AugmentationBase)SequentialBase)ImageSequential	ParamItem)extract_tensor_patchesPatchSequentialc                   @   s"   e Zd ZU ee ed< eed< dS )PatchParamItemindicesparamN)__name__
__module____qualname__r   int__annotations__r    r   r   l/var/www/html/stable-diffusion-webui/venv/lib/python3.9/site-packages/kornia/augmentation/container/patch.pyr      s   
r   c                       s  e Zd ZdZddddddddejeeef ee	e
 e	e
 e
eee
eeef f e	ee  dd	 fd	d
Zee e
dddZd&ejee	eeef  eeeeef dddZd'eje	eeef  e	eeeeef  ejdddZd(ejeeef e	eeeeef  ejdddZejee dddZejeeeef  dddZeje	ej eeeje	ej ef dddZeje	ej ee eejeeje	ej f f ddd Zejee ejd!d"d#Zd)eje	ej e	ee  eejeejejf f dd$d%Z  ZS )*r   a  Container for performing patch-level image data augmentation.

    .. image:: https://kornia-tutorials.readthedocs.io/en/latest/_images/data_patch_sequential_7_0.png

    PatchSequential breaks input images into patches by a given grid size, which will be resembled back
    afterwards.

    Different image processing and augmentation methods will be performed on each patch region as
    in :cite:`lin2021patch`.

    Args:
        *args: a list of processing modules.
        grid_size: controls the grid board separation.
        padding: same or valid padding. If same padding, it will pad to include all pixels if the input
            tensor cannot be divisible by grid_size. If valid padding, the redundant border will be removed.
        same_on_batch: apply the same transformation across the batch.
            If None, it will not overwrite the function-wise settings.
        keepdim: whether to keep the output shape the same as input (True) or broadcast it
            to the batch form (False). If None, it will not overwrite the function-wise settings.
        patchwise_apply: apply image processing args will be applied patch-wisely.
            if ``True``, the number of args must be equal to grid number.
            if ``False``, the image processing args will be applied as a sequence to all patches.
        random_apply: randomly select a sublist (order agnostic) of args to
            apply transformation.
            If ``int`` (batchwise mode only), a fixed number of transformations will be selected.
            If ``(a,)`` (batchwise mode only), x number of transformations (a <= x <= len(args)) will be selected.
            If ``(a, b)`` (batchwise mode only), x number of transformations (a <= x <= b) will be selected.
            If ``True``, the whole list of args will be processed in a random order.
            If ``False`` and not ``patchwise_apply``, the whole list of args will be processed in original order.
            If ``False`` and ``patchwise_apply``, the whole list of args will be processed in original order
            location-wisely.

    .. note::
        Transformation matrix returned only considers the transformation applied in ``kornia.augmentation`` module.
        Those transformations in ``kornia.geometry`` will not be taken into account.

    .. note::
        See a working example `here <https://kornia-tutorials.readthedocs.io/en/
        latest/data_patch_sequential.html>`__.

    Examples:
        >>> import kornia.augmentation as K
        >>> input = torch.randn(2, 3, 224, 224)
        >>> seq = PatchSequential(
        ...     ImageSequential(
        ...         K.ColorJiggle(0.1, 0.1, 0.1, 0.1, p=0.5),
        ...         K.RandomPerspective(0.2, p=0.5),
        ...         K.RandomSolarize(0.1, 0.1, p=0.5),
        ...     ),
        ...     K.RandomAffine(360, p=1.0),
        ...     ImageSequential(
        ...         K.ColorJiggle(0.1, 0.1, 0.1, 0.1, p=0.5),
        ...         K.RandomPerspective(0.2, p=0.5),
        ...         K.RandomSolarize(0.1, 0.1, p=0.5),
        ...     ),
        ...     K.RandomSolarize(0.1, 0.1, p=0.1),
        ...     grid_size=(2,2),
        ...     patchwise_apply=True,
        ...     same_on_batch=True,
        ...     random_apply=False,
        ... )
        >>> out = seq(input)
        >>> out.shape
        torch.Size([2, 3, 224, 224])
        >>> out1 = seq(input, params=seq._params)
        >>> torch.equal(out, out1)
        True

    Perform ``OneOf`` transformation with ``random_apply=1`` and ``random_apply_weights`` in ``PatchSequential``.

        >>> import kornia
        >>> input = torch.randn(2, 3, 224, 224)
        >>> seq = PatchSequential(
        ...     ImageSequential(
        ...         K.ColorJiggle(0.1, 0.1, 0.1, 0.1, p=0.5),
        ...         K.RandomPerspective(0.2, p=0.5),
        ...         K.RandomSolarize(0.1, 0.1, p=0.5),
        ...     ),
        ...     K.RandomAffine(360, p=1.0),
        ...     K.RandomSolarize(0.1, 0.1, p=0.1),
        ...     grid_size=(2,2),
        ...     patchwise_apply=False,
        ...     random_apply=1,
        ...     random_apply_weights=[0.5, 0.3, 0.8]
        ... )
        >>> out = seq(input)
        >>> out.shape
        torch.Size([2, 3, 224, 224])
       r   sameNTF)	grid_sizepaddingsame_on_batchkeepdimpatchwise_applyrandom_applyrandom_apply_weights)	argsr   r    r!   r"   r#   r$   r%   returnc          
         s   |r|du rd}	nx|rb|du rbt ||d |d  kr\tdt | d|d |d   d|}	n(|rt|ttfrtd	| d
n|}	t j||||	|d |dvrtd| d
|| _|| _|| _	d S )NT)   r   Fr   r(   zBThe number of processing modules must be equal with grid size.Got z and z<. Please set random_apply = True or patchwise_apply = False.zFOnly boolean value allowed when `patchwise_apply` is set to True. Got .)r!   r"   r$   r%   )r   validz0`padding` must be either `same` or `valid`. Got )
len
ValueError
isinstancer   tuplesuper__init__r   r    r#   )
selfr   r    r!   r"   r#   r$   r%   r&   Z_random_apply	__class__r   r   r0   q   s6    zPatchSequential.__init__)paramsr'   c                 C   s0   |D ]&}|j jds$|j jdr dS qdS )NZRandomMixUpZRandomCutMixTF)r   name
startswith)r1   r4   r   r   r   r   contains_label_operations   s    z)PatchSequential.contains_label_operations)inputr    r   r'   c                 C   s   |d u r| j }|dkrd|d|d  |d|d   }}| d |d | | d |d | fS |dkr|d|d|d  |d   }|d|d|d  |d   }|d ||d  |d ||d  fS td| d	d S )
Nr*   r   r(      r   z2Expect `padding` as either 'valid' or 'same'. Got r)   )r   sizeNotImplementedError)r1   r8   r    r   phpwr   r   r   compute_padding   s    &($$$zPatchSequential.compute_padding)r8   r   padr'   c                 C   s^   |durt jj|t|}|du r*| j}|d|d  |d|d  f}|}t|||S )af  Extract patches from tensor.

        Example:
            >>> import kornia.augmentation as K
            >>> pas = PatchSequential(K.ColorJiggle(0.1, 0.1, 0.1, 0.1, p=1.0), patchwise_apply=False)
            >>> pas.extract_patches(torch.arange(16).view(1, 1, 4, 4), grid_size=(2, 2))
            tensor([[[[[ 0,  1],
                       [ 4,  5]]],
            <BLANKLINE>
            <BLANKLINE>
                     [[[ 2,  3],
                       [ 6,  7]]],
            <BLANKLINE>
            <BLANKLINE>
                     [[[ 8,  9],
                       [12, 13]]],
            <BLANKLINE>
            <BLANKLINE>
                     [[[10, 11],
                       [14, 15]]]]])
            >>> pas.extract_patches(torch.arange(54).view(1, 1, 6, 9), grid_size=(2, 2), pad=(-1, -1, -2, -2))
            tensor([[[[[19, 20, 21]]],
            <BLANKLINE>
            <BLANKLINE>
                     [[[22, 23, 24]]],
            <BLANKLINE>
            <BLANKLINE>
                     [[[28, 29, 30]]],
            <BLANKLINE>
            <BLANKLINE>
                     [[[31, 32, 33]]]]])
        Nr9   r:   )torchnn
functionalrA   listr   r<   r   )r1   r8   r   rA   Zwindow_sizeZstrider   r   r   extract_patches   s    &$zPatchSequential.extract_patches)patchesr   rA   r'   c                 C   s   |du r| j }|jd|d |d g|jdd R  }ttj||d dddd}ttj||d dddd}|durtjj	|dd	 |D }|S )
a  Restore input from patches.

        Example:
            >>> import kornia.augmentation as K
            >>> pas = PatchSequential(K.ColorJiggle(0.1, 0.1, 0.1, 0.1, p=1.0), patchwise_apply=False)
            >>> out = pas.extract_patches(torch.arange(16).view(1, 1, 4, 4), grid_size=(2, 2))
            >>> pas.restore_from_patches(out, grid_size=(2, 2))
            tensor([[[[ 0,  1,  2,  3],
                      [ 4,  5,  6,  7],
                      [ 8,  9, 10, 11],
                      [12, 13, 14, 15]]]])
        Nr:   r   r(   Zdimr9   c                 S   s   g | ]
}| qS r   r   ).0ir   r   r   
<listcomp>       z8PatchSequential.restore_from_patches.<locals>.<listcomp>)
r   viewshaperB   catchunkZsqueezerC   rD   rA   )r1   rG   r   rA   Zpatches_tensorZrestored_tensorr   r   r   restore_from_patches   s    (""z$PatchSequential.restore_from_patches)batch_shaper'   c                    s
  g | j sd| td|d |d  g|dd  }td|d |d    fdd|D  n| js| t|d |d  dg|dd  }fdd|D  n\| t|d |d g|dd  }tjd|d |d  |d d  fdd|D  S )	Nr(   r   r;   c                    s$   g | ]\}} t  |qS r   appendr   tolist)rJ   p_r   	out_paramr   r   rL      rM   z6PatchSequential.forward_parameters.<locals>.<listcomp>c                    s"   g | ]\}}  t|g|qS r   )rU   r   rJ   rW   rK   )rZ   r   r   rL     rM   )stepc                    s(   g | ] \}} t |  |qS r   rT   r[   rY   r   r   rL     rM   )r#   generate_parametersrB   SizeZaranger!   )r1   rS   r4   r   rY   r   forward_parameters   s    ,,( z"PatchSequential.forward_parametersc                 c   s@  | j s| jrd}t|d D ]z}| j|d\}}|}|D ]\}t|d ttttfrt	|d |d 
t|dd |fV  q8t	|d d|fV  q8qn| j s | js t|  D ]b\}}t|d ttttfrt	|d |d 
t|dd |fV  qt	|d d|fV  qn| jsttt|  |d D ]d\}}t|d ttttfrt	|d |d 
t|dd |fV  nt	|d d|fV  qBnd}t|d D ]}| j|d\}}|}|D ]`}t|d ttttfr t	|d |d 
t|dd |fV  nt	|d d|fV  q֐qdS )zGet multiple forward sequence but maximumly one mix augmentation in between.

        Args:
            batch_shape: 5-dim shape arranged as :math:``(N, B, C, H, W)``, in which N represents
                the number of sequence.
        Fr   )with_mixr(   N)r!   r$   rangeZget_random_forward_sequencer-   r   r
   r   r   r   r_   rB   r^   	enumerateZnamed_childrenr   r   )r1   rS   r`   rK   seqZ	mix_addedsZnchildr   r   r   r]   
  sF    .."..z#PatchSequential.generate_parameters)r8   labelr4   r'   c                 C   s|  |j }||j }|d ur$||j }n|}| |jj}| j||||ji d\}}	t|ttt	t
frtt|jj|j}
nt|jjd }
t|tfrt|tfr|d |d |j< |d |d |j< nt|tfrt|tfs|d ||j< ||d f}nRt|tfs t|tfr ||d |j< n&t|tfsFt|tfsF|||j< d }|d ur|	d urt|	j dkrtj|d |d  |	j|	jdd }|}n@tj|d g|	j dd  R |	j|	jdd }||d d df< |	||j< n|d u rh|	d urht|	j dkr.tj|d |d  |	j|	jdd }n0tj|d g|	j dd  R |	j|	jdd }|	||j< ||t|j|
dfS )N)
extra_argsr   r(   )devicedtyper:   )r   )rO   r   Zget_submoduler   r5   Zapply_to_inputr-   r   r
   r   r   r   _paramsr.   r+   rB   Zonesrg   rh   r   )r1   r8   re   r4   in_shape_inputZ_labelmoduleoutputZ	out_labelrZ   r   r   r   apply_by_param=  sH    

$.&.
zPatchSequential.apply_by_paramc                 C   s   |j }|jdg|dd  R  }|d ur@tj|g|d  dd}|   |D ]$}| j|||d\}}}| | qL||}||fS )Nr:   rH   r(   r   rI   )r4   )rO   ZreshaperB   rP   Zclear_statern   Zupdate_params)r1   r8   re   r4   rj   rk   Zpatch_paramrZ   r   r   r   forward_by_paramsu  s    
z!PatchSequential.forward_by_params)r8   r4   r'   c                 C   s   |   r|S tddS )zInverse transformation.

        Used to inverse a tensor according to the performed transformation by a forward pass, or with respect to
        provided parameters.
        zFPatchSequential inverse cannot be used with geometric transformations.N)Zis_intensity_onlyr=   )r1   r8   r4   r   r   r   inverse  s    zPatchSequential.inversec                 C   s   t |tfrtd| || j}| || j|}|du rF| |j}| 	|||\}}| j
|| j|d}|dupz| || _| ||S )z:Input transformation will be returned if input is a tuple.z'tuple input is not currently supported.N)rA   )r-   r.   r,   r@   r    rF   r   r_   rO   ro   rR   r7   Zreturn_labelZ__packup_output__)r1   r8   re   r4   rA   rk   r   r   r   forward  s    zPatchSequential.forward)N)NN)r   N)NN) r   r   r   __doc__rC   Moduler   r   strr   boolr	   r   floatr0   r   r7   rB   ZTensorr@   rF   rR   r^   r_   r   r   r]   rn   ro   rp   rq   __classcell__r   r   r2   r   r      sn   ]

)   1  
49 )	itertoolsr   r   typingr   r   r   r   r   r	   rB   Ztorch.nnrC   Zkornia.augmentationr
   Z kornia.augmentation._2d.mix.baser   Zkornia.augmentation.baser   Z"kornia.augmentation.container.baser   Z#kornia.augmentation.container.imager   r   Zkornia.contrib.extract_patchesr   __all__r   r   r   r   r   r   <module>   s    