U
    PhsF                     @  s  d dl mZ d dlmZ d dlmZ d dlZd dlZd dl	m
Z
mZ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mZ d dlmZmZ d<dddddddZddddddZddddddZdddddddZ d=ddddd d!d"Z!d>dddd%ddd&d'd(Z"d#ej#ej$fdd%d)d)d*d+d,d-Z%d.dd/d0d1d2Z&dd%d%dd3d4d5Z'd?ddd%d8dd9d:d;Z(dS )@    )annotations)Sequence)deepcopyN)	DtypeLikeNdarrayOrTensorNdarrayTensor)COMPUTE_DTYPE	TO_REMOVEget_spatial_dims)Resize)create_scale)look_up_option)ensure_tupleensure_tuple_rep)convert_data_typeconvert_to_dst_typeTztorch.Tensorbool)pointsaffineinclude_shiftreturnc                 C  s   t | d}|rjtj| tj| jd d| j| jdgdddd}t||}|d|ddf dd}n4| dd}t|d|d|f |}|dd}|S )a  
    This internal function applies affine matrices to the point coordinate

    Args:
        points: point coordinates, Nx2 or Nx3 torch tensor or ndarray, representing [x, y] or [x, y, z]
        affine: affine matrix to be applied to the point coordinates, sized (spatial_dims+1,spatial_dims+1)
        include_shift: default True, whether the function apply translation (shift) in the affine transform

    Returns:
        transformed point coordinates, with same data type as ``points``, does not share memory with ``points``
    )r   r      )devicedtypedimN)	r
   torchcatonesshaper   r   	transposematmul)r   r   r   spatial_dimsZpoints_affine r#   \/home/dell461/cl/sdc2/HISourceFinder-master-l/src/monai/apps/detection/transforms/box_ops.py_apply_affine_to_points   s    
  r%   r   r   )boxesr   r   c                 C  s   t | tj^}}|jtd}t||d^}}t|d}t|ddd|f |dd}t|dd|df |dd}tjtj	||gdddd\}}tj
tj	||gdddd\}	}tj||	gd	d}
t|
| d^}}|S )
a  
    This function applies affine matrices to the boxes

    Args:
        boxes: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be StandardMode
        affine: affine matrix to be applied to the box coordinates, sized (spatial_dims+1,spatial_dims+1)

    Returns:
        returned affine transformed boxes, with same data type as ``boxes``, does not share memory with ``boxes``
    r   srcdstr&   NT)r      r   r   )r   r   Tensortor   r   r
   r%   minstackmaxr   )r&   r   boxes_t_Zaffine_tr"   ltrbZlt_newZrb_newZboxes_t_affineZboxes_affiner#   r#   r$   apply_affine_to_boxes>   s    
  r6   zSequence[float] | float)r&   zoomr   c                 C  s"   t | d}t||d}t| |dS )al  
    Zoom boxes

    Args:
        boxes: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be StandardMode
        zoom: The zoom factor along the spatial axes.
            If a float, zoom is the same for each spatial axis.
            If a sequence, zoom should contain one value for each spatial axis.

    Returns:
        zoomed boxes, with same data type as ``boxes``, does not share memory with ``boxes``

    Example:
        .. code-block:: python

            boxes = torch.ones(1,4)
            zoom_boxes(boxes, zoom=[0.5,2.2]) #  will return tensor([[0.5, 2.2, 0.5, 2.2]])
    r+   )r"   scaling_factor)r&   r   )r
   r   r6   )r&   r7   r"   r   r#   r#   r$   
zoom_boxesf   s    
r9   zSequence[int] | int)r&   src_spatial_sizedst_spatial_sizer   c                   sB   t | d}t|t |  fddt|D }t| |dS )a  
    Resize boxes when the corresponding image is resized

    Args:
        boxes: source bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode``
        src_spatial_size: source image spatial size.
        dst_spatial_size: target image spatial size.

    Returns:
        resized boxes, with same data type as ``boxes``, does not share memory with ``boxes``

    Example:
        .. code-block:: python

            boxes = torch.ones(1,4)
            src_spatial_size = [100, 100]
            dst_spatial_size = [128, 256]
            resize_boxes(boxes, src_spatial_size, dst_spatial_size) #  will return tensor([[1.28, 2.56, 1.28, 2.56]])
    r+   c                   s    g | ]} | t |  qS r#   )float.0axisr;   r:   r#   r$   
