o
    ĎiWf                     @  s  d dl mZ d dlZd dlZd dlmZ d dlmZ d dl	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 d d
lmZ d dlmZmZmZmZ d dlmZmZmZ d dl m!Z!m"Z" dZ#					dfdgddZ$dhd%d&Z%did)d*Z&G d+d, d,Z'G d-d. d.Z(									/		0	djdkd;d<Z)		0	=	=			/		0	dldmdDdEZ*dndodLdMZ+dpdOdPZ,dqdSdTZ-drdVdWZ.dsdYdZZ/dtd[d\Z0dud_d`Z1dvdddeZ2dS )w    )annotationsN)Sequence)Path)Literal)Image)TopologicalError)tqdm)BoundingBoxMask)logger)CocoCocoAnnotation	CocoImagecreate_coco_dict)IMAGE_EXTENSIONS_LOSSLESSIMAGE_EXTENSIONS_LOSSYread_image_as_pil)	load_json	save_json   T皙?image_heightintimage_widthslice_height
int | Noneslice_widthauto_slice_resolutionbool | Noneoverlap_height_ratiofloat | Noneoverlap_width_ratioreturnlist[list[int]]c                 C  s  g }d }}	|r|rt || }
t || }n|r$t| |d\}}
}}ntd|| k rd }}|	| }||k rw|| }|| ksD||krft||}t| |}td|| }td|| }|||||g n	|||	||g || }||k s8||
 }	|| k s,|S )a  Generate bounding boxes for slicing an image into crops.

    The function calculates the coordinates for each slice based on the provided
    image dimensions, slice size, and overlap ratios. If slice size is not provided
    and auto_slice_resolution is True, the function will automatically determine
    appropriate slice parameters.

    Args:
        image_height (int): Height of the original image.
        image_width (int): Width of the original image.
        slice_height (int, optional): Height of each slice. Default None.
        slice_width (int, optional): Width of each slice. Default None.
        overlap_height_ratio (float, optional): Fractional overlap in height of each
            slice (e.g. an overlap of 0.2 for a slice of size 100 yields an
            overlap of 20 pixels). Default 0.2.
        overlap_width_ratio(float, optional): Fractional overlap in width of each
            slice (e.g. an overlap of 0.2 for a slice of size 100 yields an
            overlap of 20 pixels). Default 0.2.
        auto_slice_resolution (bool, optional): if not set slice parameters such as slice_height and slice_width,
            it enables automatically calculate these parameters from image resolution and orientation.

    Returns:
        List[List[int]]: List of 4 corner coordinates for each N slices.
            [
                [slice_0_left, slice_0_top, slice_0_right, slice_0_bottom],
                ...
                [slice_N_left, slice_N_top, slice_N_right, slice_N_bottom]
            ]
    r   heightwidthzECompute type is not auto and slice width and height are not provided.)r   get_auto_slice_params
ValueErrorminmaxappend)r   r   r   r   r   r   r!   slice_bboxesy_maxy_min	y_overlap	x_overlapx_minx_maxxmaxymaxxminymin r7   H/home/jeff/fluffinator/venv/lib/python3.10/site-packages/sahi/slicing.pyget_slice_bboxes   s2   &

r9   
annotationdict
slice_bbox	list[int]boolc                 C  sd   | d \}}}}|| }|| }||d krdS ||d kr dS ||d kr(dS ||d kr0dS dS )aq  Check whether annotation coordinates lie inside slice coordinates.

    Args:
        annotation (dict): Single annotation entry in COCO format.
        slice_bbox (List[int]): Generated from `get_slice_bboxes`.
            Format for each slice bbox: [x_min, y_min, x_max, y_max].

    Returns:
        (bool): True if any annotation coordinate lies inside slice.
    bbox   F   r      Tr7   )r:   r<   lefttopr&   r%   rightbottomr7   r7   r8   annotation_inside_sliceZ   s   rG   coco_annotation_listlist[CocoAnnotation]c                 C  sB   g }| D ]}t |j|r||}|j|j |kr|| q|S )a1  Slices and filters given list of CocoAnnotation objects with given 'slice_bbox' and 'min_area_ratio'.

    Args:
        coco_annotation_list (List[CocoAnnotation])
        slice_bbox (List[int]): Generated from `get_slice_bboxes`.
            Format for each slice bbox: [x_min, y_min, x_max, y_max].
        min_area_ratio (float): If the cropped annotation area to original
            annotation ratio is smaller than this value, the annotation is
            filtered out. Default 0.1.

    Returns:
        (List[CocoAnnotation]): Sliced annotations.
    )rG   jsonget_sliced_coco_annotationarear+   )rH   r<   min_area_ratiosliced_coco_annotation_listcoco_annotationsliced_coco_annotationr7   r7   r8   process_coco_annotationsv   s   

