
    .hn2                       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	 d dl
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 dddZdddZ	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 ddZdddZ	 d	 	 	 	 	 	 	 	 	 	 	 	 	 d dZ	 	 	 d!	 	 	 	 	 	 	 	 	 	 	 d"dZ	 d#	 	 	 	 	 	 	 	 	 	 	 d$dZ	 d#	 	 	 	 	 	 	 	 	 	 	 d$dZedk(  r edd        edd       yy)%    )annotationsN)glob)ceil)Path)Any)Image)	exif_sizeimg2label_paths)TQDM)check_requirementsc           
        t        d       ddlm} | j                  ddd      } t	        j
                  | d      }t	        j                  | d      }t	        j                  ||gd      }t	        j                  |d	d	d	d	df   d
d	df         }t	        j                  |d	d	d	dd	f   d
dd	f         }t	        j                  ||z
  dt        j                        }	|	d   |	d   z  }
fdt        d      D        \  }}}}t	        j                  ||||||||gd      j                  ddd      }| D cg c]
  } ||       }}|D cg c]
  } ||       }}t	        j                  |
j                        }t!        t	        j"                  |
       D ],  }||d      j%                  ||d            j&                  ||<   . t	        j(                  |D cg c]  }|j&                   c}t        j*                        }|d   }t	        j                  ||t        j                        }||z  }|j,                  dk(  r|d   }|S c c}w c c}w c c}w )a  
    Calculate Intersection over Foreground (IoF) between polygons and bounding boxes.

    Args:
        polygon1 (np.ndarray): Polygon coordinates with shape (N, 8).
        bbox2 (np.ndarray): Bounding boxes with shape (N, 4).
        eps (float, optional): Small value to prevent division by zero.

    Returns:
        (np.ndarray): IoF scores with shape (N, 1) or (N, M) if bbox2 is (M, 4).

    Notes:
        Polygon format: [x1, y1, x2, y2, x3, y3, x4, y4].
        Bounding box format: [x_min, y_min, x_max, y_max].
    zshapely>=2.0.0r   )Polygon      axisN.).r   ).   c              3  ,   K   | ]  }d |f     yw.N ).0ibbox2s     Y/var/www/html/ai-service/venv/lib/python3.12/site-packages/ultralytics/data/split_dota.py	<genexpr>zbbox_iof.<locals>.<genexpr>1   s     @!c1f@s   dtyper   r   )r   shapely.geometryr   reshapenpminmaxconcatenatemaximumminimumclipinfrangestackzerosshapezipnonzerointersectionareaarrayfloat32ndim)polygon1r   epsr   lt_pointrb_pointbbox1ltrbwh
