ultralytics 8.3.11__py3-none-any.whl → 8.3.13__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ultralytics might be problematic. Click here for more details.

@@ -1,6 +1,5 @@
1
1
  # Ultralytics YOLO 🚀, AGPL-3.0 license
2
2
 
3
- import warnings
4
3
  from itertools import cycle
5
4
 
6
5
  import cv2
@@ -9,299 +8,187 @@ import numpy as np
9
8
  from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
10
9
  from matplotlib.figure import Figure
11
10
 
11
+ from ultralytics.solutions.solutions import BaseSolution # Import a parent class
12
12
 
13
- class Analytics:
13
+
14
+ class Analytics(BaseSolution):
14
15
  """A class to create and update various types of charts (line, bar, pie, area) for visual analytics."""
15
16
 
16
- def __init__(
17
- self,
18
- type,
19
- writer,
20
- im0_shape,
21
- title="ultralytics",
22
- x_label="x",
23
- y_label="y",
24
- bg_color="white",
25
- fg_color="black",
26
- line_color="yellow",
27
- line_width=2,
28
- points_width=10,
29
- fontsize=13,
30
- view_img=False,
31
- save_img=True,
32
- max_points=50,
33
- ):
34
- """
35
- Initialize the Analytics class with various chart types.
17
+ def __init__(self, **kwargs):
18
+ """Initialize the Analytics class with various chart types."""
19
+ super().__init__(**kwargs)
36
20
 
37
- Args:
38
- type (str): Type of chart to initialize ('line', 'bar', 'pie', or 'area').
39
- writer (object): Video writer object to save the frames.
40
- im0_shape (tuple): Shape of the input image (width, height).
41
- title (str): Title of the chart.
42
- x_label (str): Label for the x-axis.
43
- y_label (str): Label for the y-axis.
44
- bg_color (str): Background color of the chart.
45
- fg_color (str): Foreground (text) color of the chart.
46
- line_color (str): Line color for line charts.
47
- line_width (int): Width of the lines in line charts.
48
- points_width (int): Width of line points highlighter
49
- fontsize (int): Font size for chart text.
50
- view_img (bool): Whether to display the image.
51
- save_img (bool): Whether to save the image.
52
- max_points (int): Specifies when to remove the oldest points in a graph for multiple lines.
53
- """
54
- self.bg_color = bg_color
55
- self.fg_color = fg_color
56
- self.view_img = view_img
57
- self.save_img = save_img
58
- self.title = title
59
- self.writer = writer
60
- self.max_points = max_points
61
- self.line_color = line_color
62
- self.x_label = x_label
63
- self.y_label = y_label
64
- self.points_width = points_width
65
- self.line_width = line_width
66
- self.fontsize = fontsize
21
+ self.type = self.CFG["analytics_type"] # extract type of analytics
22
+ self.x_label = "Classes" if self.type in {"bar", "pie"} else "Frame#"
23
+ self.y_label = "Total Counts"
24
+
25
+ # Predefined data
26
+ self.bg_color = "#00F344" # background color of frame
27
+ self.fg_color = "#111E68" # foreground color of frame
28
+ self.title = "Ultralytics Solutions" # window name
29
+ self.max_points = 45 # maximum points to be drawn on window
30
+ self.fontsize = 25 # text font size for display
31
+ figsize = (19.2, 10.8) # Set output image size 1920 * 1080
32
+ self.color_cycle = cycle(["#DD00BA", "#042AFF", "#FF4447", "#7D24FF", "#BD00FF"])
67
33
 
68
- # Set figure size based on image shape
69
- figsize = (im0_shape[0] / 100, im0_shape[1] / 100)
34
+ self.total_counts = 0 # count variable for storing total counts i.e for line
35
+ self.clswise_count = {} # dictionary for classwise counts
70
36
 
71
- if type in {"line", "area"}:
72
- # Initialize line or area plot
37
+ # Ensure line and area chart
38
+ if self.type in {"line", "area"}:
73
39
  self.lines = {}
74
40
  self.fig = Figure(facecolor=self.bg_color, figsize=figsize)
