o
    oi}u                     @   s`  d dl Z d dlmZ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mZ d dlmZ d dlmZmZ d dlmZmZ d dlmZmZ d d	lmZ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' ddl(m)Z) ddl*m+Z+ ddl,m-Z- dgZ.ej/ej0ej1hZ2ej3hZ4ej5ej6hZ7ej8hZ9ej:ej;hZ<eeee f Z=G dd de"e$Z>dS )    N)AnyDictListOptionalSequenceTupleUnioncast)RigidAffineAugmentationBase2D)AugmentationBase3DRigidAffineAugmentationBase3D)_AugmentationBase)DataKeyResample)ModuleTensor)Boxes
VideoBoxes)	KeypointsVideoKeypoints)eye_likeis_autocast_enabled   )TransformMatrixMinIn)ImageSequential)AugmentationSequentialOpsDataType)	ParamItem)PatchSequential)VideoSequentialAugmentationSequentialc                       sf  e Zd ZdZdZdZejfddddddddee	e
f deeee ee ee f  dee d	ee d
eeeeeef f deee  dedeeeeeef f  ddf fddZdF fddZdeddfddZdedefddZddddeeeeef f deee  deeee ee ee f  deeee eeef f fddZdedee ddfddZdedee dee fdd Zd!ee d"ee dee dee fd#d$Z ddddeeeeef f deee  deeee ee ee f  deeee eeef f fd%d&Z!dd'd(d)ed*eee  d+ed,edef
 fd-d.Z"d/eeef deeed0f ee eed0f eeeef  f fd1d2Z#d3ee deee eee  f fd4d5Z$d6e%de%fd7d8Z&d6e%de%fd9d:Z'd6ed;ede(fd<d=Z)d>ed?e(d;edeeee e(f fd@dAZ*d6ed;ede+fdBdCZ,d>ed?e+d;edeeee e+f fdDdEZ-  Z.S )Gr    a.!  AugmentationSequential for handling multiple input types like inputs, masks, keypoints at once.

    .. image:: _static/img/AugmentationSequential.png

    Args:
        *args: a list of kornia augmentation modules.

        data_keys: the input type sequential for applying augmentations. Accepts "input", "image", "mask",
                   "bbox", "bbox_xyxy", "bbox_xywh", "keypoints", "class", "label".

        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.

        random_apply: randomly select a sublist (order agnostic) of args to apply transformation.
                      If int, a fixed number of transformations will be selected.
                      If (a,), x number of transformations (a <= x <= len(args)) will be selected.
                      If (a, b), x number of transformations (a <= x <= b) will be selected.
                      If True, the whole list of args will be processed as a sequence in a random order.
                      If False, the whole list of args will be processed as a sequence in original order.

        transformation_matrix_mode: computation mode for the chained transformation matrix, via `.transform_matrix`
                                    attribute.
                                    If `silent`, transformation matrix will be computed silently and the non-rigid
                                    modules will be ignored as identity transformations.
                                    If `rigid`, transformation matrix will be computed silently and the non-rigid
                                    modules will trigger errors.
                                    If `skip`, transformation matrix will be totally ignored.

        extra_args: to control the behaviour for each datakeys. By default, masks are handled by nearest interpolation
                    strategies.

    .. note::
        Mix augmentations (e.g. RandomMixUp, RandomCutMix) can only be working with "input"/"image" data key.
        It is not clear how to deal with the conversions of masks, bounding boxes and keypoints.

    .. note::
        See a working example `here <https://kornia.github.io/tutorials/nbs/data_augmentation_sequential.html>`__.

    Examples:
        >>> import kornia
        >>> input = torch.randn(2, 3, 5, 6)
        >>> mask = torch.ones(2, 3, 5, 6)
        >>> bbox = torch.tensor([[
        ...     [1., 1.],
        ...     [2., 1.],
        ...     [2., 2.],
        ...     [1., 2.],
        ... ]]).expand(2, 1, -1, -1)
        >>> points = torch.tensor([[[1., 1.]]]).expand(2, -1, -1)
        >>> aug_list = AugmentationSequential(
        ...     kornia.augmentation.ColorJiggle(0.1, 0.1, 0.1, 0.1, p=1.0),
        ...     kornia.augmentation.RandomAffine(360, p=1.0),
        ...     data_keys=["input", "mask", "bbox", "keypoints"],
        ...     same_on_batch=False,
        ...     random_apply=10,
        ... )
        >>> out = aug_list(input, mask, bbox, points)
        >>> [o.shape for o in out]
        [torch.Size([2, 3, 5, 6]), torch.Size([2, 3, 5, 6]), torch.Size([2, 1, 4, 2]), torch.Size([2, 1, 2])]
        >>> # apply the exact augmentation again.
        >>> out_rep = aug_list(input, mask, bbox, points, params=aug_list._params)
        >>> [(o == o_rep).all() for o, o_rep in zip(out, out_rep)]
        [tensor(True), tensor(True), tensor(True), tensor(True)]
        >>> # inverse the augmentations
        >>> out_inv = aug_list.inverse(*out)
        >>> [o.shape for o in out_inv]
        [torch.Size([2, 3, 5, 6]), torch.Size([2, 3, 5, 6]), torch.Size([2, 1, 4, 2]), torch.Size([2, 1, 2])]

    This example demonstrates the integration of VideoSequential and AugmentationSequential.

        >>> import kornia
        >>> input = torch.randn(2, 3, 5, 6)[None]
        >>> mask = torch.ones(2, 3, 5, 6)[None]
        >>> bbox = torch.tensor([[
        ...     [1., 1.],
        ...     [2., 1.],
        ...     [2., 2.],
        ...     [1., 2.],
        ... ]]).expand(2, 1, -1, -1)[None]
        >>> points = torch.tensor([[[1., 1.]]]).expand(2, -1, -1)[None]
        >>> aug_list = AugmentationSequential(
        ...     VideoSequential(
        ...         kornia.augmentation.ColorJiggle(0.1, 0.1, 0.1, 0.1, p=1.0),
        ...         kornia.augmentation.RandomAffine(360, p=1.0),
        ...     ),
        ...     data_keys=["input", "mask", "bbox", "keypoints"]
        ... )
        >>> out = aug_list(input, mask, bbox, points)
        >>> [o.shape for o in out]  # doctest: +ELLIPSIS
        [torch.Size([1, 2, 3, 5, 6]), torch.Size([1, 2, 3, 5, 6]), ...([1, 2, 1, 4, 2]), torch.Size([1, 2, 1, 2])]

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

        >>> import kornia
        >>> input = torch.randn(2, 3, 5, 6)[None]
        >>> mask = torch.ones(2, 3, 5, 6)[None]
        >>> bbox = torch.tensor([[
        ...     [1., 1.],
        ...     [2., 1.],
        ...     [2., 2.],
        ...     [1., 2.],
        ... ]]).expand(2, 1, -1, -1)[None]
        >>> points = torch.tensor([[[1., 1.]]]).expand(2, -1, -1)[None]
        >>> aug_list = AugmentationSequential(
        ...     VideoSequential(
        ...         kornia.augmentation.RandomAffine(360, p=1.0),
        ...     ),
        ...     VideoSequential(
        ...         kornia.augmentation.ColorJiggle(0.1, 0.1, 0.1, 0.1, p=1.0),
        ...     ),
        ...     data_keys=["input", "mask", "bbox", "keypoints"],
        ...     random_apply=1,
        ...     random_apply_weights=[0.5, 0.3]
        ... )
        >>> out = aug_list(input, mask, bbox, points)
        >>> [o.shape for o in out]  # doctest: +ELLIPSIS
        [torch.Size([1, 2, 3, 5, 6]), torch.Size([1, 2, 3, 5, 6]), ...([1, 2, 1, 4, 2]), torch.Size([1, 2, 1, 2])]

    This example shows how to use a list of masks and boxes within AugmentationSequential

        >>> import kornia.augmentation as K
        >>> input = torch.randn(2, 3, 256, 256)
        >>> mask = [torch.ones(1, 3, 256, 256), torch.ones(1, 2, 256, 256)]
        >>> bbox = [
        ...    torch.tensor([[28.0, 53.0, 143.0, 164.0], [254.0, 158.0, 364.0, 290.0], [307.0, 204.0, 413.0, 350.0]]),
        ...    torch.tensor([[254.0, 158.0, 364.0, 290.0], [307.0, 204.0, 413.0, 350.0]])
        ... ]
        >>> bbox = [Boxes.from_tensor(i).data for i in bbox]

        >>> aug_list = K.AugmentationSequential(
        ...    K.ColorJiggle(0.1, 0.1, 0.1, 0.1, p=1.0),
        ...    K.RandomHorizontalFlip(p=1.0),
        ...    K.ImageSequential(K.RandomHorizontalFlip(p=1.0)),
        ...    K.ImageSequential(K.ColorJiggle(0.1, 0.1, 0.1, 0.1, p=1.0)),
        ...    data_keys=["input", "mask", "bbox"],
        ...    same_on_batch=False,
        ...    random_apply=10,
        ... )
        >>> out = aug_list(input, mask, bbox)

    How to use a dictionary as input with AugmentationSequential? The dictionary keys that start with
    one of the available datakeys will be augmented accordingly. Otherwise, the dictionary item is passed
    without any augmentation.

        >>> import kornia.augmentation as K
        >>> img = torch.randn(1, 3, 256, 256)
        >>> mask = [torch.ones(1, 3, 256, 256), torch.ones(1, 2, 256, 256)]
        >>> bbox = [
        ...    torch.tensor([[28.0, 53.0, 143.0, 164.0], [254.0, 158.0, 364.0, 290.0], [307.0, 204.0, 413.0, 350.0]]),
        ...    torch.tensor([[254.0, 158.0, 364.0, 290.0], [307.0, 204.0, 413.0, 350.0]])
        ... ]
        >>> bbox = [Boxes.from_tensor(i).data for i in bbox]
        >>> aug_dict = K.AugmentationSequential(
        ...    K.ColorJiggle(0.1, 0.1, 0.1, 0.1, p=1.0),
        ...    K.RandomHorizontalFlip(p=1.0),
        ...    K.ImageSequential(K.RandomHorizontalFlip(p=1.0)),
        ...    K.ImageSequential(K.ColorJiggle(0.1, 0.1, 0.1, 0.1, p=1.0)),
        ...    data_keys=None,
        ...    same_on_batch=False,
        ...    random_apply=10,
        ... )
        >>> data = {'image': img, 'mask': mask[0], 'mask-b': mask[1], 'bbox': bbox[0], 'bbox-other':bbox[1]}
        >>> out = aug_dict(data)
        >>> out.keys()
        dict_keys(['image', 'mask', 'mask-b', 'bbox', 'bbox-other'])

    NFsilent)	data_keyssame_on_batchkeepdimrandom_applyrandom_apply_weightstransformation_matrix_mode
