Anchors Annotator
Draw anchor points on detected objects to visualize trigger positions for zones and crossings.
Overview
The anchors() annotator draws small circles at specific anchor positions on each detection's bounding box. These anchor points are the same positions used by the zone and crossing trigger systems to determine if an object is inside a zone or has crossed a line. This is useful for debugging trigger strategies and understanding detection behavior.
pf.annotators.anchors(image, detections)
Function Signature
def anchors( image: np.ndarray, detections: Detections, strategy: Union[str, List[str]] = None, radius: Optional[int] = None, thickness: Optional[int] = None, colors: Optional[List[tuple]] = None) -> np.ndarray
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| image | np.ndarray | required | Input image in BGR format. Modified in-place. |
| detections | Detections | required | PixelFlow detections with bounding boxes. |
| strategy | str, List[str], or None | None | Which anchor(s) to draw. None = all 9 anchors. |
| radius | int or None | None | Circle radius in pixels. None = auto-adapt. |
| thickness | int or None | None | Circle outline thickness. None = -1 (filled). |
| colors | List[tuple] or None | None | List of BGR colors. None = use default palette. |
Returns:np.ndarray - The input image with anchor points drawn (same array, modified in-place).
Basic Usage
import cv2import pixelflow as pffrom ultralytics import YOLO# Load image and run detectionimage = cv2.imread("pedestrians.jpg")model = YOLO("yolo11n.pt")results = model.predict(image)detections = pf.from_ultralytics(results)# Draw all anchor points (9 per detection)image = pf.annotators.box(image, detections)image = pf.annotators.anchors(image, detections)cv2.imshow("Result", image)cv2.waitKey(0)
Anchor Positions
There are 9 anchor positions available on each bounding box:
┌─────────────────────────────────────┐│ top_left top_center top_right ││ ● ● ● ││ ││ left_center center right_center││ ● ● ● ││ ││bottom_left bottom_center bottom_right│ ● ● ● │└─────────────────────────────────────┘
| Strategy | Position | Common Use Case |
|---|---|---|
| center | Center of bbox | General object location |
| bottom_center | Bottom center edge | Pedestrian ground position |
| top_left | Top-left corner | Corner-based triggers |
| top_right | Top-right corner | Corner-based triggers |
| bottom_left | Bottom-left corner | Vehicle wheel position |
| bottom_right | Bottom-right corner | Vehicle wheel position |
| top_center | Top center edge | Head position tracking |
| left_center | Left center edge | Side-based triggers |
| right_center | Right center edge | Side-based triggers |
Strategy Selection
Single Anchor Point
# Draw only center pointsimage = pf.annotators.anchors(image, detections, strategy="center")# Draw only bottom center (common for pedestrians)image = pf.annotators.anchors(image, detections, strategy="bottom_center")
Multiple Anchor Points
# Draw all four cornerscorners = ["top_left", "top_right", "bottom_left", "bottom_right"]image = pf.annotators.anchors(image, detections, strategy=corners)# Draw center and bottom centerimage = pf.annotators.anchors(image, detections, strategy=["center", "bottom_center"])
All Anchor Points (Default)
# Draw all 9 anchor points (default when strategy=None)image = pf.annotators.anchors(image, detections)
Styling Options
Circle Radius
# Small dotsimage = pf.annotators.anchors(image, detections, radius=3)# Large circlesimage = pf.annotators.anchors(image, detections, radius=10)
Filled vs Outline
# Filled circles (default)image = pf.annotators.anchors(image, detections, thickness=-1)# Outline circlesimage = pf.annotators.anchors(image, detections, thickness=2)
Custom Colors
# Single color for all anchorsimage = pf.annotators.anchors( image, detections, strategy="center", colors=[(0, 255, 0)] # Green)# Multiple colors per classcustom_colors = [(0, 255, 0), (0, 0, 255), (255, 0, 0)]image = pf.annotators.anchors(image, detections, colors=custom_colors)
Common Patterns
Debug Zone Triggers
Visualize which anchor point is being used for zone detection:
# Zone uses bottom_center trigger strategyzones = pf.Zones()zones.add_zone(polygon, trigger_strategy="bottom_center")# Visualize the trigger pointimage = pf.annotators.box(image, detections)image = pf.annotators.anchors(image, detections, strategy="bottom_center")image = pf.annotators.zones(image, zones)
Debug Line Crossings
# Crossing uses center triggercrossings = pf.Crossings()crossings.add_crossing(start, end, triggering_anchor="center")# Visualize the trigger pointimage = pf.annotators.box(image, detections)image = pf.annotators.anchors(image, detections, strategy="center")image = pf.annotators.crossings(image, crossings)
Pedestrian Ground Position
# Show where pedestrians touch the groundimage = pf.annotators.box(image, detections)image = pf.annotators.anchors( image, detections, strategy="bottom_center", radius=5, colors=[(0, 255, 255)] # Cyan dots)
Compare Multiple Strategies
# Compare center vs bottom_center visuallyimage1 = image.copy()image2 = image.copy()pf.annotators.box(image1, detections)pf.annotators.anchors(image1, detections, strategy="center")pf.annotators.box(image2, detections)pf.annotators.anchors(image2, detections, strategy="bottom_center")
Notes
-
In-place modification: The input image is modified directly. Use
image.copy()if you need the original preserved. - Adaptive sizing: Radius automatically scales with image size when not specified.
-
Filled by default: Uses
thickness=-1for filled circles unless specified otherwise. - Error handling: Invalid strategy strings are skipped gracefully without raising errors.
- Zone/Crossing sync: Use the same strategy here as in your zone or crossing configuration to visualize trigger points accurately.
See Also
-
zones()- Draw zone boundaries -
crossings()- Draw crossing lines -
box()- Draw bounding boxes -
Zones.add_zone()- Configure zone trigger strategies