ultralytics 8.3.14__py3-none-any.whl → 8.3.16__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.
@@ -1,18 +1,40 @@
1
1
  # Ultralytics YOLO 🚀, AGPL-3.0 license
2
2
 
3
- from shapely.geometry import LineString, Point
4
-
5
- from ultralytics.solutions.solutions import BaseSolution # Import a parent class
3
+ from ultralytics.solutions.solutions import BaseSolution
6
4
  from ultralytics.utils.plotting import Annotator, colors
7
5
 
8
6
 
9
7
  class ObjectCounter(BaseSolution):
10
- """A class to manage the counting of objects in a real-time video stream based on their tracks."""
8
+ """
9
+ A class to manage the counting of objects in a real-time video stream based on their tracks.
10
+
11
+ This class extends the BaseSolution class and provides functionality for counting objects moving in and out of a
12
+ specified region in a video stream. It supports both polygonal and linear regions for counting.
13
+
14
+ Attributes:
15
+ in_count (int): Counter for objects moving inward.
16
+ out_count (int): Counter for objects moving outward.
17
+ counted_ids (List[int]): List of IDs of objects that have been counted.
18
+ classwise_counts (Dict[str, Dict[str, int]]): Dictionary for counts, categorized by object class.
19
+ region_initialized (bool): Flag indicating whether the counting region has been initialized.
20
+ show_in (bool): Flag to control display of inward count.
21
+ show_out (bool): Flag to control display of outward count.
22
+
23
+ Methods:
24
+ count_objects: Counts objects within a polygonal or linear region.
25
+ store_classwise_counts: Initializes class-wise counts if not already present.
26
+ display_counts: Displays object counts on the frame.
27
+ count: Processes input data (frames or object tracks) and updates counts.
28
+
29
+ Examples:
30
+ >>> counter = ObjectCounter()
31
+ >>> frame = cv2.imread("frame.jpg")
32
+ >>> processed_frame = counter.count(frame)
33
+ >>> print(f"Inward count: {counter.in_count}, Outward count: {counter.out_count}")
34
+ """
11
35
 
12
36
  def __init__(self, **kwargs):
13
- """Initialization function for Count class, a child class of BaseSolution class, can be used for counting the
14
- objects.
15
- """
37
+ """Initializes the ObjectCounter class for real-time object counting in video streams."""
16
38
  super().__init__(**kwargs)
17
39
 
18
40
  self.in_count = 0 # Counter for objects moving inward
@@ -26,14 +48,23 @@ class ObjectCounter(BaseSolution):
26
48
 
27
49
  def count_objects(self, track_line, box, track_id, prev_position, cls):
28
50
  """
29
- Helper function to count objects within a polygonal region.
51
+ Counts objects within a polygonal or linear region based on their tracks.
30
52
 
31
53
  Args:
32
- track_line (dict): last 30 frame track record
33
- box (list): Bounding box data for specific track in current frame
34
- track_id (int): track ID of the object
35
- prev_position (tuple): last frame position coordinates of the track
36
- cls (int): Class index for classwise count updates
54
+ track_line (Dict): Last 30 frame track record for the object.
55
+ box (List[float]): Bounding box coordinates [x1, y1, x2, y2] for the specific track in the current frame.
56
+ track_id (int): Unique identifier for the tracked object.
57
+ prev_position (Tuple[float, float]): Last frame position coordinates (x, y) of the track.
58
+ cls (int): Class index for classwise count updates.
59
+
60
+ Examples:
61
+ >>> counter = ObjectCounter()
62
+ >>> track_line = {1: [100, 200], 2: [110, 210], 3: [120, 220]}
63
+ >>> box = [130, 230, 150, 250]
64
+ >>> track_id = 1
65
+ >>> prev_position = (120, 220)
66
+ >>> cls = 0
67
+ >>> counter.count_objects(track_line, box, track_id, prev_position, cls)
37
68
  """
38
69
  if prev_position is None or track_id in self.counted_ids:
39
70
  return
@@ -42,7 +73,7 @@ class ObjectCounter(BaseSolution):
42
73
  dx = (box[0] - prev_position[0]) * (centroid.x - prev_position[0])