extra_argsargsr"   r#   r$   r%   r&   r'   r(   returnc          
         s4  |  g | _ t j|||||d | | tttf| _|  |d ur+dd |D | _n|| _| jrXt	dd | jD rGt
dt d| j d| jd	 tjkrXtd
tj dt| j| _d| _d| _|D ]"}	t|	trx|	 sxtjddd t|	trd| _t|	trd| _qfd | _|ptjtjd di| _d S )N)r#   r$   r%   r&   c                 S   s   g | ]}t |qS  )r   get).0inpr+   r+   Y/home/ubuntu/.local/lib/python3.10/site-packages/kornia/augmentation/container/augment.py
<listcomp>      z3AugmentationSequential.__init__.<locals>.<listcomp>c                 s   s    | ]}|t vV  qd S N)r   )r-   in_typer+   r+   r/   	<genexpr>  s    z2AugmentationSequential.__init__.<locals>.<genexpr>z`data_keys` must be in z. Got .r   zThe first input must be FzSGeometric transformation detected in PatchSeqeuntial, which would break bbox, mask.r   )
stacklevelT)resamplealign_corners)_transform_matricessuper__init__!_parse_transformation_matrix_moder
   r   r    $_valid_ops_for_transform_computationr"   anyAssertionErrorr   INPUTNotImplementedErrorr   transform_opcontains_video_sequentialcontains_3d_augmentation