rQ   c                   @  s   e Zd Zdd ZdS )SlicedImagec                 C  s   || _ || _|| _dS )a  
        image: np.array
            Sliced image.
        coco_image: CocoImage
            Coco styled image object that belong to sliced image.
        starting_pixel: list of list of int
            Starting pixel coordinates of the sliced image.
        Nimage
coco_imagestarting_pixel)selfrT   rU   rV   r7   r7   r8   __init__   s   	
zSlicedImage.__init__N)__name__
__module____qualname__rX   r7   r7   r7   r8   rR      s    rR   c                   @  st   e Zd ZddddZdd
dZedd Zedd ZedddZed ddZ	ed ddZ
dd Zdd ZdS )!SliceImageResultNoriginal_image_sizer=   	image_dir
str | Nonec                 C  s$   |d | _ |d | _|| _g | _dS )z
        image_dir: str
            Directory of the sliced image exports.
        original_image_size: list of int
            Size of the unsliced original image in [height, width]
        r   rB   N)original_image_heightoriginal_image_widthr^   _sliced_image_list)rW   r]   r^   r7   r7   r8   rX      s   


zSliceImageResult.__init__sliced_imagerR   c                 C  s"   t |ts	td| j| d S )Nz+sliced_image must be a SlicedImage instance)
isinstancerR   	TypeErrorrb   r+   )rW   rc   r7   r7   r8   add_sliced_image   s   
z!SliceImageResult.add_sliced_imagec                 C  s   | j S N)rb   rW   r7   r7   r8   sliced_image_list   s   z"SliceImageResult.sliced_image_listc                 C      g }| j D ]}||j q|S )zXReturns sliced images.

        Returns:
            images: a list of np.array
        )rb   r+   rT   )rW   imagesrc   r7   r7   r8   rk         
zSliceImageResult.imagesr"   list[CocoImage]c                 C  rj   )z}Returns CocoImage representation of SliceImageResult.

        Returns:
            coco_images: a list of CocoImage
        )rb   r+   rU   )rW   coco_imagesrc   r7   r7   r8   rn      rl   zSliceImageResult.coco_imagesc                 C  rj   )zReturns a list of starting pixels for each slice.

        Returns:
            starting_pixels: a list of starting pixel coords [x,y]
        )rb   r+   rV   )rW   starting_pixelsrc   r7   r7   r8   ro      rl   z SliceImageResult.starting_pixelsc                 C  s"   g }| j D ]	}||jj q|S )zxReturns a list of filenames for each slice.

        Returns:
            filenames: a list of filenames as str
        )rb   r+   rU   	file_name)rW   	filenamesrc   r7   r7   r8   rq      s   
zSliceImageResult.filenamesc                   s   fdd t |tjr| }t |tr |S t |tr5|t\}}} fddt|||D S t |t	t
frEt |}t
|S tt| )Nc                   s&    j |   j|   j|   j|  dS )N)rT   rU   rV   filename)rk   rn   ro   rq   )irh   r7   r8   _prepare_ith_dict   s
   z7SliceImageResult.__getitem__.<locals>._prepare_ith_dictc                   s   g | ]} |qS r7   r7   ).0rs   )rt   r7   r8   
<listcomp>   s    z0SliceImageResult.__getitem__.<locals>.<listcomp>)rd   npndarraytolistr   sliceindiceslenrangetuplelistmapNotImplementedErrortype)rW   rs   startstopstepaccessed_mappingr7   )rt   rW   r8   __getitem__   s   


zSliceImageResult.__getitem__c                 C  s
   t | jS rg   )r|   rb   rh   r7   r7   r8   __len__   s   