h_overlapslefttoprightbottompolygon2p	sg_polys1	sg_polys2overlapsunionsoutputss    `                    r   bbox_iofrI      s$     '((Aq)HvvhR(HvvhR(HNNHh/b9E	E!T2A2+&c2A2g	7B	E!T12+&c12g	7B	b!RVV	$BFbj(J@uQx@D#ufxxsE3vtVLSUV^^_acdfghH%-..I.%-..I.xx
(()H"**Z() J!o229QrU3CDIIJXXy1!qvv1DFIFWWVS"&&)FG||q)$N /. 2s   ;IIIc                   |dv sJ d| d       t        |       dz  |z  }|j                         sJ d| d       t        t        t        |       dz  |z  dz              }t	        |      }g }t        ||      D ]  \  }}t        t        j                  |            \  }}	t        |d	      5 }
|
j                         j                         j                         D cg c]  }t        |      s|j                           }}t        j                  |t        j                   
      }ddd       |j#                  t%        |	|f|              |S c c}w # 1 sw Y   1xY w)a1  
    Load DOTA dataset annotations and image information.

    Args:
        data_root (str): Data root directory.
        split (str, optional): The split data set, could be 'train' or 'val'.

    Returns:
        (list[dict[str, Any]]): List of annotation dictionaries containing image information.

    Notes:
        The directory structure assumed for the DOTA dataset:
            - data_root
                - images
                    - train
                    - val
                - labels
                    - train
                    - val
    >   valtrainz$Split must be 'train' or 'val', not .imagesCan't find , please check your data root.*utf-8encodingr   N)ori_sizelabelfilepath)r   existsr   strr
   r.   r	   r   openreadstrip
splitlineslensplitr"   r2   r3   appenddict)	data_rootr_   im_dirim_fileslb_filesannosim_filelb_filewhfxlbs                r   load_yolo_dotarn   C   sJ   * $$U(LUGST&UU$)_x'%/F==?Pk&1OPP?CY(2U:S@ABHx(HE(3 HG,-1'G, 	0%&VVX^^%5%@%@%BMc!f!'')MBM"BJJ/B	0 	TAq6gFGH L N	0 	0s$   //EE/E'EEE!	c           	        | \  }}g }t        ||      D ];  \  }}	||	kD  sJ d| d|	 d       ||	z
  }
||k  rdnt        ||z
  |
z  dz         }t        |      D cg c]  }|
|z  	 }}t        |      dkD  r|d   |z   |kD  r||z
  |d<   ||k  rdnt        ||z
  |
z  dz         }t        |      D cg c]  }|
|z  	 }}t        |      dkD  r|d   |z   |kD  r||z
  |d<   t	        j
                  t        t        j                  ||            t        j                        }||z   }|j                  t	        j                  ||gd             > t	        j                  |d      }|j                         }t	        j                  |d	d	dd	d
f   d|      |d	d	dd	d
f<   t	        j                  |d	d	dd	d
f   d|      |d	d	dd	d
f<   |d	d	d
f   |d	d	df   z
  |d	d	df   |d	d	df   z
  z  }|d	d	d
f   |d	d	df   z
  |d	d	df   |d	d	df   z
  z  }||z  }||kD  j                         s$|j                         }d|t!        ||z
        |k  <   |||kD     S c c}w c c}w )a6  
    Get the coordinates of sliding windows for image cropping.

    Args:
        im_size (tuple[int, int]): Original image size, (H, W).
        crop_sizes (tuple[int, ...], optional): Crop size of windows.
        gaps (tuple[int, ...], optional): Gap between crops.
        im_rate_thr (float, optional): Threshold of windows areas divided by image areas.
        eps (float, optional): Epsilon value for math operations.

    Returns:
        (np.ndarray): Array of window coordinates with shape (N, 4) where each row is [x_start, y_start, x_stop, y_stop].
    zinvalid crop_size gap pair [ ]r   r   r   r   r   Nr      )r.   r   r*   r^   r"   r2   list	itertoolsproductint64r`   r%   copyr(   anyr$   abs)im_size
crop_sizesgapsim_rate_thrr6   rj   ri   windows	crop_sizegapstepxnr   xsynysstartstop
im_in_winsim_areas	win_areasim_ratesmax_rates                          r   get_windowsr   g   s   ( DAqGj$/ >	33Q">yk3%q QQ3y.QdA	MT+AA+E&F %b	*1dQh**r7Q;2b6I-1]BrFy.QdA	MT+AA+E&F %b	*1dQh**r7Q;2b6I-1]BrFi//B78Iy r~~udm!<=!>" nnW1-GJ''*Q1W"5q!<Jq!$Q$w''*Q1W"5q!<Jq!$Q$w1a4 :ad#33
1a48H:VWYZVZK[8[\HAA.71a4=71a4=3PQI)#H{"'')<<>34X()C/08k)**/ +
 +s   I"2I'c                   | d   \  }}| d   }t        |      rl|dddddfxx   |z  cc<   |dddddfxx   |z  cc<   t        |ddddf   |      }t        t        |            D cg c]  }||dd|f   |k\      c}S t        t        |            D cg c]'  }t        j                  dt        j
                        ) c}S c c}w c c}w )z3Get objects for each window based on IoF threshold.rU   rV   Nr   r   )r   	   r   )r^   rI   r*   r"   r,   r3   )	annor~   iof_thrrj   ri   rV   iofsr   _s	            r   get_window_objr      s    
