
    ^jc                        d dl Z d dlmZ d dlmZ d dlmZmZmZmZ d dl	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 d d	lmZmZ d d
lmZmZ erd dlmZ e e!ef   Z"de#e"   de#e!   fdZ$de#e"   de#e!   de e%e%f   fdZ&de#e!   de#e"   fdZ'de#e"   de e%e#e"   f   fdZ(de#e"   de)e%e%f   dejT                  e
jV                     fdZ,	 d/de#e"   de)e%e%f   de-de-def
dZ.	 	 	 d0dede%de%de/de/d e/de)e#e"   e%f   fd!Z0d"e!de e%e%f   fd#Z1	 	 d1d$e!d"e!d%e-de-de)e#e!   e#e!   e e!ef   f   f
d&Z2d'e e!ef   de-fd(Z3	 	 	 	 	 d2d)d*d+e!de/de/d e/d,e%d-e%de)e%e%f   fd.Z4y)3    N)datetime)Path)TYPE_CHECKINGAnyUnioncast)COCO_RAW_SEGMENTATION)approximate_mask_with_polygonsmap_detections_class_id)
Detections)mask_to_rlepolygon_to_maskrle_to_mask)contains_holescontains_multiple_segments)read_json_filesave_json_file)DetectionDatasetcoco_categoriesreturnc                 J    t        | d       D cg c]  }|d   	 c}S c c}w )Nc                     | d   S )Nid )categorys    k/var/www/ramen.bs-engineer-server.com/venv/lib/python3.12/site-packages/supervision/dataset/formats/coco.py<lambda>z,coco_categories_to_classes.<locals>.<lambda>    s
    Xd^     )keyname)sorted)r   r   s     r   coco_categories_to_classesr"      s1     4ST 	  s    target_classesc                     | D ci c]  }|d   |d    }}t        |      D ci c]  \  }}||   | c}}S c c}w c c}}w )Nr    r   	enumerate)r   r#   r   source_class_to_indextarget_class_indextarget_class_names         r   build_coco_class_index_mappingr*   $   sl     :I-5(4.( 
 6?~5N1 1 	/02DD s   9>classesc                 X    t        |       D cg c]  \  }}|dz   |dd c}}S c c}}w )a  Convert a list of class names to COCO ``categories`` entries.

    Category ids are emitted 1-indexed to comply with the COCO specification
    and tools such as CVAT, which require ``category_id`` values to start at
    ``1``. The id assigned to the class at position ``class_index`` is
    ``class_index + 1``, keeping it consistent with the ``category_id`` written
    by [`detections_to_coco_annotations`](#detections_to_coco_annotations).

    Args:
        classes: Class names ordered by their internal (0-indexed) class id.

    Returns:
        A list of COCO category dictionaries with 1-indexed ``id`` values.

    Examples:
        ```python
        from supervision.dataset.formats.coco import classes_to_coco_categories

        classes_to_coco_categories(classes=["cat", "dog"])
        # [
        #     {"id": 1, "name": "cat", "supercategory": "common-objects"},
        #     {"id": 2, "name": "dog", "supercategory": "common-objects"},
        # ]
        ```
       zcommon-objects)r   r    supercategoryr%   )r+   class_index
class_names      r   classes_to_coco_categoriesr1   0   s?    @ (1'9 $K	 /-	
  s   &coco_annotationsc                 \    i }| D ]$  }|d   }||vrg ||<   ||   j                  |       & |S )Nimage_id)append)r2   annotations
annotationr4   s       r   "group_coco_annotations_by_image_idr8   T   sO     .0K& 1
j);&$&K!H$$Z0	1
 r   image_annotationsresolution_whc                 r   |d   |d   }}t        j                  ||ft              }g }| D ]n  }|j                  d      }|s |j	                  |j                                7|j                  dd      r |j	                  t        |d   |             it        |t              s |j	                  |j                                t        |d   t              r|n|g}|j                         }	|D ]  }
t        j                  t        j                  |
t         j                        d      }|j                  dk(  r+t        j                  d	|j                  d
       dd       v|	t        ||      j!                  t              z  }	 |j	                  |	       q t        j                  |t              S )Nr-   r   dtypesegmentationiscrowdcounts)rler:   )   zISkipping empty polygon while loading COCO segmentation for annotation id=r   .rC   
