Skip to content

Reference for ultralytics/solutions/region_counter.py

Note

This file is available at https://github.com/ultralytics/ultralytics/blob/main/ultralytics/solutions/region_counter.py. If you spot a problem please help fix it by contributing a Pull Request 🛠️. Thank you 🙏!


ultralytics.solutions.region_counter.RegionCounter

RegionCounter(**kwargs)

Bases: BaseSolution

A class for real-time counting of objects within user-defined regions in a video stream.

This class inherits from BaseSolution and provides functionality to define polygonal regions in a video frame, track objects, and count those objects that pass through each defined region. Useful for applications requiring counting in specified areas, such as monitoring zones or segmented sections.

Attributes:

Name Type Description
region_template dict

Template for creating new counting regions with default attributes including name, polygon coordinates, and display colors.

counting_regions list

List storing all defined regions, where each entry is based on region_template and includes specific region settings like name, coordinates, and color.

region_counts dict

Dictionary storing the count of objects for each named region.

Methods:

Name Description
add_region

Add a new counting region with specified attributes.

process

Process video frames to count objects in each region.

Examples:

Initialize a RegionCounter and add a counting region

>>> counter = RegionCounter()
>>> counter.add_region("Zone1", [(100, 100), (200, 100), (200, 200), (100, 200)], (255, 0, 0), (255, 255, 255))
>>> results = counter.process(frame)
>>> print(f"Total tracks: {results.total_tracks}")
Source code in ultralytics/solutions/region_counter.py
36
37
38
39
40
41
42
43
44
45
46
47
48
def __init__(self, **kwargs):
    """Initialize the RegionCounter for real-time object counting in user-defined regions."""
    super().__init__(**kwargs)
    self.region_template = {
        "name": "Default Region",
        "polygon": None,
        "counts": 0,
        "dragging": False,
        "region_color": (255, 255, 255),
        "text_color": (0, 0, 0),
    }
    self.region_counts = {}
    self.counting_regions = []

add_region

add_region(name, polygon_points, region_color, text_color)

Add a new region to the counting list based on the provided template with specific attributes.

Parameters:

Name Type Description Default
name str

Name assigned to the new region.

required
polygon_points List[Tuple]

List of (x, y) coordinates defining the region's polygon.

required
region_color tuple

BGR color for region visualization.

required
text_color tuple

BGR color for the text within the region.

required
Source code in ultralytics/solutions/region_counter.py
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
def add_region(self, name, polygon_points, region_color, text_color):
    """
    Add a new region to the counting list based on the provided template with specific attributes.

    Args:
        name (str): Name assigned to the new region.
        polygon_points (List[Tuple]): List of (x, y) coordinates defining the region's polygon.
        region_color (tuple): BGR color for region visualization.
        text_color (tuple): BGR color for the text within the region.
    """
    region = self.region_template.copy()
    region.update(
        {
            "name": name,
            "polygon": self.Polygon(polygon_points),
            "region_color": region_color,
            "text_color": text_color,
        }
    )
    self.counting_regions.append(region)

process

process(im0)

Process the input frame to detect and count objects within each defined region.

Parameters:

Name Type Description Default
im0 ndarray

Input image frame where objects and regions are annotated.

required

Returns:

Type Description
SolutionResults

Contains processed image plot_im, 'total_tracks' (int, total number of tracked objects), and 'region_counts' (dict, counts of objects per region).

Source code in ultralytics/solutions/region_counter.py
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
def process(self, im0):
    """
    Process the input frame to detect and count objects within each defined region.

    Args:
        im0 (np.ndarray): Input image frame where objects and regions are annotated.

    Returns:
        (SolutionResults): Contains processed image `plot_im`, 'total_tracks' (int, total number of tracked objects),
            and 'region_counts' (dict, counts of objects per region).
    """
    self.extract_tracks(im0)
    annotator = SolutionAnnotator(im0, line_width=self.line_width)

    # Ensure self.region is initialized and structured as a dictionary
    if not isinstance(self.region, dict):
        self.region = {"Region#01": self.region or self.initialize_region()}

    # Draw only valid regions
    for idx, (region_name, reg_pts) in enumerate(self.region.items(), start=1):
        color = colors(idx, True)
        annotator.draw_region(reg_pts, color, self.line_width * 2)
        self.add_region(region_name, reg_pts, color, annotator.get_txt_color())

    # Prepare regions for containment check (only process valid ones)
    for region in self.counting_regions:
        if "prepared_polygon" not in region:
            region["prepared_polygon"] = self.prep(region["polygon"])

    # Convert bounding boxes to NumPy array for center points
    boxes_np = np.array([((box[0] + box[2]) / 2, (box[1] + box[3]) / 2) for box in self.boxes], dtype=np.float32)
    points = [self.Point(pt) for pt in boxes_np]  # Convert centers to Point objects

    # Process bounding boxes & check containment
    if points:
        for point, cls, track_id, box, conf in zip(points, self.clss, self.track_ids, self.boxes, self.confs):
            annotator.box_label(box, label=self.adjust_box_label(cls, conf, track_id), color=colors(track_id, True))

            for region in self.counting_regions:
                if region["prepared_polygon"].contains(point):
                    region["counts"] += 1
                    self.region_counts[region["name"]] = region["counts"]

    # Display region counts
    for region in self.counting_regions:
        annotator.text_label(
            region["polygon"].bounds,
            label=str(region["counts"]),
            color=region["region_color"],
            txt_color=region["text_color"],
            margin=self.line_width * 4,
        )
        region["counts"] = 0  # Reset for next frame
    plot_im = annotator.result()
    self.display_output(plot_im)

    return SolutionResults(plot_im=plot_im, total_tracks=len(self.track_ids), region_counts=self.region_counts)





📅 Created 6 months ago ✏️ Updated 6 months ago