75
- self.canvas = FigureCanvas(self.fig)
41
+ self.canvas = FigureCanvas(self.fig) # Set common axis properties
76
42
  self.ax = self.fig.add_subplot(111, facecolor=self.bg_color)
77
- if type == "line":
78
- (self.line,) = self.ax.plot([], [], color=self.line_color, linewidth=self.line_width)
79
-
80
- elif type in {"bar", "pie"}:
43
+ if self.type == "line":
44
+ (self.line,) = self.ax.plot([], [], color="cyan", linewidth=self.line_width)
45
+ elif self.type in {"bar", "pie"}:
81
46
  # Initialize bar or pie plot
82
47
  self.fig, self.ax = plt.subplots(figsize=figsize, facecolor=self.bg_color)
48
+ self.canvas = FigureCanvas(self.fig) # Set common axis properties
83
49
  self.ax.set_facecolor(self.bg_color)
84
- color_palette = [
85
- (31, 119, 180),
86
- (255, 127, 14),
87
- (44, 160, 44),
88
- (214, 39, 40),
89
- (148, 103, 189),
90
- (140, 86, 75),
91
- (227, 119, 194),
92
- (127, 127, 127),
93
- (188, 189, 34),
94
- (23, 190, 207),
95
- ]
96
- self.color_palette = [(r / 255, g / 255, b / 255, 1) for r, g, b in color_palette]
97
- self.color_cycle = cycle(self.color_palette)
98
50
  self.color_mapping = {}
51
+ self.ax.axis("equal") if type == "pie" else None # Ensure pie chart is circular
99
52
 
100
- # Ensure pie chart is circular
101
- self.ax.axis("equal") if type == "pie" else None
102
-
103
- # Set common axis properties
104
- self.ax.set_title(self.title, color=self.fg_color, fontsize=self.fontsize)
105
- self.ax.set_xlabel(x_label, color=self.fg_color, fontsize=self.fontsize - 3)
106
- self.ax.set_ylabel(y_label, color=self.fg_color, fontsize=self.fontsize - 3)
107
- self.ax.tick_params(axis="both", colors=self.fg_color)
53
+ def process_data(self, im0, frame_number):
54
+ """
55
+ Process the image data, run object tracking.
108
56
 
109
- def update_area(self, frame_number, counts_dict):
57
+ Args:
58
+ im0 (ndarray): Input image for processing.
59
+ frame_number (int): Video frame # for plotting the data.
60
+ """
61
+ self.extract_tracks(im0) # Extract tracks
62
+
63
+ if self.type == "line":
64
+ for box in self.boxes:
65
+ self.total_counts += 1
66
+ im0 = self.update_graph(frame_number=frame_number)
67
+ self.total_counts = 0
68
+ elif self.type == "pie" or self.type == "bar" or self.type == "area":
69
+ self.clswise_count = {}
70
+ for box, cls in zip(self.boxes, self.clss):
71
+ if self.names[int(cls)] in self.clswise_count:
72
+ self.clswise_count[self.names[int(cls)]] += 1
73
+ else:
74
+ self.clswise_count[self.names[int(cls)]] = 1
75
+ im0 = self.update_graph(frame_number=frame_number, count_dict=self.clswise_count, plot=self.type)
76
+ else:
77
+ raise ModuleNotFoundError(f"{self.type} chart is not supported ❌")
78
+ return im0
79
+
80
+ def update_graph(self, frame_number, count_dict=None, plot="line"):
110
81
  """
111
- Update the area graph with new data for multiple classes.
82
+ Update the graph (line or area) with new data for single or multiple classes.
112
83
 
113
84
  Args:
114
85
  frame_number (int): The current frame number.
115
- counts_dict (dict): Dictionary with class names as keys and counts as values.
86
+ count_dict (dict, optional): Dictionary with class names as keys and counts as values for multiple classes.
87
+ If None, updates a single line graph.
88
+ plot (str): Type of the plot i.e. line, bar or area.
116
89
  """
