
    ^jQ                       d Z ddlmZ ddlZddl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mZmZmZ dd	lmZ  ej0                  e      Z ed
       G d d             Z e       Zeeedf   z  ee ef   z  Z!d-dZ"g dZ#ejH                  ejJ                  ejL                  dZ'	 	 	 	 	 	 	 	 	 	 	 	 d.dZ(d/dZ)	 	 	 d0	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d1dZ*d2dZ+	 d3	 	 	 	 	 	 	 	 	 	 	 	 	 d4dZ,ddddedf	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d5dZ-edk(  rddl.Z. e.j^                  d       Z0e0jc                  d!e d"d#$       e0jc                  d%e2d&d'$       e0jc                  d(e2dd)$       e0jc                  d*e ddgdd+,       e0jg                         Z4 e-e4jj                  e4jl                  e4jn                  e4jp                         yy)6z2Synthetic dataset generation with COCO formatting.    )annotationsN)	dataclass)Path)Literal)Image)Color
Detectionsbox_iou_batchdraw_filled_polygon)tqdmT)frozenc                  J    e Zd ZU dZdZded<   dZded<   dZded<   d	 Zdd
Z	y)DatasetSplitRatiosa,  Dataclass for dataset split ratios.

    Attributes:
        train: Ratio for training set (default: 0.7)
        val: Ratio for validation set (default: 0.2)
        test: Ratio for test set (default: 0.1)

    Raises:
        ValueError: If ratios are negative or sum is not approximately 1.0.
    gffffff?floattraing?val皙?testc                P   | j                   | j                  z   | j                  z   }t        d | j                   | j                  | j                  fD              r2t	        d| j                    d| j                   d| j                         d|cxk  rdk  sn t	        d|       y)	zCValidate that ratios sum to approximately 1.0 and are non-negative.c              3  &   K   | ]	  }|d k    ywr   N ).0rs     d/var/www/ramen.bs-engineer-server.com/venv/lib/python3.12/site-packages/rfdetr/datasets/synthetic.py	<genexpr>z3DatasetSplitRatios.__post_init__.<locals>.<genexpr>0   s     @q1u@   z-Split ratios must be non-negative, got train=z, val=z, test=Gz?)\(?"Split ratios must sum to 1.0, got N)r   r   r   any
ValueError)selftotals     r   __post_init__z DatasetSplitRatios.__post_init__-   s    

TXX%		1@tzz488TYY?@@?

|6RVRZRZQ[[bcgclclbmn  u$$A%IJJ %    c                    | j                   | j                  | j                  dj                         D ci c]  \  }}|dkD  s|| c}}S c c}}w )z1Convert to dictionary, filtering out zero ratios.r   r   r   r   )r   r   r   items)r#   kvs      r   to_dictzDatasetSplitRatios.to_dict7   sF    +/::dhhPTPYPY!Z!`!`!blAfgjkfk1llls   AAN)returndict[str, float])
__name__
__module____qualname____doc__r   __annotations__r   r   r%   r,   r   r&   r   r   r      s3    	 E5CD%Kmr&   r   .c                   t        | t              r| j                         S t        | t              rt	        |       dk(  r| d   | d   d}n5t	        |       dk(  r| d   | d   | d   d}nt        dt	        |              t        d | D              rt        d	|        t        |       }d
|cxk  rdk  sn t        d|       |S t        | t              rdt        d | j                         D              rt        d	|        t        | j                               }d
|cxk  rdk  sn t        d|       | S t        dt        |              )a  Normalize split ratios parameter to a dictionary.

    Args:
        split_ratios: Can be:
            - DatasetSplitRatios dataclass instance
            - Tuple of floats (e.g., (0.7, 0.2, 0.1) for train/val/test)
            - Dictionary (legacy support)

    Returns:
        Dictionary mapping split names to ratios.

    Raises:
        ValueError: If split ratios are invalid.
       r      )r   r      r(   z2Split ratios tuple must have 2 or 3 elements, got c              3  &   K   | ]	  }|d k    ywr   r   )r   ratios     r   r   z*_normalize_split_ratios.<locals>.<genexpr>_   s     3Uuqy3r   z'Split ratios must be non-negative, got r   r   r    c              3  &   K   | ]	  }|d k    ywr   r   )r   values     r   r   z*_normalize_split_ratios.<locals>.<genexpr>h   s     <Uuqy<r   z=split_ratios must be DatasetSplitRatios, tuple, or dict, got )