<listcomp>   s     z resize_boxes.<locals>.<listcomp>)r&   r7   )r
   r   ranger9   )r&   r:   r;   r"   r7   r#   r@   r$   resize_boxes   s
    


rC   zSequence[int] | int | None)r&   spatial_size	flip_axesr   c                 C  s   t | d}t||}|dkr*ttd|}t|}t| tjrF|  nt	| }|D ]\}|| | dd|f  t
 |dd|| f< || | dd|| f  t
 |dd|f< qR|S )a  
    Flip boxes when the corresponding image is flipped

    Args:
        boxes: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode``
        spatial_size: image spatial size.
        flip_axes: spatial axes along which to flip over. Default is None.
            The default `axis=None` will flip over all of the axes of the input array.
            If axis is negative it counts from the last to the first axis.
            If axis is a tuple of ints, flipping is performed on all of the axes
            specified in the tuple.

    Returns:
        flipped boxes, with same data type as ``boxes``, does not share memory with ``boxes``
    r+   Nr   )r
   r   tuplerB   r   
isinstancer   r-   cloner   r	   )r&   rD   rE   r"   Z_flip_boxesr?   r#   r#   r$   
flip_boxes   s    

,.rI   Fint)r&   labelsrD   bg_labelellipse_maskr   c                   sZ  t | dt|}|jd dkrXtjd| tjdt| }t|| tjd^}}|S |t|kr|t	dt| d| |jd | jd krt	dtj|jd f| tjdt| }t
| tjtjdd td	d	d	f t|krt	d
t|d^}}tjd D ]"  fddtD }	|rt|	d }
d d tjg tjdt| }tfddtD }tfddtj| D }t|  |||
d k< t|	ddd}||d	 d }ntj|	tjdt|   } g}| fddtD  ||t|< q t|| tjdd S )au  
    Convert box to int16 mask image, which has the same size with the input image.

    Args:
        boxes: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode``.
        labels: classification foreground(fg) labels corresponding to `boxes`, dtype should be int, sized (N,).
        spatial_size: image spatial size.
        bg_label: background labels for the output mask image, make sure it is smaller than any fg labels.
        ellipse_mask: bool.

            - If True, it assumes the object shape is close to ellipse or ellipsoid.
            - If False, it assumes the object shape is close to rectangle or cube and well occupies the bounding box.
            - If the users are going to apply random rotation as data augmentation, we suggest setting ellipse_mask=True
              See also Kalra et al. "Towards Rotation Invariance in Object Detection", ICCV 2021.

    Return:
        - int16 array, sized (num_box, H, W). Each channel represents a box.
            The foreground region in channel c has intensity of labels[c].
            The background intensity is bg_label.
    r+   r   )r   r'   r)   r*   r   zGbg_label should be smaller than any foreground box labels.
min(labels)=z, while bg_label=z1Number of labels should equal to number of boxes.Nz%Some boxes are larger than the image.r(   c                   s(   g | ] } | f  |f  qS r#   r#   r=   bboxes_npr"   r#   r$   rA      s     z'convert_box_to_mask.<locals>.<listcomp>g       @r   c                 3  s   | ]}t d  V  qdS )r   Nslice)r>   r3   )max_box_sizer#   r$   	<genexpr>  s     z&convert_box_to_mask.<locals>.<genexpr>c                 3  s   | ]}|  d  V  qdS )r,   Nr#   )r>   grid)centerr#   r$   rV     s     r,   nearestF)rD   modeanti_aliasingc                 3  s,   | ]$}t  |f  | f V  qd S )NrS   )r>   drP   r#   r$   rV     s     )r
   r   r   npr   int16r   r   r/   
ValueErrorr   ndarrayint32anyarrayrB   r1   rF   sumogridr   extend)r&   rL   rD   rM   rN   boxes_mask_np
boxes_maskr3   	labels_npbox_sizeradiusZboxes_only_maskrangesdist_from_centerresizerZslicingr#   )rQ   rR   rX   rU   r"   r$   convert_box_to_mask   sD    