43
74
  dy = (box[1] - prev_position[1]) * (centroid.y - prev_position[1])
44
75
 
45
- if len(self.region) >= 3 and self.r_s.contains(Point(track_line[-1])):
76
+ if len(self.region) >= 3 and self.r_s.contains(self.Point(track_line[-1])):
46
77
  self.counted_ids.append(track_id)
47
78
  # For polygon region
48
79
  if dx > 0:
@@ -52,7 +83,7 @@ class ObjectCounter(BaseSolution):
52
83
  self.out_count += 1
53
84
  self.classwise_counts[self.names[cls]]["OUT"] += 1
54
85
 
55
- elif len(self.region) < 3 and LineString([prev_position, box[:2]]).intersects(self.l_s):
86
+ elif len(self.region) < 3 and self.LineString([prev_position, box[:2]]).intersects(self.r_s):
56
87
  self.counted_ids.append(track_id)
57
88
  # For linear region
58
89
  if dx > 0 and dy > 0:
@@ -64,20 +95,34 @@ class ObjectCounter(BaseSolution):
64
95
 
65
96
  def store_classwise_counts(self, cls):
66
97
  """
67
- Initialize class-wise counts if not already present.
98
+ Initialize class-wise counts for a specific object class if not already present.
68
99
 
69
100
  Args:
70
- cls (int): Class index for classwise count updates
101
+ cls (int): Class index for classwise count updates.
102
+
103
+ This method ensures that the 'classwise_counts' dictionary contains an entry for the specified class,
104
+ initializing 'IN' and 'OUT' counts to zero if the class is not already present.
105
+
106
+ Examples:
107
+ >>> counter = ObjectCounter()
108
+ >>> counter.store_classwise_counts(0) # Initialize counts for class index 0
109
+ >>> print(counter.classwise_counts)
110
+ {'person': {'IN': 0, 'OUT': 0}}
71
111
  """
72
112
  if self.names[cls] not in self.classwise_counts:
73
113
  self.classwise_counts[self.names[cls]] = {"IN": 0, "OUT": 0}
74
114
 
75
115
  def display_counts(self, im0):
76
116
  """
77
- Helper function to display object counts on the frame.
117
+ Displays object counts on the input image or frame.
78
118
 
79
119
  Args:
80
- im0 (ndarray): The input image or frame
120
+ im0 (numpy.ndarray): The input image or frame to display counts on.
121
+
122
+ Examples:
123
+ >>> counter = ObjectCounter()
124
+ >>> frame = cv2.imread("image.jpg")
125
+ >>> counter.display_counts(frame)
81
126
  """
82
127
  labels_dict = {
83
128
  str.capitalize(key): f"{'IN ' + str(value['IN']) if self.show_in else ''} "
@@ -91,12 +136,21 @@ class ObjectCounter(BaseSolution):
91
136
 
92
137
  def count(self, im0):
93
138
  """
94
- Processes input data (frames or object tracks) and updates counts.
139
+ Processes input data (frames or object tracks) and updates object counts.
140
+
141
+ This method initializes the counting region, extracts tracks, draws bounding boxes and regions, updates
142
+ object counts, and displays the results on the input image.
95
143
 
96
144
  Args:
97
- im0 (ndarray): The input image that will be used for processing
98
- Returns
99
- im0 (ndarray): The processed image for more usage
145
+ im0 (numpy.ndarray): The input image or frame to be processed.
146
+
147
+ Returns:
148
+ (numpy.ndarray): The processed image with annotations and count information.
149
+
150
+ Examples:
151
+ >>> counter = ObjectCounter()
152
+ >>> frame = cv2.imread("path/to/image.jpg")
153
+ >>> processed_frame = counter.count(frame)
100
154
  """
101
155
  if not self.region_initialized:
102
156
  self.initialize_region()
@@ -122,7 +176,9 @@ class ObjectCounter(BaseSolution):
122
176
  )
123
177
 
124
178
  # store previous position of track for object counting