isinstancer   r,   tuplelenr"   r!   sumdictvalues	TypeErrortype)split_ratiosresultr$   s      r   _normalize_split_ratiosrF   D   sd    , 23##%%,&|!+A|AGF!#+A|AP\]^P_`FQRUVbRcQdeff 3l33F|nUVVL!u$$A%IJJ,%<l&9&9&;<<F|nUVVL'')*u$$A%IJJ
STXYeTfSgh
iir&   )squaretrianglecircle)redgreenblueshapecolorc                   |\  }}|dz  }|dk(  r#||z
  ||z
  }	}||z   ||z   }}
||	g|
|	g|
|g||gg}n|dk(  r5t        |dz        }||d|z  dz  z
  g||z
  ||dz  z   g||z   ||dz  z   gg}n|dk(  r|}d}t        |      D cg c]x  }t        ||t        j                  dt        j                  z  |z  |z        z  z         t        ||t        j
                  dt        j                  z  |z  |z        z  z         gz }}n| g fS t        | t        j                  |t        j                        |	      } |D cg c]  }|D ]  }t        |        }}}| |fS c c}w c c}}w )
u  Draw a geometric shape on an image and return its COCO polygon.

    The polygon is computed first, then used for both rendering and annotation, so the two are always identical.

    Args:
        img: Input image array to draw on.
        shape: Shape to draw (``"square"``, ``"triangle"``, or ``"circle"``).
        color: supervision Color object.
        center: Center position ``(cx, cy)``.
        size: Size of the shape.

    Returns:
        Tuple of ``(image_with_shape, polygon)`` where ``polygon`` is a flat list ``[x1, y1, x2, y2, …]`` suitable for
        the COCO ``segmentation`` field.  Returns an empty polygon list for unknown shape names.
    r5   rG   rH   g      ?r7   rI       dtype)scenepolygonrN   )intrangemathcospisinr   nparrayint32r   )imgrM   rN   centersizecxcy	half_sizex1y1x2y2ptsheightr   n_ptsiptr+   rT   s                       r   draw_synthetic_shaperm   x   s   $ FB	IiiBiiBBx"bB8b"X6	*	TD[!a&jAo%&)^R&A+-.)^R&A+-.

 
(	 5\
 a$((1tww;?U#:;;;<c"q488TUX\X_X_T_bcTcfkTkKlGlBl>mn
 

 Bw
C#RXX1NV[
\C"%2Br2!uQx2x2G2<
 3s   A=E=E"c                    | \  }}}}t        |d      }t        |d      }t        ||      }t        ||      }	||kD  r|	|kD  r||z
  |	|z
  z  }
nd}
||z
  ||z
  z  }|dkD  rd|
|z  z
  S dS )aO  Calculate how much of a bounding box is outside the image boundaries.

    Args:
        bbox: Bounding box in [x_min, y_min, x_max, y_max] format.
        img_size: Size of the image.

    Returns:
        Overlap fraction in ``[0, 1]``: ``0.0`` means the box is fully inside the image; ``1.0`` means it is fully
        outside.
    r           g      ?)maxmin)bboximg_sizex_miny_minx_maxy_maxinside_x_mininside_y_mininside_x_maxinside_y_maxinside_area
total_areas               r   calculate_boundary_overlapr~      s     "&E5%ua=Lua=Luh'Luh'Ll"|l'B#l2|l7RS%-EEM2J/9A~3+
*+F3Fr&   c                :   t        j                  | | dft         j                        dz  }t        t        j                               }t        j                  ||      }	g }
g }g }d}d}t        |	      D ]  }t        j                  t              }t        j                  |      }t        |   }|dk(  rt        j                  |      }n|j                  |      }t        dt        | |z              }t        |dz   t        | |z              }d}t        d	      D ]A  }t        j                  ||      }t        j                  |d
z  | |d
z  z
        }t        j                  |d
z  | |d
z  z
        }t        j                  t        ||d
z  z
        t        ||d
z  z
        t        ||d