DAqME
5zaAg!aAg!aeg.8=c'l8KL1tAqDzW,-LL<A#g,<OPqrzz2PP MPs   ,C
,Cc           
     V   t        j                  | d         }t        | d         j                  }t	        |      D ]X  \  }}	|	j                         \  }
}}}| d||
z
   d|
 d| }||||
|f   }|j                  dd \  }}||   }t        |      s|r.t        j                  t        t        |      | dz        |       t        |      s|dddddfxx   |
z  cc<   |dddddfxx   |z  cc<   |dddddfxx   |z  cc<   |dddddfxx   |z  cc<   t        t        |      | dz  d	d
      5 }|D ]H  }|dd D cg c]  }|d }}|j                  t        |d          ddj                  |       d       J 	 ddd       [ yc c}w # 1 sw Y   lxY w)a$  
    Crop images and save new labels for each window.

    Args:
        anno (dict[str, Any]): Annotation dict, including 'filepath', 'label', 'ori_size' as its keys.
        windows (np.ndarray): Array of windows coordinates with shape (N, 4).
        window_objs (list[np.ndarray]): A list of labels inside each window.
        im_dir (str): The output directory path of images.
        lb_dir (str): The output directory path of labels.
        allow_background_images (bool, optional): Whether to include background images without labels.

    Notes:
        The directory structure assumed for the DOTA dataset:
            - data_root
                - images
                    - train
                    - val
                - labels
                    - train
                    - val
    rW   _____Nr   .jpgr   z.txtri   rR   rS   z.6gr   rp   
)cv2imreadr   stem	enumeratetolistr-   r^   imwriterY   rZ   writeintjoin)r   r~   window_objsrc   lb_dirallow_background_imagesimnamer   windowx_starty_startx_stopy_stopnew_namepatch_imphpwrV   rk   rm   coordformatted_coordss                          r   crop_and_saver      s   : 
D$	%BZ !&&Dw' L	6+1==?(&&V2fw./r'#gYGgfngfn45#BAu:0KKDLhZt+<<=xHu:!QTT'Ng%N!QTT'Ng%N!QTT'Nb N!QTT'Nb Nd6lz%66gN LRS LBDFqrF'K55+'K$'KGGs2a5zl!CHH5E,F+GrJKLL LL" (LL Ls   >FF
6FFF(	c           
     `   t        |      dz  |z  }|j                  dd       t        |      dz  |z  }|j                  dd       t        | |      }t        |t	        |      |      D ]?  }t        |d   ||      }	t        ||	      }
t        ||	|
t        |      t        |             A y)	a  
    Split both images and labels for a given dataset split.

    Args:
        data_root (str): Root directory of the dataset.
        save_dir (str): Directory to save the split dataset.
        split (str, optional): The split data set, could be 'train' or 'val'.
        crop_sizes (tuple[int, ...], optional): Tuple of crop sizes.
        gaps (tuple[int, ...], optional): Tuple of gaps between crops.

    Notes:
        The directory structure assumed for the DOTA dataset:
            - data_root
                - images
                    - split
                - labels
                    - split
        and the output directory structure is:
            - save_dir
                - images
                    - split
                - labels
                    - split
    rN   Tparentsexist_oklabels)r_   totaldescrU   N)	r   mkdirrn   r   r^   r   r   r   rY   )rb   save_dirr_   r{   r|   rc   r   rf   r   r~   r   s              r   split_images_and_labelsr      s    > (^h&.F
LLL-(^h&.F
LLL-9E2EU#e*59 Ld:.
DA$T73dG[#f+s6{KL    c                    g g }}|D ]<  }|j                  t        ||z               |j                  t        ||z               > dD ]  }t        | ||||        y)am  
    Split train and val sets of DOTA dataset with multiple scaling rates.

    Args:
        data_root (str): Root directory of the dataset.
        save_dir (str): Directory to save the split dataset.
        crop_size (int, optional): Base crop size.
        gap (int, optional): Base gap between crops.
        rates (tuple[float, ...], optional): Scaling rates for crop_size and gap.

    Notes:
        The directory structure assumed for the DOTA dataset:
            - data_root
                - images
                    - train
                    - val
                - labels
                    - train
                    - val
        and the output directory structure is:
            - save_dir
                - images
                    - train
                    - val
                - labels
                    - train
                    - val
    >   rK   rL   N)r`   r   r   )	rb   r   r   r   ratesr{   r|   rr_   s	            r   split_trainvalr   	  sj    > 2J "#i!m,-CaL!" " N	8UJMNr   c           	        g g }}|D ]<  }|j                  t        ||z               |j                  t        ||z               > t        |      dz  dz  }|j                  dd       t        |       dz  dz  }|j	                         sJ d| d       t        t        |dz              }	t        |	t        |	      d      D ]  }
t        t        j                  |
            \  }}t        ||f||	      }t        j                  |
      }t        |
      j                  }|D ]W  }|j!                         \  }}}}| d