zSliceImageResult.__len__rg   )r]   r=   r^   r_   )rc   rR   )r"   rm   )r"   r=   )rY   rZ   r[   rX   rf   propertyri   rk   rn   ro   rq   r   r   r7   r7   r7   r8   r\      s    


r\   皙?FrT   str | Image.Imagelist[CocoAnnotation] | Noneoutput_file_namer_   
output_dirrM   out_extverboseexif_fixc           "   	     sH  |rt jndd d  fdd	}|d
urt|jddd t|  d}dt|j  |j\}}|dkr:|dksCtd|j dt|||||||d}d}t	||g|d}t
|}|D ]}|d7 }|d }|d }|d }|d }|||||f }dtt|}|
r|
}n!t|drtt|dj}|tv rd}n|tv rt|jj}nd}| d| | }|d |d  }|d |d  }t|||d}|d
urt|||	D ]}|| qt|||d |d gd} ||  q_|r|rtjjtd}!|!||j|gt| |j dt| d t| d t|  |S )!a  Slice a large image into smaller windows. If output_file_name and output_dir is given, export sliced images.

    Args:
        image (str or PIL.Image): File path of image or Pillow Image to be sliced.
        coco_annotation_list (List[CocoAnnotation], optional): List of CocoAnnotation objects.
        output_file_name (str, optional): Root name of output files (coordinates will
            be appended to this)
        output_dir (str, optional): Output directory
        slice_height (int, optional): Height of each slice. Default None.
        slice_width (int, optional): Width of each slice. Default None.
        overlap_height_ratio (float, optional): Fractional overlap in height of each
            slice (e.g. an overlap of 0.2 for a slice of size 100 yields an
            overlap of 20 pixels). Default 0.2.
        overlap_width_ratio (float, optional): Fractional overlap in width of each
            slice (e.g. an overlap of 0.2 for a slice of size 100 yields an
            overlap of 20 pixels). Default 0.2.
        auto_slice_resolution (bool, optional): if not set slice parameters such as slice_height and slice_width,
            it enables automatically calculate these params from image resolution and orientation.
        min_area_ratio (float, optional): If the cropped annotation area to original annotation
            ratio is smaller than this value, the annotation is filtered out. Default 0.1.
        out_ext (str, optional): Extension of saved images. Default is the
            original suffix for lossless image formats and png for lossy formats ('.jpg','.jpeg').
        verbose (bool, optional): Switch to print relevant values to screen.
            Default 'False'.
        exif_fix (bool): Whether to apply an EXIF fix to the image.

    Returns:
        sliced_image_result: SliceImageResult:
                                sliced_image_list: list of SlicedImage
                                image_dir: str
                                    Directory of the sliced image exports.
                                original_image_size: list of int
                                    Size of the unsliced original image in [height, width]
    c                  _  s   d S rg   r7   )akr7   r7   r8   <lambda>5  s    zslice_image.<locals>.<lambda>rT   
np.ndarrayr   strslice_file_namec                   s>   t |  d}tt|| }|| |  d|  d S )Nr   zsliced image path: )r   r   r   saveclose)rT   r   r   	image_pilslice_file_pathr   
verboselogr7   r8   _export_single_slice7  s
   
z)slice_image.<locals>._export_single_sliceNT)parentsexist_okr   zimage.shape: r   zinvalid image size: z for 'slice_image'.)r   r   r   r   r   r   r!   )r]   r^   rB   r@   rA   _rr   z.png)rp   r%   r&   rS   )max_workerszNum slices: z slice_height: z slice_width: )rT   r   r   r   r   r   ) r   infor   mkdirr   r   sizeRuntimeErrorr9   r\   rw   asarrayjoinr   hasattrgetattrsuffixr   r   rr   r   rQ   add_annotationrR   rf   
concurrentfuturesThreadPoolExecutorMAX_WORKERSrk   r|   rq   )"rT   rH   r   r   r   r   r   r!   r   rM   r   r   r   r   r   r   r   r,   n_imssliced_image_resultimage_pil_arrr<   tlxtlybrxbryimage_pil_sliceslice_suffixesr   r   rU   rP   rc   	conc_execr7   r   r8   slice_image  s|   3	