125
- prev_position = self.track_history[track_id][-2] if len(self.track_history[track_id]) > 1 else None
179
+ prev_position = None
180
+ if len(self.track_history[track_id]) > 1:
181
+ prev_position = self.track_history[track_id][-2]
126
182
  self.count_objects(self.track_line, box, track_id, prev_position, cls) # Perform object counting
127
183
 
128
184
  self.display_counts(im0) # Display the counts on the frame
@@ -5,237 +5,232 @@ import json
5
5
  import cv2
6
6
  import numpy as np
7
7
 
8
- from ultralytics.utils.checks import check_imshow, check_requirements
8
+ from ultralytics.solutions.solutions import LOGGER, BaseSolution, check_requirements
9
9
  from ultralytics.utils.plotting import Annotator
10
10
 
11
11
 
12
12
  class ParkingPtsSelection:
13
- """Class for selecting and managing parking zone points on images using a Tkinter-based UI."""
13
+ """
14
+ A class for selecting and managing parking zone points on images using a Tkinter-based UI.
15
+
16
+ This class provides functionality to upload an image, select points to define parking zones, and save the
17
+ selected points to a JSON file. It uses Tkinter for the graphical user interface.
18
+
19
+ Attributes:
20
+ tk (module): The Tkinter module for GUI operations.
21
+ filedialog (module): Tkinter's filedialog module for file selection operations.
22
+ messagebox (module): Tkinter's messagebox module for displaying message boxes.
23
+ master (tk.Tk): The main Tkinter window.
24
+ canvas (tk.Canvas): The canvas widget for displaying the image and drawing bounding boxes.
25
+ image (PIL.Image.Image): The uploaded image.
26
+ canvas_image (ImageTk.PhotoImage): The image displayed on the canvas.
27
+ rg_data (List[List[Tuple[int, int]]]): List of bounding boxes, each defined by 4 points.
28
+ current_box (List[Tuple[int, int]]): Temporary storage for the points of the current bounding box.
29
+ imgw (int): Original width of the uploaded image.
30
+ imgh (int): Original height of the uploaded image.
31
+ canvas_max_width (int): Maximum width of the canvas.
32
+ canvas_max_height (int): Maximum height of the canvas.
33
+
34
+ Methods:
35
+ setup_ui: Sets up the Tkinter UI components.
36
+ initialize_properties: Initializes the necessary properties.
37
+ upload_image: Uploads an image, resizes it to fit the canvas, and displays it.
38
+ on_canvas_click: Handles mouse clicks to add points for bounding boxes.
39
+ draw_box: Draws a bounding box on the canvas.
40
+ remove_last_bounding_box: Removes the last bounding box and redraws the canvas.
41
+ redraw_canvas: Redraws the canvas with the image and all bounding boxes.
42
+ save_to_json: Saves the bounding boxes to a JSON file.
43
+
44
+ Examples:
45
+ >>> parking_selector = ParkingPtsSelection()
46
+ >>> # Use the GUI to upload an image, select parking zones, and save the data
47
+ """
14
48
 
15
49
  def __init__(self):
16
- """Initializes the UI for selecting parking zone points in a tkinter window."""
50
+ """Initializes the ParkingPtsSelection class, setting up UI and properties for parking zone point selection."""
17
51
  check_requirements("tkinter")
52
+ import tkinter as tk
53
+ from tkinter import filedialog, messagebox
18
54
 
19
- import tkinter as tk # scope for multi-environment compatibility
55
+ self.tk, self.filedialog, self.messagebox = tk, filedialog, messagebox
56
+ self.setup_ui()
57
+ self.initialize_properties()
58
+ self.master.mainloop()
20
59
 
21
- self.tk = tk
22
- self.master = tk.Tk()
60
+ def setup_ui(self):
61
+ """Sets up the Tkinter UI components for the parking zone points selection interface."""
62
+ self.master = self.tk.Tk()
23
63
  self.master.title("Ultralytics Parking Zones Points Selector")
24
-
25
- # Disable window resizing
26
64
  self.master.resizable(False, False)
27
65
 
28
- # Setup canvas for image display
66
+ # Canvas for image display
29
67
  self.canvas = self.tk.Canvas(self.master, bg="white")
