o
    oiJ                     @   s   d dl mZmZ d dlmZ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mZ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  d
dl!m"Z" d
dl#m$Z$m%Z% dgZ&G dd de Z'dS )    )cycleislice)AnyDictIteratorListOptionalTupleUnionN)_AugmentationBase)extract_tensor_patches)ModuleTensorconcatenatepad)Boxes)	Keypoints   )SequentialBase)ImageSequential)InputSequentialOps)	ParamItemPatchParamItemPatchSequentialc                       s>  e Zd ZdZddddddddded	eeef d
edee	 dee	 de	de
ee	eeef f deee  ddf fddZ	d9ded
ed	eeeef  deeeeef fddZ		d:ded	eeeef  deeeeeef  defddZ	d;ded	eeef deeeeeef  defddZdejdee fddZdejdeeeef  fdd Zded!ee defd"d#Z	d9ded!ee d$eeeef  defd%d&Z	d9ded!ee d$eeeef  defd'd(Z	d9ded!ee d$eeeef  defd)d*Z	d9ded!ee d$eeeef  defd+d,Z	d9de d!ee d$eeeef  de fd-d.Z!	d9de d!ee d$eeeef  de fd/d0Z"	d9de#d!ee d$eeeef  de#fd1d2Z$	d9de#d!ee d$eeeef  de#fd3d4Z%	d:ded!eee  d$eeeef  defd5d6Z&d9ded!eee  defd7d8Z'  Z(S )<r   ao  Container for performing patch-level image data augmentation.

    .. image:: _static/img/PatchSequential.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.github.io/tutorials/nbs/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}	n;|r1|du r1t ||d |d  kr.tdt | d|d |d   d|}	n|rBt|ttfrBtd	| d
|}	t j||||	|d |dvr\td| d
|| _|| _|| _	|  d S )NT)r   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
isinstanceinttuplesuper__init__r   r   r"   )
selfr   r   r    r!   r"   r#   r$   r%   _random_apply	__class__ W/home/ubuntu/.local/lib/python3.10/site-packages/kornia/augmentation/container/patch.pyr/      s8   zPatchSequential.__init__inputc                 C   s   |d u r| j }|dkr2|d|d  |d|d  }}| d |d | | d |d | fS |dkrl|d|d|d  |d   }|d|d|d  |d   }|d ||d  |d ||d  fS td| d	)
Nr(   r   r      r   z2Expect `padding` as either 'valid' or 'same'. Got r'   )r   sizeNotImplementedError)r0   r6   r   r   phpwr4   r4   r5   compute_padding   s   &($$$zPatchSequential.compute_paddingr   c                 C   sX   |durt |t|}|du r| j}|d|d  |d|d  f}|}t|||S )ag  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]]]]])

        Nr7   r8   )fpadlistr   r:   r   )r0   r6   r   r   window_sizestrider4   r4   r5   extract_patches   s   '$zPatchSequential.extract_patchespatchesc                 C   s   |du r| j }|jd|d |d g|jdd R  }tt||d ddd}tt||d ddd}|durGt|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]]]])

        Nr8   r   r   r7   c                 S   s   g | ]}| qS r4   r4   ).0ir4   r4   r5   