isinstancer   is_intensity_onlywarningswarnr   r   _transform_matrixMASKr   NEARESTr(   )
selfr"   r#   r$   r%   r&   r'   r(   r)   arg	__class__r+   r/   r;      sL   


zAugmentationSequential.__init__c                    s   |    t  S r2   )_reset_transform_matrix_stater:   clear_state)rL   rN   r+   r/   rQ     s   
z"AugmentationSequential.clear_statemodulec                 C   s   | j |j d S r2   )r9   appendtransform_matrix)rL   rR   r+   r+   r/   %_update_transform_matrix_for_valid_op"  s   z<AugmentationSequential._update_transform_matrix_for_valid_opinputc                 C   s   | j rtd|S td|S )zReturn identity matrix.      )rD   r   )rL   rV   r+   r+   r/   identity_matrix%  s   

z&AugmentationSequential.identity_matrix)paramsr"   rZ   c                G   sB  d}t |dkrt|d tr| |d \}}}}| j|| j_| j|d| jji | j|d| jji}|du rF| j	du rCt
d| j	}|}|ddd D ]}| |j}	| jj||	|| jd}t|ttfsm|g}qO| j||| jjd}t|trd	d
 t||D }
|r|
| |
S t |dkrt|tr|d S |S )zReverse the transformation applied.

        Number of input tensors must align with the number of``data_keys``. If ``data_keys`` is not set, use
        ``self.data_keys`` by default.
        Nr   r   r"   zrNo parameters available for inversing, please run a forward pass first or passing valid params into this function.rR   paramr(   r"   c                 S      i | ]\}}||qS r+   r+   r-   vkr+   r+   r/   
