Skip to content

Commit

Permalink
ultralytics 8.2.5 New 🌟 Parking Management Solution (#10385)
Browse files Browse the repository at this point in the history
Co-authored-by: UltralyticsAssistant <web@ultralytics.com>
Co-authored-by: Glenn Jocher <glenn.jocher@ultralytics.com>
  • Loading branch information
3 people committed Apr 29, 2024
1 parent 156b6be commit bc9fd45
Show file tree
Hide file tree
Showing 10 changed files with 453 additions and 83 deletions.
5 changes: 3 additions & 2 deletions docs/en/datasets/detect/roboflow-100.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Dataset benchmarking evaluates machine learning model performance on specific da
```python
from pathlib import Path
import shutil
import os
from ultralytics.utils.benchmarks import RF100Benchmark
# Initialize RF100Benchmark and set API key
Expand All @@ -65,10 +66,10 @@ Dataset benchmarking evaluates machine learning model performance on specific da
if path.exists():
# Fix YAML file and run training
benchmark.fix_yaml(str(path))
Path.cwd().system(f'yolo detect train data={path} model=yolov8s.pt epochs=1 batch=16')
os.system(f'yolo detect train data={path} model=yolov8s.pt epochs=1 batch=16')
# Run validation and evaluate
Path.cwd().system(f'yolo detect val data={path} model=runs/detect/train/weights/best.pt > {val_log_file} 2>&1')
os.system(f'yolo detect val data={path} model=runs/detect/train/weights/best.pt > {val_log_file} 2>&1')
benchmark.evaluate(str(path), str(val_log_file), str(eval_log_file), ind)
# Remove the 'runs' directory
Expand Down
1 change: 1 addition & 0 deletions docs/en/guides/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ Here's a compilation of in-depth guides to help you master different aspects of
- [Speed Estimation](speed-estimation.md) 🚀 NEW: Speed estimation in computer vision relies on analyzing object motion through techniques like [object tracking](https://docs.ultralytics.com/modes/track/), crucial for applications like autonomous vehicles and traffic monitoring.
- [Distance Calculation](distance-calculation.md) 🚀 NEW: Distance calculation, which involves measuring the separation between two objects within a defined space, is a crucial aspect. In the context of Ultralytics YOLOv8, the method employed for this involves using the bounding box centroid to determine the distance associated with user-highlighted bounding boxes.
- [Queue Management](queue-management.md) 🚀 NEW: Queue management is the practice of efficiently controlling and directing the flow of people or tasks, often through strategic planning and technology implementation, to minimize wait times and improve overall productivity.
- [Parking Management](parking-management.md) 🚀 NEW: Parking management involves efficiently organizing and directing the flow of vehicles in parking areas, often through strategic planning and technology integration, to optimize space utilization and enhance user experience.

## Contribute to Our Guides

Expand Down
116 changes: 116 additions & 0 deletions docs/en/guides/parking-management.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
---
comments: true
description: Parking Management System Using Ultralytics YOLOv8
keywords: Ultralytics, YOLOv8, Object Detection, Object Counting, Parking lots, Object Tracking, Notebook, IPython Kernel, CLI, Python SDK
---

# Parking Management using Ultralytics YOLOv8 🚀

## What is Parking Management System?

Parking management with [Ultralytics YOLOv8](https://github.com/ultralytics/ultralytics/) ensures efficient and safe parking by organizing spaces and monitoring availability. YOLOv8 can improve parking lot management through real-time vehicle detection, and insights into parking occupancy.

## Advantages of Parking Management System?

- **Efficiency**: Parking lot management optimizes the use of parking spaces and reduces congestion.
- **Safety and Security**: Parking management using YOLOv8 improves the safety of both people and vehicles through surveillance and security measures.
- **Reduced Emissions**: Parking management using YOLOv8 manages traffic flow to minimize idle time and emissions in parking lots.

## Real World Applications

| Parking Management System | Parking Management System |
|:-------------------------------------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------:|
| ![Parking lots Analytics Using Ultralytics YOLOv8](https://github.com/RizwanMunawar/RizwanMunawar/assets/62513924/e3d4bc3e-cf4a-4da9-b42e-0da55cc74ad6) | ![Parking management top view using Ultralytics YOLOv8](https://github.com/RizwanMunawar/RizwanMunawar/assets/62513924/fe186719-1aca-43c9-b388-1ded91280eb5) |
| Parking management Aeriel View using Ultralytics YOLOv8 | Parking management Top View using Ultralytics YOLOv8 |


## Parking Management System Code Workflow

### Selection of Points

!!! Tip "Point Selection is now Easy"

Choosing parking points is a critical and complex task in parking management systems. Ultralytics streamlines this process by providing a tool that lets you define parking lot areas, which can be utilized later for additional processing.

- Capture a frame from the video or camera stream where you want to manage the parking lot.
- Use the provided code to launch a graphical interface, where you can select an image and start outlining parking regions by mouse click to create polygons.

!!! Warning "Image Size"

Max Image Size of 1920 * 1080 supported

```python
from ultralytics.solutions.parking_management import ParkingPtsSelection, tk
root = tk.Tk()
ParkingPtsSelection(root)
root.mainloop()
```

- After defining the parking areas with polygons, click `save` to store a JSON file with the data in your working directory.

![Ultralytics YOLOv8 Points Selection Demo](https://github.com/RizwanMunawar/RizwanMunawar/assets/62513924/72737b8a-0f0f-4efb-98ad-b917a0039535)


### Python Code for Parking Management

!!! Example "Parking management using YOLOv8 Example"

=== "Parking Management"

```python
import cv2
from ultralytics.solutions.parking_management import ParkingManagement

# Path to json file, that created with above point selection app
polygon_json_path = "bounding_boxes.json"
# Video Capture
cap = cv2.VideoCapture("Path/to/video/file.mp4")
assert cap.isOpened(), "Error reading video file"
w, h, fps = (int(cap.get(x)) for x in (cv2.CAP_PROP_FRAME_WIDTH, cv2.CAP_PROP_FRAME_HEIGHT, cv2.CAP_PROP_FPS))
video_writer = cv2.VideoWriter("parking management.avi", cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h))
# Initialize parking management object
management = ParkingManagement(model_path="yolov8n.pt")
while cap.isOpened():
ret, im0 = cap.read()
if not ret:
break
json_data = management.parking_regions_extraction(polygon_json_path)
results = management.model.track(im0, persist=True, show=False)
if results[0].boxes.id is not None:
boxes = results[0].boxes.xyxy.cpu().tolist()
clss = results[0].boxes.cls.cpu().tolist()
management.process_data(json_data, im0, boxes, clss)
management.display_frames(im0)
video_writer.write(im0)
cap.release()
video_writer.release()
cv2.destroyAllWindows()
```

### Optional Arguments `ParkingManagement()`

| Name | Type | Default | Description |
|--------------------------|-------------|-------------------|-----------------------------------------------------|
| `occupied_region_color` | `RGB Color` | `(0, 255, 0)` | Parking space occupied region color |
| `available_region_color` | `RGB Color` | `(0, 0, 255)` | Parking space available region color |
| `margin` | `int` | `10` | Gap between text display for multiple classes count |
| `txt_color` | `RGB Color` | `(255, 255, 255)` | Foreground color for object counts text |
| `bg_color` | `RGB Color` | `(255, 255, 255)` | Rectangle behind text background color |

### Arguments `model.track`

| Name | Type | Default | Description |
|-----------|---------|----------------|-------------------------------------------------------------|
| `source` | `im0` | `None` | source directory for images or videos |
| `persist` | `bool` | `False` | persisting tracks between frames |
| `tracker` | `str` | `botsort.yaml` | Tracking method 'bytetrack' or 'botsort' |
| `conf` | `float` | `0.3` | Confidence Threshold |
| `iou` | `float` | `0.5` | IOU Threshold |
| `classes` | `list` | `None` | filter results by class, i.e. classes=0, or classes=[0,2,3] |
| `verbose` | `bool` | `True` | Display the object tracking results |
20 changes: 20 additions & 0 deletions docs/en/reference/solutions/parking_management.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
description: Parking management system using Ultralytics YOLO featuring cutting-edge technology for precise real-time occupancy and availability monitoring for parking lots.
keywords: Ultralytics YOLO, object tracking software, real-time counting solutions, video stream analysis, YOLOv8 object detection, AI surveillance, smart counting technology, computer vision, AI-powered tracking, object counting accuracy, video analytics tools, automated monitoring.
---

# Reference for `ultralytics/solutions/parking_management.py`

!!! Note

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

<br><br>

## ::: ultralytics.solutions.parking_management.ParkingManagement

<br><br>

## ::: ultralytics.solutions.parking_management.ParkingPtsSelection

<br><br>
5 changes: 4 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@ nav:
- datasets/index.md
- Guides:
- guides/index.md
- NEW 🚀 Explorer:
- New 🚀 Parking Management: guides/parking-management.md
- Explorer:
- datasets/explorer/index.md
- Languages:
- 🇬🇧&nbsp English: https://ultralytics.com/docs/
Expand Down Expand Up @@ -301,6 +302,7 @@ nav:
- Speed Estimation: guides/speed-estimation.md
- Distance Calculation: guides/distance-calculation.md
- Queue Management: guides/queue-management.md
- Parking Management: guides/parking-management.md
- YOLOv5:
- yolov5/index.md
- Quickstart: yolov5/quickstart_tutorial.md
Expand Down Expand Up @@ -499,6 +501,7 @@ nav:
- object_counter: reference/solutions/object_counter.md
- queue_management: reference/solutions/queue_management.md
- speed_estimation: reference/solutions/speed_estimation.md
- parking_management: reference/solutions/parking_management.md
- trackers:
- basetrack: reference/trackers/basetrack.md
- bot_sort: reference/trackers/bot_sort.md
Expand Down
2 changes: 1 addition & 1 deletion ultralytics/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Ultralytics YOLO 🚀, AGPL-3.0 license

__version__ = "8.2.4"
__version__ = "8.2.5"

from ultralytics.data.explorer.explorer import Explorer
from ultralytics.models import RTDETR, SAM, YOLO, YOLOWorld
Expand Down
35 changes: 13 additions & 22 deletions ultralytics/solutions/heatmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,7 @@ def generate_heatmap(self, im0, tracks):
for box, cls, track_id in zip(self.boxes, self.clss, self.track_ids):
# Store class info
if self.names[cls] not in self.class_wise_count:
if len(self.names[cls]) > 5:
self.names[cls] = self.names[cls][:5]
self.class_wise_count[self.names[cls]] = {"in": 0, "out": 0}
self.class_wise_count[self.names[cls]] = {"IN": 0, "OUT": 0}

if self.shape == "circle":
center = (int((box[0] + box[2]) // 2), int((box[1] + box[3]) // 2))
Expand Down Expand Up @@ -225,10 +223,10 @@ def generate_heatmap(self, im0, tracks):

if (box[0] - prev_position[0]) * (self.counting_region.centroid.x - prev_position[0]) > 0:
self.in_counts += 1
self.class_wise_count[self.names[cls]]["in"] += 1
self.class_wise_count[self.names[cls]]["IN"] += 1
else:
self.out_counts += 1
self.class_wise_count[self.names[cls]]["out"] += 1
self.class_wise_count[self.names[cls]]["OUT"] += 1

# Count objects using line
elif len(self.count_reg_pts) == 2:
Expand All @@ -239,10 +237,10 @@ def generate_heatmap(self, im0, tracks):

if (box[0] - prev_position[0]) * (self.counting_region.centroid.x - prev_position[0]) > 0:
self.in_counts += 1
self.class_wise_count[self.names[cls]]["in"] += 1
self.class_wise_count[self.names[cls]]["IN"] += 1
else:
self.out_counts += 1
self.class_wise_count[self.names[cls]]["out"] += 1
self.class_wise_count[self.names[cls]]["OUT"] += 1

else:
for box, cls in zip(self.boxes, self.clss):
Expand All @@ -264,28 +262,21 @@ def generate_heatmap(self, im0, tracks):
heatmap_normalized = cv2.normalize(self.heatmap, None, 0, 255, cv2.NORM_MINMAX)
heatmap_colored = cv2.applyColorMap(heatmap_normalized.astype(np.uint8), self.colormap)

label = "Ultralytics Analytics \t"
labels_dict = {}

for key, value in self.class_wise_count.items():
if value["in"] != 0 or value["out"] != 0:
if value["IN"] != 0 or value["OUT"] != 0:
if not self.view_in_counts and not self.view_out_counts:
label = None
continue
elif not self.view_in_counts:
label += f"{str.capitalize(key)}: IN {value['in']} \t"
labels_dict[str.capitalize(key)] = f"OUT {value['OUT']}"
elif not self.view_out_counts:
label += f"{str.capitalize(key)}: OUT {value['out']} \t"
labels_dict[str.capitalize(key)] = f"IN {value['IN']}"
else:
label += f"{str.capitalize(key)}: IN {value['in']} OUT {value['out']} \t"
labels_dict[str.capitalize(key)] = f"IN {value['IN']} OUT {value['OUT']}"

label = label.rstrip()
label = label.split("\t")

if self.count_reg_pts is not None and label is not None:
self.annotator.display_counts(
counts=label,
count_txt_color=self.count_txt_color,
count_bg_color=self.count_bg_color,
)
if labels_dict is not None:
self.annotator.display_analytics(self.im0, labels_dict, self.count_txt_color, self.count_bg_color, 10)

self.im0 = cv2.addWeighted(self.im0, 1 - self.heatmap_alpha, heatmap_colored, self.heatmap_alpha, 0)

Expand Down
35 changes: 13 additions & 22 deletions ultralytics/solutions/object_counter.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,7 @@ def extract_and_process_tracks(self, tracks):

# Store class info
if self.names[cls] not in self.class_wise_count:
if len(self.names[cls]) > 5:
self.names[cls] = self.names[cls][:5]
self.class_wise_count[self.names[cls]] = {"in": 0, "out": 0}
self.class_wise_count[self.names[cls]] = {"IN": 0, "OUT": 0}

# Draw Tracks
track_line = self.track_history[track_id]
Expand All @@ -210,10 +208,10 @@ def extract_and_process_tracks(self, tracks):

if (box[0] - prev_position[0]) * (self.counting_region.centroid.x - prev_position[0]) > 0:
self.in_counts += 1
self.class_wise_count[self.names[cls]]["in"] += 1
self.class_wise_count[self.names[cls]]["IN"] += 1
else:
self.out_counts += 1
self.class_wise_count[self.names[cls]]["out"] += 1
self.class_wise_count[self.names[cls]]["OUT"] += 1

# Count objects using line
elif len(self.reg_pts) == 2:
Expand All @@ -224,33 +222,26 @@ def extract_and_process_tracks(self, tracks):

if (box[0] - prev_position[0]) * (self.counting_region.centroid.x - prev_position[0]) > 0:
self.in_counts += 1
self.class_wise_count[self.names[cls]]["in"] += 1
self.class_wise_count[self.names[cls]]["IN"] += 1
else:
self.out_counts += 1
self.class_wise_count[self.names[cls]]["out"] += 1
self.class_wise_count[self.names[cls]]["OUT"] += 1

label = "Ultralytics Analytics \t"
labels_dict = {}

for key, value in self.class_wise_count.items():
if value["in"] != 0 or value["out"] != 0:
if value["IN"] != 0 or value["OUT"] != 0:
if not self.view_in_counts and not self.view_out_counts:
label = None
continue
elif not self.view_in_counts:
label += f"{str.capitalize(key)}: IN {value['in']} \t"
labels_dict[str.capitalize(key)] = f"OUT {value['OUT']}"
elif not self.view_out_counts:
label += f"{str.capitalize(key)}: OUT {value['out']} \t"
labels_dict[str.capitalize(key)] = f"IN {value['IN']}"
else:
label += f"{str.capitalize(key)}: IN {value['in']} OUT {value['out']} \t"
labels_dict[str.capitalize(key)] = f"IN {value['IN']} OUT {value['OUT']}"

label = label.rstrip()
label = label.split("\t")

if label is not None:
self.annotator.display_counts(
counts=label,
count_txt_color=self.count_txt_color,
count_bg_color=self.count_bg_color,
)
if labels_dict is not None:
self.annotator.display_analytics(self.im0, labels_dict, self.count_txt_color, self.count_bg_color, 10)

def display_frames(self):
"""Display frame."""
Expand Down
Loading

0 comments on commit bc9fd45

Please sign in to comment.