stacklevel)polygonr:   )npzerosboolgetr5   copyr   
isinstancelistreshapeasarrayint32sizewarningswarnr   astype)r9   r:   heightwidth
empty_maskmasksimage_annotationr>   polygonsobject_maskrG   polygon_arrays               r   coco_annotations_to_masksr^   `   s    "!$mA&6EF(*&%(MJE- %"'++N; LL*+	1-LLX 6mT ,-LL*+#-l1ot#D<<. oo' 	G35::

7"((3W4M !!Q&%%5%9%9$%?$@C 
  ?%]fTlK	" 	[!K%"N ::e4((r   
with_masksuse_iscrowdc                    | st        j                         S | D cg c]  }|d   	 }}| D cg c]  }|d   	 }}t        j                  |t        j                        }|ddddfxx   |ddddf   z  cc<   i }|rc| D cg c]  }|d   	 }	}| D cg c]  }|d	   	 }
}t        t        j                  |	t              t        j                  |
t              
      }|rt        | |      }nWd}t        j                  t        |       t              }t        |       D ]  \  }}|j                  dg       ||<    ||t        <   t        t        j                  |t              |||      S c c}w c c}w c c}w c c}w )a  Convert COCO annotation dicts for a single image into a `Detections` object.

    .. warning::
        The returned ``Detections.class_id`` contains **raw COCO** ``category_id``
        values, not the final 0-indexed internal class ids.  Callers **must** pass
        the result through :func:`map_detections_class_id` with the appropriate
        ``source_to_target_mapping`` (built by
        :func:`build_coco_class_index_mapping`) before the ``class_id`` values are
        meaningful.  Skipping the remap step yields 1-based ids in a field that the
        rest of supervision treats as 0-based.

    Args:
        image_annotations: List of COCO annotation dicts for one image.
        resolution_wh: ``(width, height)`` of the image, used for mask decoding.
        with_masks: Whether to decode segmentation fields into binary masks.
        use_iscrowd: When ``True``, store ``iscrowd`` and ``area`` in
            ``Detections.data``.

    Returns:
        Detections with ``class_id`` set to raw COCO ``category_id`` values.
        Call :func:`map_detections_class_id` on the result before use.
        When ``with_masks=False``, ``detections.data[COCO_RAW_SEGMENTATION]`` is
        populated as an object array (shape ``(N,)``) holding the raw polygon list or
        RLE dict per annotation; consumed by :func:`detections_to_coco_annotations`
        for a coordinate-preserving round-trip.
    category_idbboxr<   NrC      r   r?   area)r?   re   )r9   r:   r>   )class_idxyxymaskdata)r   emptyrH   rP   float32dictintfloatr^   lenobjectr&   rK   r	   )r9   r:   r_   r`   rZ   	class_ids	xyxy_listrg   ri   r?   re   rh   raw_segsk_anns                  r   coco_annotations_to_detectionsrv      s   @ !! AR,<'I  CTT.>!&)TIT$&JJy