<dictcomp>Z  r1   z2AugmentationSequential.inverse.<locals>.<dictcomp>)lenrE   dict_preproc_dict_datarB   preproc_datakeysr"   _validate_args_datakeys_arguments_preproc_params
ValueErrorget_submodulenameinverser(   listtuple_arguments_postproczipupdate)rL   rZ   r"   r)   original_keysinvalid_datain_argsoutputsr]   rR   resultr+   r+   r/   rn   ,  s<   



zAugmentationSequential.inversec                G   s2   t |t |krtdt | dt | dd S )NzBThe number of inputs must align with the number of data_keys. Got z and r5   )rd   r?   )rL   r"   r)   r+   r+   r/   rh   d  s
   z.AugmentationSequential._validate_args_datakeysc                G   s  g }t ||D ]|\}}t|tv r!tt|}|j| _|| qt|t	v rMt
|tr;ttt |}|d j| _n	tt|}|j| _|| | qt|tv r^|| || qt|tv ro|| || qt|tv r||| qtd| d|S )Nr   input type of  is not implemented.)rr   r   r,   _IMG_OPTIONSr	   r   dtypeinput_dtyperS   _MSK_OPTIONSrE   ro   r   
mask_dtype_preproc_mask_KEYPOINTS_OPTIONS_preproc_keypoints_BOXES_OPTIONS_preproc_boxes_CLS_OPTIONSrA   )rL   r"   r)   r.   rM   dcater+   r+   r/   ri   k  s*   


z)AugmentationSequential._arguments_preprocrv   out_argsc           
         sd  g }t |||D ]\ }}t|tv r|| qt|tv r/| tt|}|| qt|t	v re| 
 tt||}t r_t ttfr_t|trY fdd|D }n| j}|| qt|tv r|  tt||}	t rt ttfrt|	tr fdd|	D }	n|	 j}	||	 qt|tv r|| qtd| d|S )Nc                       g | ]}|  jqS r+   typer|   r-   iin_argr+   r/   r0         z>AugmentationSequential._arguments_postproc.<locals>.<listcomp>c                    r   r+   r   r   r   r+   r/   r0     r   ry   rz   )rr   r   r,   r{   rS   r~   _postproc_maskr	   MaskDataTyper   _postproc_keypointr   r   rE   r   ro   r   r|   r   _postproc_boxesr   r   rA   )