117
- x_data = np.array([])
118
- y_data_dict = {key: np.array([]) for key in counts_dict.keys()}
119
-
120
- if self.ax.lines:
121
- x_data = self.ax.lines[0].get_xdata()
122
- for line, key in zip(self.ax.lines, counts_dict.keys()):
123
- y_data_dict[key] = line.get_ydata()
124
-
125
- x_data = np.append(x_data, float(frame_number))
126
- max_length = len(x_data)
127
-
128
- for key in counts_dict.keys():
129
- y_data_dict[key] = np.append(y_data_dict[key], float(counts_dict[key]))
130
- if len(y_data_dict[key]) < max_length:
131
- y_data_dict[key] = np.pad(y_data_dict[key], (0, max_length - len(y_data_dict[key])), "constant")
132
-
133
- # Remove the oldest points if the number of points exceeds max_points
134
- if len(x_data) > self.max_points:
135
- x_data = x_data[1:]
136
- for key in counts_dict.keys():
137
- y_data_dict[key] = y_data_dict[key][1:]
138
-
139
- self.ax.clear()
140
-
141
- colors = ["#E1FF25", "#0BDBEB", "#FF64DA", "#111F68", "#042AFF"]
142
- color_cycle = cycle(colors)
143
-
144
- for key, y_data in y_data_dict.items():
145
- color = next(color_cycle)
146
- self.ax.fill_between(x_data, y_data, color=color, alpha=0.6)
147
- self.ax.plot(
148
- x_data,
149
- y_data,
150
- color=color,
151
- linewidth=self.line_width,
152
- marker="o",
153
- markersize=self.points_width,
154
- label=f"{key} Data Points",
155
- )
156
-
90
+ if count_dict is None:
91
+ # Single line update
92
+ x_data = np.append(self.line.get_xdata(), float(frame_number))
93
+ y_data = np.append(self.line.get_ydata(), float(self.total_counts))
94
+
95
+ if len(x_data) > self.max_points:
96
+ x_data, y_data = x_data[-self.max_points :], y_data[-self.max_points :]
97
+
98
+ self.line.set_data(x_data, y_data)
99
+ self.line.set_label("Counts")
100
+ self.line.set_color("#7b0068") # Pink color
101
+ self.line.set_marker("*")
102
+ self.line.set_markersize(self.line_width * 5)
103
+ else:
104
+ labels = list(count_dict.keys())
105
+ counts = list(count_dict.values())
106
+ if plot == "area":
107
+ color_cycle = cycle(["#DD00BA", "#042AFF", "#FF4447", "#7D24FF", "#BD00FF"])
108
+ # Multiple lines or area update
109
+ x_data = self.ax.lines[0].get_xdata() if self.ax.lines else np.array([])
110
+ y_data_dict = {key: np.array([]) for key in count_dict.keys()}
111
+ if self.ax.lines:
112
+ for line, key in zip(self.ax.lines, count_dict.keys()):
113
+ y_data_dict[key] = line.get_ydata()
114
+
115
+ x_data = np.append(x_data, float(frame_number))
116
+ max_length = len(x_data)
117
+ for key in count_dict.keys():
118
+ y_data_dict[key] = np.append(y_data_dict[key], float(count_dict[key]))
119
+ if len(y_data_dict[key]) < max_length:
120
+ y_data_dict[key] = np.pad(y_data_dict[key], (0, max_length - len(y_data_dict[key])), "constant")
121
+ if len(x_data) > self.max_points:
122
+ x_data = x_data[1:]
123
+ for key in count_dict.keys():
124
+ y_data_dict[key] = y_data_dict[key][1:]
125
+
126
+ self.ax.clear()
127
+ for key, y_data in y_data_dict.items():
128
+ color = next(color_cycle)
129
+ self.ax.fill_between(x_data, y_data, color=color, alpha=0.7)
130
+ self.ax.plot(
131
+ x_data,
132
+ y_data,
133
+ color=color,
134
+ linewidth=self.line_width,
135
+ marker="o",
136
+ markersize=self.line_width * 5,
137
+ label=f"{key} Data Points",
138
+ )
139
+ if plot == "bar":
140
+ self.ax.clear() # clear bar data
141
+ for label in labels: # Map labels to colors
142
+ if label not in self.color_mapping:
143
+ self.color_mapping[label] = next(self.color_cycle)
144
+ colors = [self.color_mapping[label] for label in labels]
145
+ bars = self.ax.bar(labels, counts, color=colors)
146
+ for bar, count in zip(bars, counts):
147
+ self.ax.text(
148
+ bar.get_x() + bar.get_width() / 2,
149
+ bar.get_height(),
150
+ str(count),
151
+ ha="center",
152
+ va="bottom",
153
+ color=self.fg_color,
154
+ )
155
+ # Create the legend using labels from the bars
156
+ for bar, label in zip(bars, labels):
157
+ bar.set_label(label) # Assign label to each bar
158
+ self.ax.legend(loc="upper left", fontsize=13, facecolor=self.fg_color, edgecolor=self.fg_color)
159
+ if plot == "pie":
160
+ total = sum(counts)
161
+ percentages = [size / total * 100 for size in counts]
162
+ start_angle = 90
163
+ self.ax.clear()
164
+
165
+ # Create pie chart and create legend labels with percentages
166
+ wedges, autotexts = self.ax.pie(
167
+ counts, labels=labels, startangle=start_angle, textprops={"color": self.fg_color}, autopct=None
168
+ )
169
+ legend_labels = [f"{label} ({percentage:.1f}%)" for label, percentage in zip(labels, percentages)]
170
+
171
+ # Assign the legend using the wedges and manually created labels
172
+ self.ax.legend(wedges, legend_labels, title="Classes", loc="center left", bbox_to_anchor=(1, 0, 0.5, 1))
173
+ self.fig.subplots_adjust(left=0.1, right=0.75) # Adjust layout to fit the legend
174
+
175
+ # Common plot settings
176
+ self.ax.set_facecolor("#f0f0f0") # Set to light gray or any other color you like
157
177
  self.ax.set_title(self.title, color=self.fg_color, fontsize=self.fontsize)