<listcomp>   s    z8PatchSequential.restore_from_patches.<locals>.<listcomp>)r   viewshaper   torchchunksqueezer?   )r0   rD   r   r   patches_tensorrestored_tensorr4   r4   r5   restore_from_patches   s   (z$PatchSequential.restore_from_patchesbatch_shapec                    s  g }| j s2| td|d |d  g|dd  }td|d |d    fdd|D }|S | jsT| t|d |d  dg|dd  }dd |D }|S | t|d |d g|dd  }tjd|d |d  |d d  fdd|D }|S )	Nr   r   r9   c                    s   g | ]\}}t   |qS r4   r   tolist)rF   p_indicesr4   r5   rH     s    z6PatchSequential.forward_parameters.<locals>.<listcomp>c                 S   s   g | ]
\}}t |g|qS r4   )r   rF   rT   rG   r4   r4   r5   rH     s    )stepc                    s"   g | ]\}}t  |  |qS r4   rR   rX   rV   r4   r5   rH     s   " )r"   generate_parametersrK   Sizearanger    )r0   rQ   	out_paramparamsr4   rV   r5   forward_parameters  s   ,,( z"PatchSequential.forward_parametersc                 c   s4   | j sO| jrOd}t|d D ]=}| j|d\}}|}|D ].}t|d tttjfrAt	|d |d 
t|dd |fV  qt	|d d|fV  qqdS | j s| jst|  D ]0\}}t|d tttjfrt	|d |d 
t|dd |fV  q[t	|d d|fV  q[dS | jsttt|  |d D ]0\}}t|d tttjfrt	|d |d 
t|dd |fV  qt	|d d|fV  qdS d}t|d D ]>}| j|d\}}|}|D ]/}t|d tttjfrt	|d |d 
t|dd |fV  qt	|d d|fV  qqd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#   rangeget_random_forward_sequencer+   r   r   KMixAugmentationBaseV2r   r_   rK   r[   	enumeratenamed_childrenr   r   )r0   rQ   r`   rG   seq	mix_addedsnchildr4   r4   r5   rZ     sD   .."..z#PatchSequential.generate_parametersr^   c                 C   sj   |j }|jdg|dd  R  }|D ]}| |jj}||j }tj|||ji d}|||j< q||S )Nr8   rE   )
extra_args)rJ   reshapeget_submoduleparamnamerW   r   	transform)r0   r6   r^   in_shapepatch_parammodule_inputoutputr4   r4   r5   forward_by_paramsA  s   

z!PatchSequential.forward_by_paramsrk   c                 C   s@   |  || j}| || j|}| ||}| j|| j|d}|S )Nr   )r>   r   rC   r   rv   rP   )r0   r6   r^   rk   r   r4   r4   r5   transform_inputsN  s
   z PatchSequential.transform_inputsc                 C      |   r|S tdNFPatchSequential inverse cannot be used with geometric transformations.is_intensity_onlyr;   r0   r6   r^   rk   r4   r4   r5   inverse_inputsX     zPatchSequential.inverse_inputsc                 C   rx   NzHPatchSequential for boxes cannot be used with geometric transformations.r{   r}   r4   r4   r5   transform_masks`  r   zPatchSequential.transform_masksc                 C   rx   ry   r{   r}   r4   r4   r5   inverse_masksh  r   zPatchSequential.inverse_masksc                 C   rx   r   r{   r}   r4   r4   r5   transform_boxesp  r   zPatchSequential.transform_boxesc                 C   rx   ry   r{   r}   r4   r4   r5   inverse_boxesx  r   zPatchSequential.inverse_boxesc                 C   rx   )NzLPatchSequential for keypoints cannot be used with geometric transformations.r{   r}   r4   r4   r5   transform_keypoints  r   z#PatchSequential.transform_keypointsc                 C   rx   ry   r{   r}   r4   r4   r5   inverse_keypoints  r   z!PatchSequential.inverse_keypointsc                 C   rx   )zInverse transformation.

        Used to inverse a tensor according to the performed transformation by a forward pass, or with respect to
        provided parameters.
        rz   r{   r}   r4   r4   r5   inverse  s   zPatchSequential.inversec                 C   s@   t |tfr
td|du r| |j}| j||d}|| _|S )z:Input transformation will be returned if input is a tuple.z'tuple input is not currently supported.N)r^   )r+   r-   r*   r_   rJ   rw   _params)r0   r6   r^   ru   r4   r4   r5   forward  s   zPatchSequential.forward)N)NN)r   N))__name__
__module____qualname____doc__r   r	   r,   strr   boolr
   r   floatr/   r   r>   rC   rP   rK   r[   r   r_   r   r   rZ   rv   r   r   rw   r~   r   r   r   r   r   r   r   r   r   r   __classcell__r4   r4   r2   r5   r   '   s2   ]

	
+

0

 ,

	
	
	
	
	
	
	

()(	itertoolsr   r   typingr   r   r   r   r   r	   r
   rK   kornia.augmentationaugmentationrc   kornia.augmentation.baser   kornia.contrib.extract_patchesr   kornia.corer   r   r   r   r?   kornia.geometry.boxesr   kornia.geometry.keypointsr   baser   imager   opsr   r^   r   r   __all__r   r4   r4   r4   r5   <module>   s    $