&&  ro   zDtypeLike | torch.dtypez'tuple[NdarrayOrTensor, NdarrayOrTensor])rh   rM   	box_dtypelabel_dtyper   c              	   C  s  t t| jddg t| jdd }t|d}t| tj^}}g }g }	t|jd D ]}
t	||
df | }|d jd dkrqVg }|D ]}|
t| q|D ]}|
t|d t  q|
| |dkr|	
||
|d d |d d f  |dkrV|	
||
|d d |d d |d d f  qVt|dkr^tdd| gtdg }}nt|t|	 }}t|| |d	^}}t|| |d	^}}||fS )
a  
    Convert int16 mask image to box, which has the same size with the input image

    Args:
        boxes_mask: int16 array, sized (num_box, H, W). Each channel represents a box.
            The foreground region in channel c has intensity of labels[c].
            The background intensity is bg_label.
        bg_label: background labels for the boxes_mask
        box_dtype: output dtype for boxes
        label_dtype: output dtype for labels

    Return:
        - bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode``.
        - classification foreground(fg) labels, dtype should be int, sized (N,).
          r   N)rD   r   .r,   rO   )r   lenr   listr
   r   r]   r`   rB   nonzeroappendr/   r1   r	   zerosasarrayr   )rh   rM   rp   rq   rD   r"   rg   r3   
boxes_listZlabels_listrQ   
fg_indicesZboxes_bZfd_irR   ri   r&   rL   r#   r#   r$   convert_mask_to_box  s4    

$0"r|   z+Sequence[NdarrayOrTensor] | NdarrayOrTensorztuple | NdarrayOrTensor)rL   keepr   c                 C  s|   t | d}g }t|tjd }|D ]6}t|tjd }||df }|t||dd  q"t| tjtjfrt|d S t	|S )au  
    For element in labels, select indices keep from it.

    Args:
        labels: Sequence of array. Each element represents classification labels or scores
            corresponding to ``boxes``, sized (N,).
        keep: the indices to keep, same length with each element in labels.

    Return:
        selected labels, does not share memory with original labels.
    Tr   .r(   )
r   r   r   r-   rw   r   rG   r]   r`   rF   )rL   r}   Zlabels_tupleZlabels_select_listkeep_titemlabels_tr#   r#   r$   select_labelsH  s    
r   )r&   axis1axis2r   c                 C  s   t | d}t| tjr |  }nt| }|dd||gf |dd||gf< |dd|| || gf |dd|| || gf< |S )a  
    Interchange two axes of boxes.

    Args:
        boxes: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode``
        axis1: First axis.
        axis2: Second axis.

    Returns:
        boxes with two axes interchanged.

    r+   N)r
   rG   r   r-   rH   r   )r&   r   r   r"   Z
boxes_swapr#   r#   r$   swapaxes_boxese  s    

$r   r   r   r   ztuple[int, int])r&   rD   kaxesr   c                 C  sf  t | d}tt||}t|}t|dkr4td|d |d ks\t|d |d  |krdtd|d |ks|d | k s|d |ks|d | k rtd| d| d	|d
; }|dkr| S |dkrtt| ||d ||d S |dkrt| ||d }t||d |d S t| |d |d }||d  ||d   ||d < ||d < t|||d S dS )a@  
    Rotate boxes by 90 degrees in the plane specified by axes.
    Rotation direction is from the first towards the second axis.

    Args:
        boxes: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode``
        spatial_size: image spatial size.
        k : number of times the array is rotated by 90 degrees.
        axes: (2,) array_like
            The array is rotated in the plane defined by the axes. Axes must be different.

    Returns:
        A rotated view of `boxes`.

    Notes:
        ``rot90_boxes(boxes, spatial_size, k=1, axes=(1,0))``  is the reverse of
        ``rot90_boxes(boxes, spatial_size, k=1, axes=(0,1))``
        ``rot90_boxes(boxes, spatial_size, k=1, axes=(1,0))`` is equivalent to
        ``rot90_boxes(boxes, spatial_size, k=-1, axes=(0,1))``
    r+   r,   zlen(axes) must be 2.r   r   zAxes must be different.zAxes=z  out of range for array of ndim=.rs   N)	r
   ru   r   r   rt   r_   absrI   r   )r&   rD   r   r   r"   spatial_size_Zboxes_r#   r#   r$   rot90_boxes  s(    
(4
*r   )T)N)rJ   F)r   r   ))
__future__r   collections.abcr   copyr   numpyr]   r   monai.config.type_definitionsr   r   r   monai.data.box_utilsr   r	   r
   monai.transformsr   monai.transforms.utilsr   monai.utilsr   monai.utils.miscr   r   monai.utils.type_conversionr   r   r%   r6   r9   rC   rI   ro   float32longr|   r   r   r   r#   r#   r#   r$   <module>   s:   !(! &  R5   