rL   rv   r   r"   outout_argr   _out_m_out_k_out_br+   r   r/   rq     s2   

z*AugmentationSequential._arguments_postprocc                G   s  |    d}t|dkrt|d tr| |d \}}}}| j|| j_| j|d| jji | j	|d| jji}|du rt
j| jjv r~|| jjt
j }t|tfs_tdt| d| jse| jro| j|dd\}}	n	| j|d	d\}}	| |	}ntd
|}
|D ]#}| |j}| jj|
||| jd}
t|
ttfs|
g}
| | q| j||
| jjd}
| j| j_|| _t|trdd t|
|D }|r|| |S t|
dkrt|
tr|
d S |
S )zHCompute multiple tensors simultaneously according to ``self.data_keys``.Nr   r   r"   z `INPUT` should be a tensor but `z` received.)rX      )	dim_range)   rW   z;`params` must be provided whilst INPUT is not in data_keys.r\   r^   c                 S   r_   r+   r+   r`   r+   r+   r/   rc     r1   z2AugmentationSequential.forward.<locals>.<dictcomp>)rQ   rd   rE   re   rf   rB   rg   r"   rh   ri   r   r@   indexr   rk   r   rC   rD   autofill_dimforward_parametersrl   rm   	transformr(   ro   rp   "_update_transform_matrix_by_modulerq   rj   rr   rs   )rL   rZ   r"   r)   rt   ru   rv   r.   _	out_shaperw   r]   rR   rx   r+   r+   r/   forward  sJ   



zAugmentationSequential.forwardtensorinput_names_to_handleoutput_typeinputsr   r   kwargsc                   s:  | j s| j||dtt| j}||i |}t|dkr0t|d tr0| |d \}}}}	n|	d| j
}| j|}
t|
dkrtj|
v r|
tj}|dkrp|| _t|trg|||  | j|| < |S || | j|< |S t|tr|||  | j|| < |S || | j|< |S || _|S tt| j|i |}|S )a  Overwrite the __call__ function to handle various inputs.

        Args:
            inputs: Inputs to operate on.
            input_names_to_handle: List of input names to convert, if None, handle all inputs.
            output_type: Desired output type ('tensor', 'numpy', or 'pil').
            kwargs: Additional arguments.

        Returns:
            Callable: Decorated function with converted input and output types.

        r   r   r   r"   r   )_disable_featuresconvert_input_outputr:   r   __call__rd   rE   re   rf   r,   r"   rB   rg   r   r@   r   _output_image)rL   r   r   r   r   decorated_forwardr   rt   in_data_keys_invalid_datar"   idxrN   r+   r/   r     s:   

	