68
+ self.canvas.pack(side=self.tk.BOTTOM)
30
69
 
31
- # Setup buttons
70
+ # Button frame with buttons
32
71
  button_frame = self.tk.Frame(self.master)
33
72
  button_frame.pack(side=self.tk.TOP)
34
73
 
35
- self.tk.Button(button_frame, text="Upload Image", command=self.upload_image).grid(row=0, column=0)
36
- self.tk.Button(button_frame, text="Remove Last BBox", command=self.remove_last_bounding_box).grid(
37
- row=0, column=1
38
- )
39
- self.tk.Button(button_frame, text="Save", command=self.save_to_json).grid(row=0, column=2)
40
-
41
- # Initialize properties
42
- self.image_path = None
43
- self.image = None
44
- self.canvas_image = None
45
- self.rg_data = [] # region coordinates
46
- self.current_box = []
47
- self.imgw = 0 # image width
48
- self.imgh = 0 # image height
74
+ for text, cmd in [
75
+ ("Upload Image", self.upload_image),
76
+ ("Remove Last BBox", self.remove_last_bounding_box),
77
+ ("Save", self.save_to_json),
78
+ ]:
79
+ self.tk.Button(button_frame, text=text, command=cmd).pack(side=self.tk.LEFT)
49
80
 
50
- # Constants
51
- self.canvas_max_width = 1280
52
- self.canvas_max_height = 720
53
-
54
- self.master.mainloop()
81
+ def initialize_properties(self):
82
+ """Initialize properties for image, canvas, bounding boxes, and dimensions."""
83
+ self.image = self.canvas_image = None
84
+ self.rg_data, self.current_box = [], []
85
+ self.imgw = self.imgh = 0
86
+ self.canvas_max_width, self.canvas_max_height = 1280, 720
55
87
 
56
88
  def upload_image(self):
57
- """Upload an image and resize it to fit canvas."""
58
- from tkinter import filedialog
59
-
89
+ """Uploads and displays an image on the canvas, resizing it to fit within specified dimensions."""
60
90
  from PIL import Image, ImageTk # scope because ImageTk requires tkinter package
61
91
 
62
- self.image_path = filedialog.askopenfilename(filetypes=[("Image Files", "*.png;*.jpg;*.jpeg")])
63
- if not self.image_path:
92
+ self.image = Image.open(self.filedialog.askopenfilename(filetypes=[("Image Files", "*.png;*.jpg;*.jpeg")]))
93
+ if not self.image:
64
94
  return
65
95
 
66
- self.image = Image.open(self.image_path)
67
96
  self.imgw, self.imgh = self.image.size
68
-
69
- # Calculate the aspect ratio and resize image
70
97
  aspect_ratio = self.imgw / self.imgh
71
- if aspect_ratio > 1:
72
- # Landscape orientation
73
- canvas_width = min(self.canvas_max_width, self.imgw)
74
- canvas_height = int(canvas_width / aspect_ratio)
75
- else:
76
- # Portrait orientation
77
- canvas_height = min(self.canvas_max_height, self.imgh)
78
- canvas_width = int(canvas_height * aspect_ratio)
79
-
80
- # Check if canvas is already initialized
81
- if self.canvas:
82
- self.canvas.destroy() # Destroy previous canvas
83
-
84
- self.canvas = self.tk.Canvas(self.master, bg="white", width=canvas_width, height=canvas_height)
85
- resized_image = self.image.resize((canvas_width, canvas_height), Image.LANCZOS)
86
- self.canvas_image = ImageTk.PhotoImage(resized_image)
87
- self.canvas.create_image(0, 0, anchor=self.tk.NW, image=self.canvas_image)
98
+ canvas_width = (
99
+ min(self.canvas_max_width, self.imgw) if aspect_ratio > 1 else int(self.canvas_max_height * aspect_ratio)
100
+ )
101
+ canvas_height = (
102
+ min(self.canvas_max_height, self.imgh) if aspect_ratio <= 1 else int(canvas_width / aspect_ratio)
103
+ )
88
104
 