158
178
  self.ax.set_xlabel(self.x_label, color=self.fg_color, fontsize=self.fontsize - 3)
159
179
  self.ax.set_ylabel(self.y_label, color=self.fg_color, fontsize=self.fontsize - 3)
160
- legend = self.ax.legend(loc="upper left", fontsize=13, facecolor=self.bg_color, edgecolor=self.fg_color)
161
180
 
162
- # Set legend text color
181
+ # Add and format legend
182
+ legend = self.ax.legend(loc="upper left", fontsize=13, facecolor=self.bg_color, edgecolor=self.bg_color)
163
183
  for text in legend.get_texts():
164
184
  text.set_color(self.fg_color)
165
185
 
166
- self.canvas.draw()
167
- im0 = np.array(self.canvas.renderer.buffer_rgba())
168
- self.write_and_display(im0)
169
-
170
- def update_line(self, frame_number, total_counts):
171
- """
172
- Update the line graph with new data.
173
-
174
- Args:
175
- frame_number (int): The current frame number.
176
- total_counts (int): The total counts to plot.
177
- """
178
- # Update line graph data
179
- x_data = self.line.get_xdata()
180
- y_data = self.line.get_ydata()
181
- x_data = np.append(x_data, float(frame_number))
182
- y_data = np.append(y_data, float(total_counts))
183
- self.line.set_data(x_data, y_data)
186
+ # Redraw graph, update view, capture, and display the updated plot
184
187
  self.ax.relim()
185
188
  self.ax.autoscale_view()
186
189
  self.canvas.draw()
187
190
  im0 = np.array(self.canvas.renderer.buffer_rgba())