$KDAaCLDAaCL LACD@Q
,<Y'
 
 BSS-= (SSJJwc2DPU9V
 (/}
  -/HH!"&-
 !!23 	7GAt((>26HQK	7&."#IS14d A U
 Ts   E2E7E<F
detectionsr4   annotation_idmin_image_area_percentagemax_image_area_percentageapproximation_percentagec           
         g }| D ]p  \  }}}	}
}	}|
t        d      |d   |d   z
  |d   |d   z
  }}g }|t        t        j                  t        j
                     |      }d|v r0t        t	        j                  |d         j                               }n#t        t        |      xs t        |            }|r=t        t        t           t        |d	
            t        |j                  dd       d}nt        ||||      }|r'|D cg c]  }t        |j                                }}nt!        j"                  d| dd       nt        t	        j                  |j%                  dd            j                               }|j%                  t&              }|at)        |      rVt+        |t,              r|}nCt+        |t              r(|r&t+        |d   t        t.        f      st        |      g}nt        |      }t1        t	        j                  |j%                  d||z              j                               }||t        |
      dz   |d   |d   ||g|||d}|j3                  |       |dz  }s ||fS c c}w )a	  Convert `Detections` to COCO ``annotations`` entries.

    The internal 0-indexed ``Detections.class_id`` is serialized as a 1-indexed
    COCO ``category_id`` (``category_id = class_id + 1``). This complies with the
    COCO specification and tools such as CVAT, and stays consistent with the ids
    emitted by [`classes_to_coco_categories`](#classes_to_coco_categories), so a
    detection with internal ``class_id=k`` maps to ``category_id=k + 1``.

    Args:
        detections: The detections to convert. ``class_id`` must not be ``None``.
        image_id: COCO ``image_id`` shared by every produced annotation.
        annotation_id: First annotation id to assign; incremented per detection.
        min_image_area_percentage: Lower bound on detection area / image area,
            used only when approximating masks with polygons.
        max_image_area_percentage: Upper bound on detection area / image area,
            used only when approximating masks with polygons.
        approximation_percentage: Polygon-simplification ratio in ``[0, 1)``.

    Returns:
        A ``(coco_annotations, next_annotation_id)`` tuple, where
        ``next_annotation_id`` is one greater than the last id assigned.

    Raises:
        ValueError: If any detection has ``class_id`` equal to ``None``.

    Note:
        For ``iscrowd=0`` annotations, ``segmentation`` is a
        ``list[list[float]]`` where each inner list encodes one polygon
        part as flat ``[x1, y1, x2, y2, ...]`` coordinates. A single
        object with *N* disjoint parts produces *N* inner lists.

        When ``iscrowd`` is not in ``detections.data``, masks with holes
        or multiple disjoint segments are auto-encoded as RLE
        (``iscrowd=1``); simple single-region masks use polygon format
        (``iscrowd=0``). Supply ``data={"iscrowd": np.array([0])}`` to
        force polygon output regardless of mask topology.

    Examples:
        ```python
        import numpy as np
        from supervision import Detections
        from supervision.dataset.formats.coco import (
            detections_to_coco_annotations,
        )

        detections = Detections(
            xyxy=np.array([[0, 0, 10, 10]], dtype=np.float32),
            class_id=np.array([0], dtype=int),
        )
        annotations, next_id = detections_to_coco_annotations(
            detections=detections, image_id=1, annotation_id=1
        )
        annotations[0]["category_id"]
        # 1
        ```
    Nz1Detections must include class_id for COCO export.rC   r      r-   r?   )rh   F)rh   
compressed)r@   rR   )rh   ry   rz   r{   z5Skipping COCO polygon segmentation for annotation id=z1 because mask approximation returned no polygons.rE   re   )r   r4   rb   rc   re   r>   r?   )
ValueErrorr   nptNDArrayrH   bool_rm   rP   itemr   r   rN   r   shaper
   flattenrS   rT   rK   r	   rJ   rM   rl   tuplern   r5   )rw   r4   rx   ry   rz   r{   r2   rg   rh   _rf   ri   	box_width
box_heightr>   	mask_boolr?   r[   praw_segre   coco_annotations                         r   detections_to_coco_annotationsr      s~   @ (*,6 G(dAxDPQQ $Q$q' 147T!W3D:	GIS[[2D9ID bjji9>>@A"	2 B1yA
 "S	;I%#P !BQ0	  :".G.G-E	 ?G#H!D$5#HL#HMM+_ -00 $%	 "**TXXi%;<AACDG hh45G"tG}gt,#*Lw-&wqzD%=A %)M?L#'=LBJJtxx	J8N'OPUUWX x=1,!Wd1gy*=(
 	0OGP ]**O $Is    I=annotations_pathc                     t        |       }t        |d         }t        |d   |      }|j                         D ci c]  \  }}||
 c}}S c c}}w )ay  
    Generates a mapping from sequential class indices to original COCO class ids.

    This function is essential when working with models that expect class ids to be
    zero-indexed and sequential (0 to 79), as opposed to the original COCO
    dataset where category ids are non-contiguous ranging from 1 to 90 but skipping some
    ids.

    Use Cases:
        - Evaluating models trained with COCO-style annotations where class ids
          are sequential ranging from 0 to 79.
        - Ensuring consistent class indexing across training, inference and evaluation,
          when using different tools or datasets with COCO format.
        - Reproducing results from models that assume sequential class ids (0 to 79).

    How it Works:
        - Reads the COCO annotation file in its original format (`annotations_path`).
        - Extracts and sorts all class names by their original COCO id (1 to 90).
        - Builds a mapping from COCO class ids (not sequential with skipped ids) to
          new class ids (sequential ranging from 0 to 79).
        - Returns a dictionary mapping: `{new_class_id: original_COCO_class_id}`.

    Args:
        annotations_path: Path to COCO JSON annotations file
        (e.g., `instances_val2017.json`).

    Returns:
        A mapping from new class id (sequential ranging from 0 to 79)
        to original COCO class id (1 to 90 with skipped ids).
    