zAugmentationSequential.__call__data.c                    s|   | j d ur	tdt  }| |\}r! fddD nd }r0tfdd|D n|}t  }||||fS )NzEIf you are using a dictionary as input, the data_keys should be None.c                    s   i | ]}|  |qS r+   )popr   )r   r+   r/   rc   (  r   z=AugmentationSequential._preproc_dict_data.<locals>.<dictcomp>c                 3   s    | ]	}| vr|V  qd S r2   r+   )r-   rb   )invalid_keysr+   r/   r4   )  s    z<AugmentationSequential._preproc_dict_data.<locals>.<genexpr>)r"   rk   rp   keys_read_datakeys_from_dictvalues)rL   r   r   r"   ru   data_unpackedr+   )r   r   r/   rf      s   
z)AugmentationSequential._preproc_dict_datar   c              	   C   s`   dt dtfdd}g }g }|D ]}z|t|| W q ty+   || Y qw ||fS )Nkeyr*   c                 S   s   |   dr
tjS tD ]!}|   dv rt|     S |   |jr-t|j  S qddd tD }td| d|  d)	z;Try to retrieve the datakey value by matching `<datakey>*`.r@   >   	BBOX_XYWH	BBOX_XYXYz | c                 s   s    | ]
}d |j  d V  qdS )`N)rm   )r-   dr+   r+   r/   r4   ;  s    zXAugmentationSequential._read_datakeys_from_dict.<locals>.retrieve_key.<locals>.<genexpr>zJYour input data dictionary keys should start with some of datakey values: z. Got `r   )upper
startswithr   r@   r,   rm   joinrk   )r   dk
allowed_dkr+   r+   r/   retrieve_key/  s   zEAugmentationSequential._read_datakeys_from_dict.<locals>.retrieve_key)strr   rS   r,   rk   )rL   r   r   valid_data_keysr   rb   r+   r+   r/   r   .  s   z/AugmentationSequential._read_datakeys_from_dictrM   c                 C   f   t |tr"g }|D ]}| jr|| jn|tj}|| q	|S | jr+|| jn|tj}|S r2   )rE   ro   r}   totorchfloatrS   rL   rM   new_argaa_newr+   r+   r/   r   J     
z$AugmentationSequential._preproc_maskc                 C   r   r2   )rE   ro   r   r   r   r   rS   r   r+   r+   r/   r   V  r   z%AugmentationSequential._postproc_maskr   c                 C   s   t |t jfv rd}n$t |t jfv rd}nt |t jfv r$d}ntdt |j dt|tfr8|S | j	rEt
t|}t|S | jrLtdt
t|}tj||dS )Nvertices_plus	xyxy_plusxywhUnsupported mode ``.z&3D box handlers are not yet supported.mode)r   r,   BBOXr   r   rk   rm   rE   r   rC   r	   r   r   from_tensorrD   rA   )rL   rM   r   r   r+   r+   r/   r   b  s    


z%AugmentationSequential._preproc_boxesr   r   c                 C   s|   t |t jfv rd}n$t |t jfv rd}nt |t jfv r$d}ntdt |j dt|tfr8|S |j	|dS )Nr   r   r   r   r   r   )
r   r,   r   r   r   rk   rm   rE   r   	to_tensor)rL   r   r   r   r   r+   r+   r/   r   v  s   z&AugmentationSequential._postproc_boxesc                 C   s   d }| j rCttttt f |}t|tr)t|d s(|d j	}dd |D }nt|s5|j	}|
 }t|}|rA||S |S | jrJtdt|tfrR|S tt|}t|sc|j	}|
 }t|}|ro||S |S )Nr   c                 S   s   g | ]}|  qS r+   )r   )r-   r   r+   r+   r/   r0     s    z=AugmentationSequential._preproc_keypoints.<locals>.<listcomp>z+3D keypoint handlers are not yet supported.)rC   r	   r   r   r   rE   ro   r   is_floating_pointr|   r   r   r   r   rD   rA   r   )rL   rM   r   r|   video_resultrx   r+   r+   r/   r     s.   






z)AugmentationSequential._preproc_keypointsc                 C   s   t |tfr|S | S r2   )rE   r   r   )rL   r   r   r   r+   r+   r/   r     s   z)AugmentationSequential._postproc_keypoint)r*   N)/__name__
__module____qualname____doc__r}   r   r   r@   r   r   r   r   r   r   intboolr   r   r   r   r   r;   rQ   r   rU   r   rY   r   r   rn   rh   ri   rq   r   r   rf   r   r   r   r   r   r   r   r   r   r   __classcell__r+   r+   rN   r/   r    2   s     -

	
<


8
*

B
6
.
*()?rG   typingr   r   r   r   r   r   r   r	   r   kornia.augmentation._2d.baser
   kornia.augmentation._3d.baser   r   kornia.augmentation.baser   kornia.constantsr   r   kornia.corer   r   kornia.geometry.boxesr   r   kornia.geometry.keypointsr   r   kornia.utilsr   r   baser   imager   opsr   r   rZ   r   patchr   videor   __all__r   r   r   r   	KEYPOINTSr   r@   IMAGEr{   rJ   r~   CLASSLABELr   r   r    r+   r+   r+   r/   <module>   s2   (