89
- self.canvas.pack(side=self.tk.BOTTOM)
105
+ self.canvas.config(width=canvas_width, height=canvas_height)
106
+ self.canvas_image = ImageTk.PhotoImage(self.image.resize((canvas_width, canvas_height), Image.LANCZOS))
107
+ self.canvas.create_image(0, 0, anchor=self.tk.NW, image=self.canvas_image)
90
108
  self.canvas.bind("<Button-1>", self.on_canvas_click)
91
109
 
92
- # Reset bounding boxes and current box
93
- self.rg_data = []
94
- self.current_box = []
110
+ self.rg_data.clear(), self.current_box.clear()
95
111
 
96
112
  def on_canvas_click(self, event):
97
- """Handle mouse clicks on canvas to create points for bounding boxes."""
113
+ """Handles mouse clicks to add points for bounding boxes on the canvas."""
98
114
  self.current_box.append((event.x, event.y))
99
115
  self.canvas.create_oval(event.x - 3, event.y - 3, event.x + 3, event.y + 3, fill="red")
100
-
101
116
  if len(self.current_box) == 4:
102
- self.rg_data.append(self.current_box)
103
- [
104
- self.canvas.create_line(self.current_box[i], self.current_box[(i + 1) % 4], fill="blue", width=2)
105
- for i in range(4)
106
- ]
107
- self.current_box = []
117
+ self.rg_data.append(self.current_box.copy())
118
+ self.draw_box(self.current_box)
119
+ self.current_box.clear()
108
120
 
109
- def remove_last_bounding_box(self):
110
- """Remove the last drawn bounding box from canvas."""
111
- from tkinter import messagebox # scope for multi-environment compatibility
121
+ def draw_box(self, box):
122
+ """Draws a bounding box on the canvas using the provided coordinates."""
123
+ for i in range(4):
124
+ self.canvas.create_line(box[i], box[(i + 1) % 4], fill="blue", width=2)
112
125
 
113
- if self.rg_data:
114
- self.rg_data.pop() # Remove the last bounding box
115
- self.canvas.delete("all") # Clear the canvas
116
- self.canvas.create_image(0, 0, anchor=self.tk.NW, image=self.canvas_image) # Redraw the image
126
+ def remove_last_bounding_box(self):
127
+ """Removes the last bounding box from the list and redraws the canvas."""
128
+ if not self.rg_data:
129
+ self.messagebox.showwarning("Warning", "No bounding boxes to remove.")
130
+ return
131
+ self.rg_data.pop()
132
+ self.redraw_canvas()
117
133
 
118
- # Redraw all bounding boxes
119
- for box in self.rg_data:
120
- [self.canvas.create_line(box[i], box[(i + 1) % 4], fill="blue", width=2) for i in range(4)]
121
- messagebox.showinfo("Success", "Last bounding box removed.")
122
- else:
123
- messagebox.showwarning("Warning", "No bounding boxes to remove.")
134
+ def redraw_canvas(self):
135
+ """Redraws the canvas with the image and all bounding boxes."""
136
+ self.canvas.delete("all")
137
+ self.canvas.create_image(0, 0, anchor=self.tk.NW, image=self.canvas_image)
138
+ for box in self.rg_data:
139
+ self.draw_box(box)
124
140
 
125
141
  def save_to_json(self):
126
- """Saves rescaled bounding boxes to 'bounding_boxes.json' based on image-to-canvas size ratio."""
127
- from tkinter import messagebox # scope for multi-environment compatibility
128
-
129
- rg_data = [] # regions data
130
- for box in self.rg_data:
131
- rs_box = [
132
- (
133
- int(x * self.imgw / self.canvas.winfo_width()), # width scaling
134
- int(y * self.imgh / self.canvas.winfo_height()), # height scaling
135
- )
136
- for x, y in box
137
- ]
138
- rg_data.append({"points": rs_box})
142
+ """Saves the selected parking zone points to a JSON file with scaled coordinates."""
143
+ scale_w, scale_h = self.imgw / self.canvas.winfo_width(), self.imgh / self.canvas.winfo_height()
144
+ data = [{"points": [(int(x * scale_w), int(y * scale_h)) for x, y in box]} for box in self.rg_data]
139
145
  with open("bounding_boxes.json", "w") as f:
140
- json.dump(rg_data, f, indent=4)
146
+ json.dump(data, f, indent=4)
147
+ self.messagebox.showinfo("Success", "Bounding boxes saved to bounding_boxes.json")
141
148
 
142
- messagebox.showinfo("Success", "Bounding boxes saved to bounding_boxes.json")
143
149
 
150
+ class ParkingManagement(BaseSolution):
151
+ """
152
+ Manages parking occupancy and availability using YOLO model for real-time monitoring and visualization.
144
153
 
145
- class ParkingManagement:
146
- """Manages parking occupancy and availability using YOLOv8 for real-time monitoring and visualization."""
154
+ This class extends BaseSolution to provide functionality for parking lot management, including detection of
155
+ occupied spaces, visualization of parking regions, and display of occupancy statistics.
147
156
 
148
- def __init__(
149
- self,
150
- model, # Ultralytics YOLO model file path
151
- json_file, # Parking management annotation file created from Parking Annotator
152
- occupied_region_color=(0, 0, 255), # occupied region color
153
- available_region_color=(0, 255, 0), # available region color
154
- ):
155
- """
156
- Initializes the parking management system with a YOLOv8 model and visualization settings.
157
+ Attributes:
158
+ json_file (str): Path to the JSON file containing parking region details.
159
+ json (List[Dict]): Loaded JSON data containing parking region information.
160
+ pr_info (Dict[str, int]): Dictionary storing parking information (Occupancy and Available spaces).
161
+ arc (Tuple[int, int, int]): RGB color tuple for available region visualization.
162
+ occ (Tuple[int, int, int]): RGB color tuple for occupied region visualization.
163
+ dc (Tuple[int, int, int]): RGB color tuple for centroid visualization of detected objects.
157
164
 
158
- Args:
159
- model (str): Path to the YOLOv8 model.
160
- json_file (str): file that have all parking slot points data
161
- occupied_region_color (tuple): RGB color tuple for occupied regions.
162
- available_region_color (tuple): RGB color tuple for available regions.
163
- """
164
- # Model initialization
165
- from ultralytics import YOLO
165
+ Methods:
166
+ process_data: Processes model data for parking lot management and visualization.
166
167
 
167
- self.model = YOLO(model)
168
+ Examples:
169
+ >>> from ultralytics.solutions import ParkingManagement
170
+ >>> parking_manager = ParkingManagement(model="yolov8n.pt", json_file="parking_regions.json")
171
+ >>> results = parking_manager(source="parking_lot_video.mp4")
172
+ >>> print(f"Occupied spaces: {parking_manager.pr_info['Occupancy']}")
173
+ >>> print(f"Available spaces: {parking_manager.pr_info['Available']}")
174
+ """
168
175
 
169
- # Load JSON data
170
- with open(json_file) as f:
171
- self.json_data = json.load(f)
176
+ def __init__(self, **kwargs):
177
+ """Initializes the parking management system with a YOLO model and visualization settings."""
178
+ super().__init__(**kwargs)
172
179
 
173
- self.pr_info = {"Occupancy": 0, "Available": 0} # dictionary for parking information
180
+ self.json_file = self.CFG["json_file"] # Load JSON data
181
+ if self.json_file is None:
182
+ LOGGER.warning("❌ json_file argument missing. Parking region details required.")
183
+ raise ValueError("❌ Json file path can not be empty")
174
184
 
175
- self.occ = occupied_region_color
176
- self.arc = available_region_color
185
+ with open(self.json_file) as f:
186
+ self.json = json.load(f)
177
187
 
178
- self.env_check = check_imshow(warn=True) # check if environment supports imshow
188
+ self.pr_info = {"Occupancy": 0, "Available": 0} # dictionary for parking information
179
189
 
180
- def process_data(self, im0):
181
- """
182
- Process the model data for parking lot management.
190
+ self.arc = (0, 0, 255) # available region color
191
+ self.occ = (0, 255, 0) # occupied region color
192
+ self.dc = (255, 0, 189) # centroid color for each box
183
193
 
184
- Args:
185
- im0 (ndarray): inference image
194
+ def process_data(self, im0):
186
195
  """