z  z         t        ||d
z  z         g      }t!        ||       dkD  rt#        |
      dkD  rPt%        t        j                  |g      t        j                  |
            d   }t        j&                  ||kD        rt)        |||||f|      \  }}t        j*                  |t              j-                  dd
      }t        t        j.                  |dddf               }t        t        j.                  |dddf               }t        t        j                  |dddf               } t        t        j                  |dddf               }!t        j                  ||| |!gt              }"|
j1                  |"       |j1                  |       |j1                  |       d} n |r|dz  }||k\  s n t        j2                  t#        |      t4              }#t7        |      D ]
  \  }$}%|%|#|$<    t9        |
rt        j                  |
      nt        j2                  d      |rt        j                  |      nt        j2                  dt              d|#i      }&||&fS )u  Generate a single synthetic image and its detections.

    Args:
        img_size: Side length of the square output image.
        min_objects: Minimum number of objects to attempt placing.
        max_objects: Maximum number of objects to attempt placing.
        class_mode: ``"shape"`` assigns class IDs by shape type;
            ``"color"`` assigns class IDs by colour.
        min_size_ratio: Minimum object size as a fraction of ``img_size``.
        max_size_ratio: Maximum object size as a fraction of ``img_size``.
        overlap_threshold: Maximum allowed IoU between any two objects before
            a placement attempt is rejected.

    Returns:
        Tuple of ``(image, detections)`` where ``image`` is an ``(img_size, img_size, 3)`` uint8 array and
        ``detections`` is an :class:`Detections` instance whose ``data["polygons"]`` field contains one flat ``[x1,
        y1, x2, y2, …]`` polygon list per detection, matching the geometry returned by :func:`draw_synthetic_shape`.
    r7   rQ      r   rM   
   r6   Fd   r5   g?NT)r      )r   polygons)xyxyclass_iddata)r[   onesuint8listSYNTHETIC_COLORSkeysrandomrandintrV   choiceSYNTHETIC_SHAPESindexrp   rU   r\   r   r~   r>   r
   r!   rm   asarrayreshaperq   appendemptyobject	enumerater	   )'rs   min_objectsmax_objects
class_modemin_size_ratiomax_size_ratiooverlap_thresholdr^   color_namesnum_objectsxyxys	class_idsr   failed_attemptsmax_failed_attempts_rM   
color_namerN   category_idmin_sizemax_sizeplacedobj_sizera   rb   rr   iousrT   polygon_array
poly_x_min
poly_y_min
poly_x_max
poly_y_maxbbox_from_polygonpolygon_datark   poly
detectionss'                                          r   generate_synthetic_sampler      s   6 ''8Xq)
:S
@C',,./K..k:KEI"$HO; 4./]];/
 , *007K%++J7Kr3x.89:x!|SN)B%CDs  	A~~h9HAx(a-/GHBAx(a-/GHB 88rHqL()5hl1B+CU2PX[\P\K\E]_degjruvjvev_wxD *$9D@5zA~$RXXtf%5rxxGJ66$!223/UEB8XVLC JJwe<DDRKMrvvmAqD&9:;JrvvmAqD&9:;JrvvmAqD&9:;JrvvmAqD&9:;J "*j*j)Yaf gLL*+[)OOG$FA 	F q O"55i4l 88C	N&9LX& 4Q  %RXXe_288F+;(1)$rxxC7P,'J
 
?r&   c                   t        |       dk  st        |       dz  dk7  ryt        j                  | t              j	                  dd      }|dddf   }|dddf   }t        d	t        t        j                  |t        j                  |d            t        j                  |t        j                  |d            z
        z        S )
z8Calculate polygon area from COCO-style flat coordinates.   r5   r   ro   rQ   r   Nr6   g      ?)r>   r[   r   r   r   absdotroll)rT   pointsx_coordsy_coordss       r   _calculate_polygon_arear   *  s    
7|a3w<!+q0ZZu-55b!<Fad|Had|Hs266(BGGHb,ABRVVHVXV]V]^fhjVkEllmmnnr&   Fc                b   t        |      t        |      k7  r#t        dt        |       dt        |             t        |      D cg c]  \  }}|dz  dz   |dd }}}g }	g }
d}t        t        ||      d      D ]  \  }\  }}|	j	                  |t        |      j                  ||d       |rp|j                  j                  d	      }|t        d| d| d      t        |      t        |      k  rEt        dt        |       dt        |       d| d| d	      t        j                  dt              }t        t        |            D ]  }d |j                  |   D        \  }}}}||z
  ||z
  }}t        |j                  |         }|dk  s|t        |      k\  r(t        dj!                  ||||t        |                  |dz  dz   }||z  }|rb|t        |      k  r||   nd
}|Ht#        |d      r<t        |      dkD  r.|D cg c]  }t%        |       }}|g}t'        |      }|dkD  r|}ng }ng }|
j	                  |||||||g|d|d       |dz  }  t)        | d      5 }t+        j,                  |	|
|d|       d
d
d
       y