"r      coco_annotation_file_pathr   r^    output_coco_annotation_file_nameignore_negative_sampleslist[dict | str]c                 C  s   t | }t|}g }tt|jD ]?\}}tj||j	}z"t
||jt|j	j d| ||||||	|
||d}||j W q tyQ   td|  Y qw t||d |d}d}|rn|rnt||d  }t|| ||fS )a  Slice large images given in a directory, into smaller windows. If output_dir is given, export sliced images and
    coco file.

    Args:
        coco_annotation_file_path (str): Location of the coco annotation file
        image_dir (str): Base directory for the images
        output_coco_annotation_file_name (str): File name of the exported coco
            dataset json.
        output_dir (str, optional): Output directory
        ignore_negative_samples (bool, optional): If True, images without annotations
            are ignored. Defaults to False.
        slice_height (int, optional): Height of each slice. Default 512.
        slice_width (int, optional): Width of each slice. Default 512.
        overlap_height_ratio (float, optional): Fractional overlap in height of each
            slice (e.g. an overlap of 0.2 for a slice of size 100 yields an
            overlap of 20 pixels). Default 0.2.
        overlap_width_ratio (float, optional): Fractional overlap in width of each
            slice (e.g. an overlap of 0.2 for a slice of size 100 yields an
            overlap of 20 pixels). Default 0.2.
        min_area_ratio (float): If the cropped annotation area to original annotation
            ratio is smaller than this value, the annotation is filtered out. Default 0.1.
        out_ext (str, optional): Extension of saved images. Default is the
            original suffix.
        verbose (bool, optional): Switch to print relevant values to screen.
        exif_fix (bool, optional): Whether to apply an EXIF fix to the image.

    Returns:
        coco_dict: dict
            COCO dict for sliced images and annotations
        save_path: str
            Path to the saved coco file
    r   )rT   rH   r   r   r   r   r   r!   rM   r   r   r   z/Invalid annotation found, skipping this image: 
categories)r    z
_coco.json)r   r   from_coco_dict_or_path	enumerater   rk   ospathr   rp   r   r   r   stemextendrn   r   r   warningr   r   )r   r^   r   r   r   r   r   r   r!   rM   r   r   r   	coco_dictcocosliced_coco_imagesidxrU   
image_pathslice_image_result	save_pathr7   r7   r8   
slice_coco  s@   1


r   rB   orientation+Literal['vertical', 'horizontal', 'square']slideratiofloatc                 C  s~   | dkr||d ||f\}}}}n(| dkr"|d |||f\}}}}n| dkr1||||f\}}}}nt d|  d||||fS )z
    According to image resolution calculation overlap params
    Args:
        orientation: image capture angle
        slide: sliding window
        ratio: buffer value

    Returns:
        overlap params
    verticalr@   
horizontalsquarezInvalid orientation: z7. Must be one of 'vertical', 'horizontal', or 'square'.)r(   )r   r   r   	slice_row	slice_colr   r!   r7   r7   r8   calc_ratio_and_slice  s   r   
resolutionc                 C  s4   d}t d|| k r|d7 }t d|| k s
|d S )z
    According to image resolution calculate power(2,n) and return the closest smaller `n`.
    Args:
        resolution: the width and height of the image multiplied. such as 1024x720 = 737280

    Returns:

    r   r@   rB   )rw   power)r   expor7   r7   r8   calc_resolution_factor
  s
   	r   r&   r%   c                 C  s   | |k rdS | |krdS dS )z_

    Args:
        width:
        height:

    Returns:
        image capture orientation
    r   r   r   r7   r&   r%   r7   r7   r8   calc_aspect_ratio_orientation  s
   r   tuple[int, int, int, int]c                 C  s   | dkrt |ddd\}}}}n(| dkr t |ddd\}}}}n| dkr0t |d	dd\}}}}nd}d}d}d}|| }|| }	t|	| }
t|| }|
||	|fS )
a  
    This function calculate according to image resolution slice and overlap params.
    Args:
        resolution: str
        height: int
        width: int
        orientation: str

    Returns:
        x_overlap, y_overlap, slice_width, slice_height
    mediumrB   g?)r   r   highr@   g?