categoriesr   r   r#   )r   r"   r*   items)r   	coco_datar+   class_mappingrt   vs         r   get_coco_class_index_mappingr   e  sY    > /0I(<9PQG2!,/M +0023TQAqD333s   Aimages_directory_pathforce_masksc           
      0   t        |      }t        |d         }t        |d   |      }|d   }t        |d         }g }	i }
t	        |       j                         }|D ]  }|d   |d	   |d
   }}}|j                  |d   g       }t        t	        |       t	        |      z        }	 t	        |      j                         }||k(  rt        d|d| d      ||j                  vrt        d|d| d| d      |j                         rt        d|d| d      |xs t        d |D              }t        |||f||      }t        ||      }|	j                  |       ||
|<   
 ||	|
fS # t        t        f$ r}t        d|d|       |d}~ww xY w)a  
    Load COCO annotations and convert them to `Detections`.

    If `force_masks` is `False`, masks are still loaded for images whose annotations
    include a `segmentation` field. This keeps mask handling consistent with other
    dataset loaders that infer masks from annotation content.

    Args:
        images_directory_path: Path to the image directory.
        annotations_path: Path to COCO JSON annotations.
        force_masks: If `True`, always attempt to load masks.
        use_iscrowd: If `True`, include `iscrowd` and `area` in detection data.

    Returns:
        A tuple of `(classes, image_paths, annotations)`.

    Raises:
        ValueError: If any annotation's ``file_name`` resolves to the images
            directory itself, to a path outside the images directory (e.g. via
            ``../`` traversal or an absolute path), or to a subdirectory instead
            of a regular image file.

    Note:
        Each annotation's ``file_name`` is validated against
        ``images_directory_path`` before loading. Annotations that reference
        paths outside the directory are rejected to prevent path-traversal
        attacks when loading user-supplied annotation files. Symlinked images
        pointing outside the resolved images directory are also rejected.
    	file_pathr   r   r   imagesr6   )r2   	file_namerW   rV   r   z COCO annotation refers to image z", which produces an invalid path: Nz1, which resolves to the images directory itself (z$). Expected a path to an image file.z, which resolves to u"    — outside the images directory rD   z, which resolves to directory z#. Expected a path to an image file.c              3   2   K   | ]  }t        |        y w)N)_with_seg_mask).0r7   s     r   	<genexpr>z(load_coco_annotations.<locals>.<genexpr>  s      (
+5N:&(
s   )r9   r:   r_   r`   )source_to_target_mappingrw   )r   r"   r*   r8   r   resolverK   strOSErrorr   parentsis_diranyrv   r   r5   )r   r   r   r`   r   r+   class_index_mappingcoco_imagescoco_annotations_groupsr   r6   images_directory_resolved
coco_image
image_nameimage_widthimage_heightr9   
image_pathresolved_image_pathexcr_   r7   s                         r   load_coco_annotationsr     sZ   F )9:I(<9PQG8!,/ H%K@"=1 FK $%: ; C C E! 3-
{#wx  ".K

 477
48H"M34tJ7GGH
	"&z"2":":"< ";;2:. A-. /  %,?,G,GG2:. A23 467q: 
 %%'2:. A))<(= >))  ! 
C (
9J(
 %

 4/&5!#	

 -%8!


 	j!",Jg3-j FK''W $ 	2:. A--0E3 	s   (E//F>FFr7   c                 6    t        | j                  d            S )Nr>   )rJ   rK   )r7   s    r   r   r     s    
~.//r   datasetr   annotation_pathstarting_image_idstarting_annotation_idc           	      X   |dk  s|dk  rt        d|d|      t        |      j                  j                  dd       ddddg}g }g }	t	        | j
                  	      }
||}}| D ]  \  }}}|j                  \  }}}t        |      j                   t        |      j                   }|d|||t        j                         j                  d
      d}|	j                  |       t        ||||||      \  }}|j                  |       |dz  } i ||