c c}}w c c}w # 1 sw Y   y
xY w)u*  Write a synthetic COCO JSON file.

    Category IDs use sparse 1-based encoding (index * 2 + 1 → 1, 3, 5, …) so synthetic data exercises the same
    ``cat2label`` remapping path that real COCO datasets use.

    Args:
        annotations_path: Destination path for the JSON file.
        classes: Ordered list of class names.
        file_paths: Ordered list of absolute image file paths (one per image).
        detections_list: Detections for each image in the same order.
        img_size: Side length of the square images (width = height = img_size).
        with_segmentation: When ``True`` each annotation includes a
            ``segmentation`` polygon taken from ``detections.data["polygons"]`` (populated by
            :func:`generate_synthetic_sample`).  When ``False`` the field is an empty list.

    Raises:
        ValueError: If ``file_paths`` and ``detections_list`` have different
            lengths.
        ValueError: If ``with_segmentation=True`` and a detections entry has
            no ``"polygons"`` key in its ``data`` dict.
        ValueError: If ``with_segmentation=True`` and the ``"polygons"`` array
            has fewer entries than there are detections for that image.
        ValueError: If any detection has a ``class_id`` outside the range
            ``[0, len(classes))``.
    zBfile_paths and detections_list must have the same length, but got z and r5   r6   	synthetic)idnamesupercategory)start)r   	file_namewidthri   r   NzRwith_segmentation=True but no 'polygons' found in detections.data for image index z (file: )zlwith_segmentation=True requires a polygon entry for every detection (one per detection index), but got only z polygon entries for z detections in image index r   rQ   c              3  2   K   | ]  }t        |        y w)N)r   )r   r+   s     r   r   z#_write_coco_json.<locals>.<genexpr>z  s     I1eAhIs   zInvalid class_id {class_id} for detection index {det_idx} in image index {img_id} (file: {file_path}); expected 0 <= class_id < {num_classes})r   det_idximg_id	file_pathnum_classes__len__ro   )r   image_idr   rr   areaiscrowdsegmentationw)imagesr   
categories)r>   r"   r   zipr   r   r   r   getr[   r   r   rV   r   rU   r   formathasattrr   r   openjsondump) annotations_pathclasses
file_pathsdetections_listrs   with_segmentationidxr   r   images_listannotations_listann_idr   r   r   r   r   rd   re   rf   rg   r   h_boxr   r   annotation_arear   r;   	poly_listr   polygon_areafhs                                    r   _write_coco_jsonr   5  sF   B :#o..:'uS-A,BD
 	

 dmmtcuvV_VY[_q1d[QvJvKF+4S_5U]^+_ A''J!)_11!"		
 %??..z:L# ''-hhykD  < 3z?2 $$'$5#66KCPZOK\ ]&&,XXi[C  88AV4LS_- )	GI
0HINBBBwRuA:..w78H!|x3w<7 ==CV!) '%"+$'L >D >
 
 #Q,*K%iO 07#l:K0K|G,QU#i(@SYQR];? @%u @I @$-;L#:9#EL#c)*6#%L!##  &#.Q.+ $0
 aKFS)	1AF 
	$ j		[9IYcdfhij jQ wd !A,j js   	JJ 6J%%J.i  r6   r   c           	        t        |      }t        |       }	|	j                  dd       |dk(  rt        }
nt	        t
        j                               }