ultra-high   )r   r   )r   r%   r&   r   	split_row	split_colr   r!   r   r   r0   r/   r7   r7   r8   calc_slice_and_overlap_params-  s*   r   resc                 C  s0   t ||d}t| |||d\}}}}||||fS )z

    Args:
        res: resolution of image such as low, medium
        height:
        width:

    Returns:
        trigger slicing params function and return overlap params
    r   )r   r%   r&   r   )r   r   )r   r%   r&   r   r0   r/   r   r   r7   r7   r8   get_resolution_selectorY  s
   r   c                 C  s   | | }t |}|dkrtd| |dS d|  krdk r&n ntd| |dS d|  kr0dk r9n ntd| |dS td| |dS )	aW  
    According to Image HxW calculate overlap sliding window and buffer params
    factor is the power value of 2 closest to the image resolution.
        factor <= 18: low resolution image such as 300x300, 640x640
        18 < factor <= 21: medium resolution image such as 1024x1024, 1336x960
        21 < factor <= 24: high resolution image such as 2048x2048, 2048x4096, 4096x4096
        factor > 24: ultra-high resolution image such as 6380x6380, 4096x8192
    Args:
        height:
        width:

    Returns:
        slicing overlap params x_overlap, y_overlap, slice_width, slice_height
       lowr$      r      r   r   )r   r   )r%   r&   r   factorr7   r7   r8   r'   l  s   r'   offsetSequence[int]c                 C  s   g }t | jdkrd}nd}| D ]}|st|tjr| }t||d}| }||	  qt| tjr=tj
|ddS |rD| |S |S )aM  Shift bboxes w.r.t offset.

    Suppo

    Args:
        bboxes (Tensor, np.ndarray, list): The bboxes need to be translated. Its shape can
            be (n, 4), which means (x, y, x, y).
        offset (Sequence[int]): The translation offsets with shape of (2, ).
    Returns:
        Tensor, np.ndarray, list: Shifted bboxes.
    torchTF)shift_amountr   axis)r   rZ   rd   rw   rx   ry   r	   get_shifted_boxr+   to_xyxystack
new_tensor)bboxesr   shifted_bboxesbboxes_is_torch_tensorr?   r7   r7   r8   shift_bboxes  s   
r   masksr   
full_shapec                 C  sJ   | du r| S g }| D ]}t |||d}| }||j q
tj|ddS )aA  Shift masks to the original image.

    Args:
        masks (np.ndarray): masks that need to be shifted.
        offset (Sequence[int]): The offset to translate with shape of (2, ).
        full_shape (Sequence[int]): A (height, width) tuple of the huge image's shape.
    Returns:
        np.ndarray: Shifted masks.
    N)segmentationr   r  r   r   )r
   get_shifted_maskr+   	bool_maskrw   r   )r  r   r  shifted_masksmaskr7   r7   r8   shift_masks  s   r  )NNTr   r   )r   r   r   r   r   r   r   r   r   r   r   r    r!   r    r"   r#   )r:   r;   r<   r=   r"   r>   )rH   rI   r<   r=   r"   rI   )NNNNNr   r   Tr   NFT)rT   r   rH   r   r   r_   r   r_   r   r   r   r   r   r    r!   r    r   r   rM   r    r   r_   r   r   r   r>   r"   r\   )
NFr   r   r   r   r   NFT)r   r   r^   r   r   r   r   r_   r   r   r   r   r   r   r   r    r!   r    rM   r    r   r_   r   r   r   r>   r"   r   )rB   r   )r   r   r   r   r   r   )r   r   r"   r   )r&   r   r%   r   r"   r   )
r   r   r%   r   r&   r   r   r   r"   r   )r   r   r%   r   r&   r   r"   r   )r%   r   r&   r   r"   r   )r   r   )r  r   r   r   r  r   r"   r   )3
__future__r   concurrent.futuresr   r   collections.abcr   pathlibr   typingr   numpyrw   PILr   shapely.errorsr   r   sahi.annotationr	   r
   sahi.loggerr   sahi.utils.cocor   r   r   r   sahi.utils.cvr   r   r   sahi.utils.filer   r   r   r9   rG   rQ   rR   r\   r   r   r   r   r   r   r   r'   r   r  r7   r7   r7   r8   <module>   sv    
C
e ]



,

"