Repository: roboflow/supervision
File: supervision/keypoint/annotators.py (Python)

Code before:
        )[0]
        center_x, center_y = center_coordinates
        return (
            center_x - text_w // 2,
            center_y - text_h // 2,
            center_x + text_w // 2,
            center_y + text_h // 2,
        )

    def annotate(
        self, scene: ImageType, key_points: KeyPoints, labels: List[str] = None
    ) -> ImageType:
        font = cv2.FONT_HERSHEY_SIMPLEX

        N, K, _ = key_points.xy.shape

        if N == 0:
            return scene

        anchors = key_points.xy.reshape(K * N, 2).astype(int)
        colors = (
            np.array(self.color * N)
            if isinstance(self.color, list)
            else np.array([self.color] * K * N)
        )
        labels = np.array(labels * N)

        mask = np.all(anchors != 0, axis=1)

        if np.all(mask == False):
            return scene

        anchors = anchors[mask]
        colors = colors[mask]
        labels = labels[mask]

        xyxy = np.array(
            [
                self.get_text_bounding_box(
                    text=label,
                    font=font,
                    text_scale=self.text_scale,
                    text_thickness=self.text_thickness,
                    center_coordinates=tuple(anchor),
                )
                for anchor, label in zip(anchors, labels)
            ]
        )

        xyxy_padded = pad_boxes(xyxy=xyxy, px=self.text_padding)


Review comment (bug):
if labels are `None`, this fails with `TypeError: unsupported operand type(s) for *: 'NoneType' and 'int'`

Something basic would work, for example:
```
if labels is None:
    labels = [str(i) for i in range(K)]
```

I've checked - it produces the correct COCO IDs for both ultralytics and inference.

Code after:
        self.color: Union[Color, List[Color]] = color
        self.text_color: Color = text_color
        self.text_scale: float = text_scale
        self.text_thickness: int = text_thickness
        self.text_padding: int = text_padding

    def annotate(
        self, scene: ImageType, key_points: KeyPoints, labels: List[str] = None
    ) -> ImageType:
        """
        A class that draws labels of skeleton vertices on images. It uses specified key
            points to determine the locations where the vertices should be drawn.

        Args:
            scene (ImageType): The image where vertex labels will be drawn. `ImageType`
                is a flexible type, accepting either `numpy.ndarray` or
                `PIL.Image.Image`.
            key_points (KeyPoints): A collection of key points where each key point
                consists of x and y coordinates.
            labels (List[str], optional): A list of labels to be displayed on the
                annotated image. If not provided, keypoint indices will be used.

        Returns:
            The annotated image, matching the type of `scene` (`numpy.ndarray`
                or `PIL.Image.Image`)

        Example:
            ```python
            import supervision as sv

            image = ...
            key_points = sv.KeyPoints(...)

            vertex_label_annotator = sv.VertexLabelAnnotator(
                color=sv.Color.GREEN,
                text_color=sv.Color.BLACK,
                border_radius=5
            )
            annotated_frame = vertex_label_annotator.annotate(
                scene=image.copy(),
                key_points=key_points
            )
            ```

        ![vertex-label-annotator-example](https://media.roboflow.com/
        supervision-annotator-examples/vertex-label-annotator-example.png)

        !!! tip

            `VertexLabelAnnotator` allows to customize the color of each keypoint label
            values.