t	        t        |            }t        j                  |       d}t	        |j                               }t        |      D ]2  \  }\  }}|t        |      dz
  k(  rt        |      |z
  }nt        ||z        }|dk(  r|dkD  rd}||||z    }||z  }|sT|	|z  }|j                  dd       |dz  }g }g }t        j                  d| dt        |       d	       t!        |d| d
      D ]u  }t#        ||||      \  }}|dd}t%        ||z        }t'        j(                  |ddddf         j+                  |       |j-                  |       |j-                  |       w t/        ||
||||       5 y)a
  Generate a full synthetic dataset in COCO format.

    Args:
        output_dir: Directory where the dataset will be saved.
        num_images: Total number of images to generate.
        img_size: Size of the square images.
        class_mode: Classification mode - "shape" or "color" (default: "shape").
        min_objects: Minimum objects per image.
        max_objects: Maximum objects per image.
        split_ratios: Dataset split ratios. Can be:
            - SplitRatios dataclass instance (default: 70/20/10 split)
            - Tuple of 2 floats for train/val (e.g., (0.8, 0.2))
            - Tuple of 3 floats for train/val/test (e.g., (0.7, 0.2, 0.1))
            - Dictionary (legacy support, e.g., {"train": 0.7, "val": 0.2, "test": 0.1})
        with_segmentation: If ``True``, include COCO polygon ``segmentation``
            fields derived from the exact geometry of each drawn shape. Requires the COCO dataset reader to be loaded
            with ``include_masks=True`` (i.e. ``args.segmentation_head=True``).
    T)parentsexist_okrM   r   r6   z_annotations.coco.jsonzGenerating z split with z
 images...z split)desc06dz.jpg.Nr   )rF   r   mkdirr   r   r   r   rV   r   shuffler)   r   r>   rU   loggerinfor   r   strr   	fromarraysaver   r   )
output_dir
num_imagesrs   r   r   r   rD   r   split_ratios_dictoutput_pathr   all_indices	start_idxsplit_items	split_idxsplitr9   	num_splitsplit_indices	split_dirr   file_paths_ordereddetections_orderedrk   r^   r   r   r   s                               r   generate_coco_datasetr    s   : 0=z"KdT2W"',,./ uZ()K
NN;I(..01K%.{%; (y!	>E5K(1,,K(94IJ./IA~%!)	#I	I0EFY	  %'	t4$'??(*/1k%S5G4H
STmKwf*EF 	2A7	OC S'II	12I OOCTrT	N+00;%%i0%%j1	2" 	)74FHZ\dfwxQ(yr&   __main__zGenerate synthetic COCO dataset)descriptionz--outputsynthetic_datasetzOutput directory)rC   defaulthelpz--num_imagesr   zTotal number of imagesz
--img_sizezImage size (square)z--modezClassification mode)rC   choicesr
  r  )rD   SplitRatiosTyper-   r.   )r^   
np.ndarrayrM   r   rN   r   r_   ztuple[int, int]r`   rU   r-   ztuple[np.ndarray, list[float]])rr   r  rs   rU   r-   r   )r   g333333?r   )rs   rU   r   rU   r   rU   r   Literal['shape', 'color']r   r   r   r   r   r   r-   ztuple[np.ndarray, Detections])rT   zlist[float]r-   r   )F)r   r   r   	list[str]r   r  r   zlist[Detections]rs   rU   r   boolr-   None)r   r   r   rU   rs   rU   r   r  r   rU   r   rU   rD   r  r   r  r-   r  )9r2   
__future__r   r   loggingrW   r   dataclassesr   pathlibr   typingr   numpyr[   PILr   supervisionr   r	   r
   r   	tqdm.autor   	getLoggerr/   r   r   DEFAULT_SPLIT_RATIOSr=   r   r@   r   r  rF   r   REDGREENBLUEr   rm   r~   r   r   r   r  argparseArgumentParserparseradd_argumentrU   
parse_argsargsoutputr   rs   moder   r&   r   <module>r)     s   9 "     !     M M 			8	$ $m m m@ *+  %uUCZ'884U
;KK+j^ 4  99u{{EJJO -	--(--7F-NQ-#-`G@  "ddd d *	d
 d d d #dNo" $pjpjpj pj &	pj
 pj pj 
pjl ,3$8#UyUyUy Uy *	Uy
 Uy Uy "Uy Uy 
Uyp z$X$$1RSF

6IPbc
S#D\]
3BWX
sWg4FPW^stD$++ttyyQ r&   