188
- self.write_and_display(im0)
189
-
190
- def update_multiple_lines(self, counts_dict, labels_list, frame_number):
191
- """
192
- Update the line graph with multiple classes.
193
-
194
- Args:
195
- counts_dict (int): Dictionary include each class counts.
196
- labels_list (int): list include each classes names.
197
- frame_number (int): The current frame number.
198
- """
199
- warnings.warn("Display is not supported for multiple lines, output will be stored normally!")
200
- for obj in labels_list:
201
- if obj not in self.lines:
202
- (line,) = self.ax.plot([], [], label=obj, marker="o", markersize=self.points_width)
203
- self.lines[obj] = line
204
-
205
- x_data = self.lines[obj].get_xdata()
206
- y_data = self.lines[obj].get_ydata()
207
-
208
- # Remove the initial point if the number of points exceeds max_points
209
- if len(x_data) >= self.max_points:
210
- x_data = np.delete(x_data, 0)
211
- y_data = np.delete(y_data, 0)
212
-
213
- x_data = np.append(x_data, float(frame_number)) # Ensure frame_number is converted to float
214
- y_data = np.append(y_data, float(counts_dict.get(obj, 0))) # Ensure total_count is converted to float
215
- self.lines[obj].set_data(x_data, y_data)
216
-
217
- self.ax.relim()
218
- self.ax.autoscale_view()
219
- self.ax.legend()
220
- self.canvas.draw()
221
-
222
- im0 = np.array(self.canvas.renderer.buffer_rgba())
223
- self.view_img = False # for multiple line view_img not supported yet, coming soon!
224
- self.write_and_display(im0)
225
-
226
- def write_and_display(self, im0):
227
- """
228
- Write and display the line graph
229
- Args:
230
- im0 (ndarray): Image for processing.
231
- """
232
191
  im0 = cv2.cvtColor(im0[:, :, :3], cv2.COLOR_RGBA2BGR)
233
- cv2.imshow(self.title, im0) if self.view_img else None
234
- self.writer.write(im0) if self.save_img else None
235
-
236
- def update_bar(self, count_dict):
237
- """
238
- Update the bar graph with new data.
239
-
240
- Args:
241
- count_dict (dict): Dictionary containing the count data to plot.
242
- """
243
- # Update bar graph data
244
- self.ax.clear()
245
- self.ax.set_facecolor(self.bg_color)
246
- labels = list(count_dict.keys())
247
- counts = list(count_dict.values())
248
-
249
- # Map labels to colors
250
- for label in labels:
251
- if label not in self.color_mapping:
252
- self.color_mapping[label] = next(self.color_cycle)
253
-
254
- colors = [self.color_mapping[label] for label in labels]
255
-
256
- bars = self.ax.bar(labels, counts, color=colors)
257
- for bar, count in zip(bars, counts):
258
- self.ax.text(
259
- bar.get_x() + bar.get_width() / 2,
260
- bar.get_height(),
261
- str(count),
262
- ha="center",
263
- va="bottom",
264
- color=self.fg_color,
265
- )
266
-
267
- # Display and save the updated graph
268
- canvas = FigureCanvas(self.fig)
269
- canvas.draw()
270
- buf = canvas.buffer_rgba()
271
- im0 = np.asarray(buf)
272
- self.write_and_display(im0)
273
-
274
- def update_pie(self, classes_dict):
275
- """
276
- Update the pie chart with new data.
277
-
278
- Args:
279
- classes_dict (dict): Dictionary containing the class data to plot.
280
- """
281
- # Update pie chart data
282
- labels = list(classes_dict.keys())
283
- sizes = list(classes_dict.values())
284
- total = sum(sizes)
285
- percentages = [size / total * 100 for size in sizes]
286
- start_angle = 90
287
- self.ax.clear()
288
-
289
- # Create pie chart without labels inside the slices
290
- wedges, autotexts = self.ax.pie(sizes, autopct=None, startangle=start_angle, textprops={"color": self.fg_color})
291
-
292
- # Construct legend labels with percentages
293
- legend_labels = [f"{label} ({percentage:.1f}%)" for label, percentage in zip(labels, percentages)]
294
- self.ax.legend(wedges, legend_labels, title="Classes", loc="center left", bbox_to_anchor=(1, 0, 0.5, 1))
295
-
296
- # Adjust layout to fit the legend
297
- self.fig.tight_layout()
298
- self.fig.subplots_adjust(left=0.1, right=0.75)
299
-
300
- # Display and save the updated chart
301
- im0 = self.fig.canvas.draw()
302
- im0 = np.array(self.fig.canvas.renderer.buffer_rgba())
303
- self.write_and_display(im0)
304
-
192
+ self.display_output(im0)
305
193
 