187
- results = self.model.track(im0, persist=True, show=False) # object tracking
196
+ Processes the model data for parking lot management.
188
197
 
189
- es, fs = len(self.json_data), 0 # empty slots, filled slots
190
- annotator = Annotator(im0) # init annotator
198
+ This function analyzes the input image, extracts tracks, and determines the occupancy status of parking
199
+ regions defined in the JSON file. It annotates the image with occupied and available parking spots,
200
+ and updates the parking information.
191
201
 
192
- # extract tracks data
193
- if results[0].boxes.id is None:
194
- self.display_frames(im0)
195
- return im0
202
+ Args:
203
+ im0 (np.ndarray): The input inference image.
196
204
 
197
- boxes = results[0].boxes.xyxy.cpu().tolist()
198
- clss = results[0].boxes.cls.cpu().tolist()
205
+ Examples:
206
+ >>> parking_manager = ParkingManagement(json_file="parking_regions.json")
207
+ >>> image = cv2.imread("parking_lot.jpg")
208
+ >>> parking_manager.process_data(image)
209
+ """
210
+ self.extract_tracks(im0) # extract tracks from im0
211
+ es, fs = len(self.json), 0 # empty slots, filled slots
212
+ annotator = Annotator(im0, self.line_width) # init annotator
199
213
 
200
- for region in self.json_data:
214
+ for region in self.json:
201
215
  # Convert points to a NumPy array with the correct dtype and reshape properly
202
216
  pts_array = np.array(region["points"], dtype=np.int32).reshape((-1, 1, 2))
203
217
  rg_occupied = False # occupied region initialization
204
- for box, cls in zip(boxes, clss):
205
- xc = int((box[0] + box[2]) / 2)
206
- yc = int((box[1] + box[3]) / 2)
207
- annotator.display_objects_labels(
208
- im0, self.model.names[int(cls)], (104, 31, 17), (255, 255, 255), xc, yc, 10
209
- )
218
+ for box, cls in zip(self.boxes, self.clss):
219
+ xc, yc = int((box[0] + box[2]) / 2), int((box[1] + box[3]) / 2)
210
220
  dist = cv2.pointPolygonTest(pts_array, (xc, yc), False)
211
221
  if dist >= 0:
222
+ # cv2.circle(im0, (xc, yc), radius=self.line_width * 4, color=self.dc, thickness=-1)
223
+ annotator.display_objects_labels(
224
+ im0, self.model.names[int(cls)], (104, 31, 17), (255, 255, 255), xc, yc, 10
225
+ )
212
226
  rg_occupied = True
213
227
  break
214
- if rg_occupied:
215
- fs += 1
216
- es -= 1
217
-
228
+ fs, es = (fs + 1, es - 1) if rg_occupied else (fs, es)
218
229
  # Plotting regions
219
- color = self.occ if rg_occupied else self.arc
220
- cv2.polylines(im0, [pts_array], isClosed=True, color=color, thickness=2)
230
+ cv2.polylines(im0, [pts_array], isClosed=True, color=self.occ if rg_occupied else self.arc, thickness=2)
221
231
 
222
- self.pr_info["Occupancy"] = fs
223
- self.pr_info["Available"] = es
232
+ self.pr_info["Occupancy"], self.pr_info["Available"] = fs, es
224
233
 
225
234
  annotator.display_analytics(im0, self.pr_info, (104, 31, 17), (255, 255, 255), 10)
226
-
227
- self.display_frames(im0)
228
- return im0
229
-
230
- def display_frames(self, im0):
231
- """
232
- Display frame.
233
-
234
- Args:
235
- im0 (ndarray): inference image
236
- """
237
- if self.env_check:
238
- cv2.imshow("Ultralytics Parking Manager", im0)
239
- # Break Window
240
- if cv2.waitKey(1) & 0xFF == ord("q"):
241
- return
235
+ self.display_output(im0) # display output with base class function
236
+ return im0 # return output image for more usage