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

Code before:
            detections (Detections): Object detections to annotate.
            custom_color_lookup (Optional[np.ndarray]): Custom color lookup array.
                Allows to override the default color mapping strategy.

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

        Example:
            ```python
            import supervision as sv

            image = ...
            detections = sv.Detections(...)

            triangle_annotator = sv.TriangleAnnotator()
            annotated_frame = triangle_annotator.annotate(
                scene=image.copy(),
                detections=detections
            )
            ```

        ![triangle-annotator-example](https://media.roboflow.com/
        supervision-annotator-examples/triangle-annotator-example.png)
        """
        if self.outline_thickness:
            for detection_idx in range(len(detections)):
                x1, y1, x2, y2 = detections.xyxy[detection_idx].astype(int)
                color = resolve_color(
                    color=self.color,
                    detections=detections,
                    detection_idx=detection_idx,
                    color_lookup=self.color_lookup
                    if custom_color_lookup is None
                    else custom_color_lookup,
                )

                midpoint_top = (
                    (x1 + x2) // 2,
                    (y1 + y1) // 2,
                )  # midpoint((x1, y1), (x2, y1))

                # shifted origin/centroid
                cen2 = (midpoint_top[0], midpoint_top[1] - 18)
                tri_vertices = np.array(
                    [
                        [cen2[0], cen2[1] + 12],
                        [cen2[0] - 10, cen2[1] - 10],
                        [cen2[0] + 10, cen2[1] - 10],
                    ]
                )

Review comment (performance):
This is a lot of logic for a small change.

A more efficient method involve using `cv2.polylines`.
There you can specify thickness and draw another shape behind the original triangle.

I wouldn't expect to have two very different if-else branches.

Code after:
        Annotates the given scene with triangles based on the provided detections.

        Args:
            scene (ImageType): The image where triangles will be drawn.
                `ImageType` is a flexible type, accepting either `numpy.ndarray`
                or `PIL.Image.Image`.
            detections (Detections): Object detections to annotate.
            custom_color_lookup (Optional[np.ndarray]): Custom color lookup array.
                Allows to override the default color mapping strategy.

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

        Example:
            ```python
            import supervision as sv

            image = ...
            detections = sv.Detections(...)

            triangle_annotator = sv.TriangleAnnotator()
            annotated_frame = triangle_annotator.annotate(
                scene=image.copy(),
                detections=detections
            )
            ```

        ![triangle-annotator-example](https://media.roboflow.com/
        supervision-annotator-examples/triangle-annotator-example.png)
        """
        xy = detections.get_anchors_coordinates(anchor=self.position)
        for detection_idx in range(len(detections)):
            color = resolve_color(
                color=self.color,
                detections=detections,
                detection_idx=detection_idx,
                color_lookup=self.color_lookup
                if custom_color_lookup is None
                else custom_color_lookup,
            )
            tip_x, tip_y = int(xy[detection_idx, 0]), int(xy[detection_idx, 1])
            vertices = np.array(
                [
                    [tip_x - self.base // 2, tip_y - self.height],
                    [tip_x + self.base // 2, tip_y - self.height],
                    [tip_x, tip_y],
                ],
                np.int32,
            )