306
- if __name__ == "__main__":
307
- Analytics("line", writer=None, im0_shape=None)
194
+ return im0 # Return the image
@@ -4,55 +4,21 @@ import math
4
4
 
5
5
  import cv2
6
6
 
7
- from ultralytics.utils.checks import check_imshow
7
+ from ultralytics.solutions.solutions import BaseSolution # Import a parent class
8
8
  from ultralytics.utils.plotting import Annotator, colors
9
9
 
10
10
 
11
- class DistanceCalculation:
11
+ class DistanceCalculation(BaseSolution):
12
12
  """A class to calculate distance between two objects in a real-time video stream based on their tracks."""
13
13
 
14
- def __init__(
15
- self,
16
- names,
17
- view_img=False,
18
- line_thickness=2,
19
- line_color=(255, 0, 255),
20
- centroid_color=(104, 31, 17),
21
- ):
22
- """
23
- Initializes the DistanceCalculation class with the given parameters.
24
-
25
- Args:
26
- names (dict): Dictionary of classes names.
27
- view_img (bool, optional): Flag to indicate if the video stream should be displayed. Defaults to False.
28
- line_thickness (int, optional): Thickness of the lines drawn on the image. Defaults to 2.
29
- line_color (tuple, optional): Color of the lines drawn on the image (BGR format). Defaults to (255, 255, 0).
30
- centroid_color (tuple, optional): Color of the centroids drawn (BGR format). Defaults to (255, 0, 255).
31
- """
32
- # Visual & image information
33
- self.im0 = None
34
- self.annotator = None
35
- self.view_img = view_img
36
- self.line_color = line_color
37
- self.centroid_color = centroid_color
38
-
39
- # Prediction & tracking information
40
- self.names = names
41
- self.boxes = None
42
- self.line_thickness = line_thickness
43
- self.trk_ids = None
44
-
45
- # Distance calculation information
46
- self.centroids = []
14
+ def __init__(self, **kwargs):
15
+ """Initializes the DistanceCalculation class with the given parameters."""
16
+ super().__init__(**kwargs)
47
17
 
48
18
  # Mouse event information
49
19
  self.left_mouse_count = 0
50
20
  self.selected_boxes = {}
51
21
 
52
- # Check if environment supports imshow
53
- self.env_check = check_imshow(warn=True)
54
- self.window_name = "Ultralytics Solutions"
55
-
56
22
  def mouse_event_for_distance(self, event, x, y, flags, param):
57
23
  """
58
24
  Handles mouse events to select regions in a real-time video stream.
@@ -67,7 +33,7 @@ class DistanceCalculation:
67
33
  if event == cv2.EVENT_LBUTTONDOWN:
68
34
  self.left_mouse_count += 1
69
35
  if self.left_mouse_count <= 2:
70
- for box, track_id in zip(self.boxes, self.trk_ids):
36
+ for box, track_id in zip(self.boxes, self.track_ids):
71
37
  if box[0] < x < box[2] and box[1] < y < box[3] and track_id not in self.selected_boxes:
72
38
  self.selected_boxes[track_id] = box
73
39
 
@@ -75,30 +41,21 @@ class DistanceCalculation:
75
41
  self.selected_boxes = {}
76
42
  self.left_mouse_count = 0
77
43
 
78
- def start_process(self, im0, tracks):
44
+ def calculate(self, im0):
79
45
  """
80
46
  Processes the video frame and calculates the distance between two bounding boxes.
81
47
 
82
48
  Args:
83
49
  im0 (ndarray): The image frame.
84
- tracks (list): List of tracks obtained from the object tracking process.
85
50
 
86
51
  Returns:
