A class for defining a polygon-shaped zone within a frame for detecting objects.
Warning
PolygonZone uses the tracker_id. Read
here to learn how to plug
tracking into your inference pipeline.
Attributes:
Name
Type
Description
polygon
ndarray
A polygon represented by a numpy array of shape
(N, 2), containing the x, y coordinates of the points.
triggering_anchors
Iterable[Position]
A list of positions specifying
which anchors of the detections bounding box to consider when deciding on
whether the detection fits within the PolygonZone
(default: (sv.Position.BOTTOM_CENTER,)).
current_count
int
The current count of detected objects within the zone
classPolygonZone:""" A class for defining a polygon-shaped zone within a frame for detecting objects. !!! warning PolygonZone uses the `tracker_id`. Read [here](/latest/trackers/) to learn how to plug tracking into your inference pipeline. Attributes: polygon (np.ndarray): A polygon represented by a numpy array of shape `(N, 2)`, containing the `x`, `y` coordinates of the points. triggering_anchors (Iterable[sv.Position]): A list of positions specifying which anchors of the detections bounding box to consider when deciding on whether the detection fits within the PolygonZone (default: (sv.Position.BOTTOM_CENTER,)). current_count (int): The current count of detected objects within the zone mask (np.ndarray): The 2D bool mask for the polygon zone Example: ```python import supervision as sv from ultralytics import YOLO import numpy as np import cv2 image = cv2.imread(<SOURCE_IMAGE_PATH>) model = YOLO("yolo11s") tracker = sv.ByteTrack() polygon = np.array([[100, 200], [200, 100], [300, 200], [200, 300]]) polygon_zone = sv.PolygonZone(polygon=polygon) result = model.infer(image)[0] detections = sv.Detections.from_ultralytics(result) detections = tracker.update_with_detections(detections) is_detections_in_zone = polygon_zone.trigger(detections) print(polygon_zone.current_count) ``` """def__init__(self,polygon:npt.NDArray[np.int64],triggering_anchors:Iterable[Position]=(Position.BOTTOM_CENTER,),):self.polygon=polygon.astype(int)self.triggering_anchors=triggering_anchorsifnotlist(self.triggering_anchors):raiseValueError("Triggering anchors cannot be empty.")self.current_count=0x_max,y_max=np.max(polygon,axis=0)self.frame_resolution_wh=(x_max+1,y_max+1)self.mask=polygon_to_mask(polygon=polygon,resolution_wh=(x_max+2,y_max+2))deftrigger(self,detections:Detections)->npt.NDArray[np.bool_]:""" Determines if the detections are within the polygon zone. Parameters: detections (Detections): The detections to be checked against the polygon zone Returns: np.ndarray: A boolean numpy array indicating if each detection is within the polygon zone """clipped_xyxy=clip_boxes(xyxy=detections.xyxy,resolution_wh=self.frame_resolution_wh)clipped_detections=replace(detections,xyxy=clipped_xyxy)all_clipped_anchors=np.array([np.ceil(clipped_detections.get_anchors_coordinates(anchor)).astype(int)foranchorinself.triggering_anchors])is_in_zone:npt.NDArray[np.bool_]=(self.mask[all_clipped_anchors[:,:,1],all_clipped_anchors[:,:,0]].transpose().astype(bool))is_in_zone:npt.NDArray[np.bool_]=np.all(is_in_zone,axis=1)self.current_count=int(np.sum(is_in_zone))returnis_in_zone.astype(bool)
deftrigger(self,detections:Detections)->npt.NDArray[np.bool_]:""" Determines if the detections are within the polygon zone. Parameters: detections (Detections): The detections to be checked against the polygon zone Returns: np.ndarray: A boolean numpy array indicating if each detection is within the polygon zone """clipped_xyxy=clip_boxes(xyxy=detections.xyxy,resolution_wh=self.frame_resolution_wh)clipped_detections=replace(detections,xyxy=clipped_xyxy)all_clipped_anchors=np.array([np.ceil(clipped_detections.get_anchors_coordinates(anchor)).astype(int)foranchorinself.triggering_anchors])is_in_zone:npt.NDArray[np.bool_]=(self.mask[all_clipped_anchors[:,:,1],all_clipped_anchors[:,:,0]].transpose().astype(bool))is_in_zone:npt.NDArray[np.bool_]=np.all(is_in_zone,axis=1)self.current_count=int(np.sum(is_in_zone))returnis_in_zone.astype(bool)
PolygonZoneAnnotator
A class for annotating a polygon-shaped zone within a
frame with a count of detected objects.
classPolygonZoneAnnotator:""" A class for annotating a polygon-shaped zone within a frame with a count of detected objects. Attributes: zone (PolygonZone): The polygon zone to be annotated color (Color): The color to draw the polygon lines, default is white thickness (int): The thickness of the polygon lines, default is 2 text_color (Color): The color of the text on the polygon, default is black text_scale (float): The scale of the text on the polygon, default is 0.5 text_thickness (int): The thickness of the text on the polygon, default is 1 text_padding (int): The padding around the text on the polygon, default is 10 font (int): The font type for the text on the polygon, default is cv2.FONT_HERSHEY_SIMPLEX center (Tuple[int, int]): The center of the polygon for text placement display_in_zone_count (bool): Show the label of the zone or not. Default is True opacity: The opacity of zone filling when drawn on the scene. Default is 0 """def__init__(self,zone:PolygonZone,color:Color=Color.WHITE,thickness:int=2,text_color:Color=Color.BLACK,text_scale:float=0.5,text_thickness:int=1,text_padding:int=10,display_in_zone_count:bool=True,opacity:float=0,):self.zone=zoneself.color=colorself.thickness=thicknessself.text_color=text_colorself.text_scale=text_scaleself.text_thickness=text_thicknessself.text_padding=text_paddingself.font=cv2.FONT_HERSHEY_SIMPLEXself.center=get_polygon_center(polygon=zone.polygon)self.display_in_zone_count=display_in_zone_countself.opacity=opacitydefannotate(self,scene:np.ndarray,label:Optional[str]=None)->np.ndarray:""" Annotates the polygon zone within a frame with a count of detected objects. Parameters: scene (np.ndarray): The image on which the polygon zone will be annotated label (Optional[str]): A label for the count of detected objects within the polygon zone (default: None) Returns: np.ndarray: The image with the polygon zone and count of detected objects """ifself.opacity==0:annotated_frame=draw_polygon(scene=scene,polygon=self.zone.polygon,color=self.color,thickness=self.thickness,)else:annotated_frame=draw_filled_polygon(scene=scene.copy(),polygon=self.zone.polygon,color=self.color,opacity=self.opacity,)annotated_frame=draw_polygon(scene=annotated_frame,polygon=self.zone.polygon,color=self.color,thickness=self.thickness,)ifself.display_in_zone_count:annotated_frame=draw_text(scene=annotated_frame,text=str(self.zone.current_count)iflabelisNoneelselabel,text_anchor=self.center,background_color=self.color,text_color=self.text_color,text_scale=self.text_scale,text_thickness=self.text_thickness,text_padding=self.text_padding,text_font=self.font,)returnannotated_frame
defannotate(self,scene:np.ndarray,label:Optional[str]=None)->np.ndarray:""" Annotates the polygon zone within a frame with a count of detected objects. Parameters: scene (np.ndarray): The image on which the polygon zone will be annotated label (Optional[str]): A label for the count of detected objects within the polygon zone (default: None) Returns: np.ndarray: The image with the polygon zone and count of detected objects """ifself.opacity==0:annotated_frame=draw_polygon(scene=scene,polygon=self.zone.polygon,color=self.color,thickness=self.thickness,)else:annotated_frame=draw_filled_polygon(scene=scene.copy(),polygon=self.zone.polygon,color=self.color,opacity=self.opacity,)annotated_frame=draw_polygon(scene=annotated_frame,polygon=self.zone.polygon,color=self.color,thickness=self.thickness,)ifself.display_in_zone_count:annotated_frame=draw_text(scene=annotated_frame,text=str(self.zone.current_count)iflabelisNoneelselabel,text_anchor=self.center,background_color=self.color,text_color=self.text_color,text_scale=self.text_scale,text_thickness=self.text_thickness,text_padding=self.text_padding,text_font=self.font,)returnannotated_frame