|	|d}t        ||       ||fS )ul
  Save a DetectionDataset to a COCO-format ``annotations.json`` file.

    Args:
        dataset: The DetectionDataset to write.
        annotation_path: Output path for the COCO ``annotations.json``.
        min_image_area_percentage: Lower bound on detection area / image area;
            used only for segmentation datasets.
        max_image_area_percentage: Upper bound on detection area / image area;
            used only for segmentation datasets.
        approximation_percentage: Polygon-simplification ratio in ``[0, 1)``;
            used only for segmentation datasets.
        starting_image_id: First image id to assign in the exported file.
            Defaults to ``1``. Override when exporting multiple splits into
            a coordinated COCO collection so ids remain unique across the set.
        starting_annotation_id: First annotation id to assign in the exported
            file. Defaults to ``1``. Override for the same multi-split reason
            as ``starting_image_id``.

    Returns:
        A ``(next_image_id, next_annotation_id)`` tuple. The returned values
        are one greater than the highest ids written, so they can be fed
        directly back into ``starting_image_id`` and ``starting_annotation_id``
        when exporting another split into a coordinated COCO collection
        (see ``DetectionDataset.as_coco`` for the chaining pattern). When the
        dataset is empty the starting ids are returned unchanged.

        .. note::
            This function ensures globally unique integer ``id`` values across
            splits. It does **not** ensure unique ``file_name`` values — the
            ``file_name`` field is set to the bare image basename, so splits
            that share filenames (e.g. ``000001.jpg`` in both train and valid)
            will have duplicate ``file_name`` values when their COCO files are
            merged. Use distinct output directories or rename images before
            merging if downstream tools require unique ``file_name`` keys.

    Example:
        ```python
        import supervision as sv
        from supervision.dataset.formats.coco import save_coco_annotations

        ds = sv.DetectionDataset.from_yolo(
            images_directory_path="train/images",
            annotations_directory_path="train/labels",
            data_yaml_path="data.yaml",
        )
        next_img_id, next_ann_id = save_coco_annotations(
            dataset=ds, annotation_path="out/train/annotations.json"
        )
        # next_img_id and next_ann_id are the first unused ids — pass them
        # to the next split to keep ids globally unique across files.
        ```
    r-   ztstarting_image_id and starting_annotation_id must be >= 1 (COCO spec requires 1-indexed ids); got starting_image_id=z, starting_annotation_id=T)r   exist_okz,https://creativecommons.org/licenses/by/4.0/z	CC BY 4.0)r   urlr    )r+   z%m/%d/%Y,%H:%M:%S)r   licenser   rV   rW   date_captured)rw   r4   rx   ry   rz   r{   )infolicensesr   r   r6   r   )r   r   parentmkdirr1   r+   r   stemsuffixr   nowstrftimer5   r   extendr   )r   r   ry   rz   r{   r   r   r   r2   r   r   r4   rx   r   imager7   r   r   r   r   r   r   annotation_dicts                          r   save_coco_annotationsr     s   z 1 6 :&$&&@)?(AC
 	

 	  &&td&C A	
H K0IO/1GmH)0 %
E:',{{$k1Z(--.tJ/?/F/F.GH
#" %\\^445HI

 	:&)G!'&?&?%=*
& 	0A/4 %'O ?o>]""r   )T)              ?g      ?)FT)r   r   r   r-   r-   )5rS   r   pathlibr   typingr   r   r   r   numpyrH   numpy.typingr   supervision.configr	   supervision.dataset.utilsr
   r   supervision.detection.corer   &supervision.detection.utils.convertersr   r   r   !supervision.detection.utils.masksr   r   supervision.utils.filer   r   supervision.dataset.corer   rl   r   CocoDictrN   r"   rm   r*   r1   r8   r   r   r   r^   rJ   rv   rn   r   r   r   r   r   r   r   r   <module>r      s      2 2   4 2 
 Y A9S>X 49 	(^	59#Y		#s(^	!S	 !d8n !H	8n		#tH~
	.)H~.)6;CHo.)[[.)j 	EH~Ec?E E 	E
 EX (+'*&*I+I+I+ I+  %	I+
  %I+ $I+ 4>3I+X$43 $44S> $4T 	h(h(h( h( 	h(
 49d3ic:o!667h(V0tCH~ 0$ 0 (+'*&)"#r#r#r#  %r#  %	r#
 $r# r#  r# 38_r#r   