||z
   d
| d| }|||||f   }t        j"                  t        || dz        |       Y  y)a  
    Split test set of DOTA dataset, labels are not included within this set.

    Args:
        data_root (str): Root directory of the dataset.
        save_dir (str): Directory to save the split dataset.
        crop_size (int, optional): Base crop size.
        gap (int, optional): Base gap between crops.
        rates (tuple[float, ...], optional): Scaling rates for crop_size and gap.

    Notes:
        The directory structure assumed for the DOTA dataset:
            - data_root
                - images
                    - test
        and the output directory structure is:
            - save_dir
                - images
                    - test
    rN   testTr   rO   rP   rQ   r   )r{   r|   r   r   r   N)r`   r   r   r   rX   r   rY   r   r^   r	   r   rZ   r   r   r   r   r   r   )rb   r   r   r   r   r{   r|   r   rc   rd   rg   ri   rj   r~   r   r   r   r   r   r   r   r   r   s                          r   
split_testr   0  s   . 2J "#i!m,-CaL!" H~(61HNN4$N/)_x'&0F==?Pk&1OPP?C%&HHFC 	EG,-1q!f$GZZ G}!! 	EF/5}},GWffr&7"2!32gYc'KH'&.'&.89HKKH(4'8898D		E	Er   __main__DOTAv2zDOTAv2-split)rb   r   )gư>)r5   
np.ndarrayr   r   r6   floatreturnr   )rL   )rb   rY   r_   rY   r   zlist[dict[str, Any]])      g333333?g{Gz?)rz   ztuple[int, int]r{   tuple[int, ...]r|   r   r}   r   r6   r   r   r   )gffffff?)r   dict[str, Any]r~   r   r   r   r   list[np.ndarray])T)r   r   r~   r   r   r   rc   rY   r   rY   r   boolr   None)rL   r   r   )rb   rY   r   rY   r_   rY   r{   r   r|   r   r   r   )r   r   )g      ?)rb   rY   r   rY   r   r   r   r   r   ztuple[float, ...]r   r   )
__future__r   rt   r   mathr   pathlibr   typingr   r   numpyr"   PILr   ultralytics.data.utilsr	   r
   ultralytics.utilsr   ultralytics.utils.checksr   rI   rn   r   r   r   r   r   r   __name__r   r   r   <module>r      s   #      
   = " 7,^!L #*"2+2+2+ 2+ 	2+
 
2+ 2+jQ( %)1L
1L1L "1L 	1L
 1L "1L 
1Ln ")"(L(L(L (L  	(L
 (L 
(LX fl$N$N!$N.1$N?B$NQb$N	$NP fl*E*E!*E.1*E?B*EQb*E	*EZ zX?N; r   