87
52
  (ndarray): The processed image frame.
88
53
  """
89
- self.im0 = im0
90
- if tracks[0].boxes.id is None:
91
- if self.view_img:
92
- self.display_frames()
93
- return im0
54
+ self.annotator = Annotator(im0, line_width=self.line_width) # Initialize annotator
55
+ self.extract_tracks(im0) # Extract tracks
94
56
 
95
- self.boxes = tracks[0].boxes.xyxy.cpu()
96
- clss = tracks[0].boxes.cls.cpu().tolist()
97
- self.trk_ids = tracks[0].boxes.id.int().cpu().tolist()
98
-
99
- self.annotator = Annotator(self.im0, line_width=self.line_thickness)
100
-
101
- for box, cls, track_id in zip(self.boxes, clss, self.trk_ids):
57
+ # Iterate over bounding boxes, track ids and classes index
58
+ for box, track_id, cls in zip(self.boxes, self.track_ids, self.clss):
102
59
  self.annotator.box_label(box, color=colors(int(cls), True), label=self.names[int(cls)])
103
60
 
104
61
  if len(self.selected_boxes) == 2:
@@ -115,25 +72,11 @@ class DistanceCalculation:
115
72
  pixels_distance = math.sqrt(
116
73
  (self.centroids[0][0] - self.centroids[1][0]) ** 2 + (self.centroids[0][1] - self.centroids[1][1]) ** 2
117
74
  )
118
- self.annotator.plot_distance_and_line(pixels_distance, self.centroids, self.line_color, self.centroid_color)
75
+ self.annotator.plot_distance_and_line(pixels_distance, self.centroids)
119
76
 
120
77
  self.centroids = []
121
78
 
122
- if self.view_img and self.env_check:
123
- self.display_frames()
124
-
125
- return im0
126
-
127
- def display_frames(self):
128
- """Displays the current frame with annotations."""
129
- cv2.namedWindow(self.window_name)
130
- cv2.setMouseCallback(self.window_name, self.mouse_event_for_distance)
131
- cv2.imshow(self.window_name, self.im0)
132
-
133
- if cv2.waitKey(1) & 0xFF == ord("q"):
134
- return
135
-
79
+ self.display_output(im0) # display output with base class function
80
+ cv2.setMouseCallback("Ultralytics Solutions", self.mouse_event_for_distance)
136
81
 
137
- if __name__ == "__main__":
138
- names = {0: "person", 1: "car"} # example class names
139
- distance_calculation = DistanceCalculation(names)
82
+ return im0 # return output image for more usage
@@ -112,13 +112,13 @@ class ObjectCounter(BaseSolution):
112
112
  # Iterate over bounding boxes, track ids and classes index
113
113
  for box, track_id, cls in zip(self.boxes, self.track_ids, self.clss):
114
114
  # Draw bounding box and counting region
115
- self.annotator.box_label(box, label=self.names[cls], color=colors(track_id, True))
115
+ self.annotator.box_label(box, label=self.names[cls], color=colors(cls, True))
116
116
  self.store_tracking_history(track_id, box) # Store track history
117
117
  self.store_classwise_counts(cls) # store classwise counts in dict
118
118
 
119
119
  # Draw tracks of objects
120
120
  self.annotator.draw_centroid_and_tracks(
121
- self.track_line, color=colors(int(track_id), True), track_thickness=self.line_width
121
+ self.track_line, color=colors(int(cls), True), track_thickness=self.line_width
122
122
  )
123
123
 
124
124
  # store previous position of track for object counting
@@ -598,7 +598,7 @@ def ap_per_class(
598
598
  # AP from recall-precision curve
599
599
  for j in range(tp.shape[1]):
600
600
  ap[ci, j], mpre, mrec = compute_ap(recall[:, j], precision[:, j])
601
- if plot and j == 0:
601
+ if j == 0:
602
602
  prec_values.append(np.interp(x, mrec, mpre)) # precision at mAP@0.5
603
603
 
604
604
  prec_values = np.array(prec_values) # (nc, 1000)