Skip to content

Commit 93ed41f

Browse files
Merge pull request #2180 from Killer2OP/Parking
[ADDED]: Parking Space Detection System
2 parents ace41bf + c0cb681 commit 93ed41f

File tree

5 files changed

+279
-0
lines changed

5 files changed

+279
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# OVERVIEW
2+
Finding parking space for your vehicle is a major problem in big cities. The rise of car ownership has created an imbalance between parking demand and supply. In the current situation, a parking management system that can track parking spots has become a necessity for all major cities. The system has to be scalable, efficient, reliable, and affordable at the same time. In recent years, the advances in deep learning powered computer vision algorithms have shown very promising results in a variety of tasks. Similar techniques can be used to address the problem of parking space detection.
3+
4+
how to build a simple parking space detection system using deep learning. Let's get straight to the business. We will break down our pipeline into three major components:
5+
6+
- Detection of parking spots.
7+
- Detection of cars.
8+
- Calculate IoU.
9+
10+
![Diagram](image.png)
11+
12+
On each frame of the input video, we will first use the Mask-RCNN object detection model to detect the cars and their bounding boxes. After getting the bounding boxes from the Mask-RCNN, we will compute the Intersection over Union (IoU) on each pair of the bounding boxes and parking spot coordinates. If the IoU value for any parking spot is greater than a certain threshold, we will consider that parking spot as occupied.
13+
14+
## Dependencies
15+
- Python 3.6
16+
- Tensorflow ≥1.3.0
17+
- OpenCV
18+
- Matplotlib
19+
- Shapely
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import argparse
2+
import cv2
3+
import numpy as np
4+
import pickle
5+
from pathlib import Path
6+
from shapely.geometry import Polygon as shapely_poly
7+
from mrcnn.model import MaskRCNN
8+
import mrcnn.utils
9+
import mrcnn.config
10+
import os
11+
import sys
12+
import time
13+
14+
15+
class Config(mrcnn.config.Config):
16+
NAME = "model_config"
17+
IMAGES_PER_GPU = 1
18+
GPU_COUNT = 1
19+
NUM_CLASSES = 81
20+
21+
22+
def download_model_weights(model_path):
23+
if not os.path.exists(model_path):
24+
print("Downloading pre-trained weights...")
25+
mrcnn.utils.download_trained_weights(model_path)
26+
27+
28+
def load_parking_regions(regions_path):
29+
regions_file = Path(regions_path)
30+
if regions_file.exists():
31+
with open(regions_file, 'rb') as f:
32+
parked_car_boxes = pickle.load(f)
33+
return parked_car_boxes
34+
else:
35+
print("Error: Could not find the regions file.")
36+
sys.exit(1)
37+
38+
39+
def get_car_boxes(boxes, class_ids):
40+
cars = []
41+
for i, box in enumerate(boxes):
42+
if class_ids[i] in [3, 8, 6]:
43+
cars.append(box)
44+
return np.array(cars)
45+
46+
47+
def compute_overlaps(parked_car_boxes, car_boxes):
48+
new_car_boxes = []
49+
for box in car_boxes:
50+
y1, x1, y2, x2 = box
51+
p1 = (x1, y1)
52+
p2 = (x2, y1)
53+
p3 = (x2, y2)
54+
p4 = (x1, y2)
55+
new_car_boxes.append([p1, p2, p3, p4])
56+
57+
overlaps = np.zeros((len(parked_car_boxes), len(new_car_boxes)))
58+
for i, park_area in enumerate(parked_car_boxes):
59+
for j, car_box in enumerate(new_car_boxes):
60+
polygon1_shape = shapely_poly(park_area)
61+
polygon2_shape = shapely_poly(car_box)
62+
63+
polygon_intersection = polygon1_shape.intersection(polygon2_shape).area
64+
polygon_union = polygon1_shape.union(polygon2_shape).area
65+
iou = polygon_intersection / polygon_union
66+
overlaps[i][j] = iou
67+
68+
return overlaps
69+
70+
71+
def draw_parking_area(frame, parking_area, color=(71, 27, 92), thickness=2):
72+
cv2.drawContours(frame, [np.array(parking_area)], contourIdx=-1, color=color, thickness=thickness)
73+
74+
75+
def draw_overlay(frame, overlay, alpha):
76+
cv2.addWeighted(overlay, alpha, frame, 1 - alpha, 0, frame)
77+
78+
79+
def process_video(video_path, regions_path, output_path):
80+
parked_car_boxes = load_parking_regions(regions_path)
81+
82+
config = Config()
83+
model = MaskRCNN(mode="inference", model_dir=model_dir, config=config)
84+
model_path = os.path.join(model_dir, "mask_rcnn_coco.h5")
85+
download_model_weights(model_path)
86+
model.load_weights(model_path, by_name=True)
87+
88+
alpha = 0.6
89+
video_capture = cv2.VideoCapture(video_path)
90+
video_FourCC = cv2.VideoWriter_fourcc(*'XVID')
91+
video_fps = video_capture.get(cv2.CAP_PROP_FPS)
92+
video_size = (int(video_capture.get(cv2.CAP_PROP_FRAME_WIDTH)), int(video_capture.get(cv2.CAP_PROP_FRAME_HEIGHT)))
93+
out = cv2.VideoWriter(output_path, video_FourCC, video_fps, video_size)
94+
95+
while video_capture.isOpened():
96+
success, frame = video_capture.read()
97+
if not success:
98+
break
99+
100+
start_time = time.time()
101+
rgb_image = frame[:, :, ::-1]
102+
results = model.detect([rgb_image], verbose=0)
103+
inference_time = time.time() - start_time
104+
105+
cars = get_car_boxes(results[0]['rois'], results[0]['class_ids'])
106+
overlaps = compute_overlaps(parked_car_boxes, cars)
107+
108+
overlay = frame.copy()
109+
110+
for park_area, overlap_areas in zip(parked_car_boxes, overlaps):
111+
max_iou_overlap = np.max(overlap_areas)
112+
if max_iou_overlap < 0.15:
113+
draw_parking_area(overlay, park_area)
114+
115+
draw_overlay(frame, overlay, alpha)
116+
cv2.putText(frame, f"Inference Time: {inference_time:.2f}s", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
117+
118+
cv2.imshow('Parking Space Detection', frame)
119+
out.write(frame)
120+
if cv2.waitKey(1) & 0xFF == ord('q'):
121+
break
122+
123+
video_capture.release()
124+
out.release()
125+
cv2.destroyAllWindows()
126+
print("Output saved as", output_path)
127+
128+
129+
if __name__ == "__main__":
130+
parser = argparse.ArgumentParser()
131+
parser.add_argument('video_path', help="Video file")
132+
parser.add_argument('regions_path', help="Regions file")
133+
parser.add_argument('--output', '-o', help="Output file", default="output.avi")
134+
args = parser.parse_args()
135+
136+
video_path = args.video_path
137+
regions_path = args.regions_path
138+
output_path = args.output
139+
140+
process_video(video_path, regions_path, output_path)
27.7 KB
Loading
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
scikit-image
2+
tensorflow==1.15.2
3+
keras>=2.0.8
4+
opencv-python
5+
matplotlib
6+
numpy
7+
gitpython
8+
shapely
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import os
2+
import numpy as np
3+
import cv2
4+
import pickle
5+
import argparse
6+
import matplotlib.pyplot as plt
7+
from matplotlib.patches import Polygon
8+
from matplotlib.widgets import PolygonSelector
9+
from matplotlib.collections import PatchCollection
10+
from shapely.geometry import box
11+
from shapely.geometry import Polygon as shapely_poly
12+
13+
points = []
14+
prev_points = []
15+
patches = []
16+
total_points = []
17+
breaker = False
18+
19+
20+
class SelectFromCollection(object):
21+
def __init__(self, ax):
22+
self.canvas = ax.figure.canvas
23+
24+
self.poly = PolygonSelector(ax, self.onselect)
25+
self.ind = []
26+
27+
def onselect(self, verts):
28+
global points
29+
points = verts
30+
self.canvas.draw_idle()
31+
32+
def disconnect(self):
33+
self.poly.disconnect_events()
34+
self.canvas.draw_idle()
35+
36+
37+
def break_loop(event):
38+
global breaker
39+
global globSelect
40+
global savePath
41+
if event.key == 'b':
42+
globSelect.disconnect()
43+
if os.path.exists(savePath):
44+
os.remove(savePath)
45+
46+
print("Data saved in " + savePath + " file")
47+
with open(savePath, 'wb') as f:
48+
pickle.dump(total_points, f, protocol=pickle.HIGHEST_PROTOCOL)
49+
exit()
50+
51+
52+
def onkeypress(event):
53+
global points, prev_points, total_points
54+
if event.key == 'n':
55+
pts = np.array(points, dtype=np.int32)
56+
if points != prev_points and len(set(points)) == 4:
57+
print("Points: " + str(pts))
58+
patches.append(Polygon(pts))
59+
total_points.append(pts)
60+
prev_points = points
61+
62+
63+
def process_video(video_path, out_file):
64+
global globSelect
65+
global savePath
66+
savePath = out_file if out_file.endswith(".p") else out_file + ".p"
67+
68+
print("\n> Select a region in the figure by enclosing it within a quadrilateral.")
69+
print("> Press the 'f' key to go full screen.")
70+
print("> Press the 'esc' key to discard the current quadrilateral.")
71+
print("> Try holding the 'shift' key to move all of the vertices.")
72+
print("> Try holding the 'ctrl' key to move a single vertex.")
73+
print("> After marking a quadrilateral, press 'n' to save the current quadrilateral, and then press 'q' to start marking a new quadrilateral.")
74+
print("> When you are done, press 'b' to exit the program.\n")
75+
76+
video_capture = cv2.VideoCapture(video_path)
77+
cnt = 0
78+
rgb_image = None
79+
while video_capture.isOpened():
80+
success, frame = video_capture.read()
81+
if not success:
82+
break
83+
if cnt == 5:
84+
rgb_image = frame[:, :, ::-1]
85+
cnt += 1
86+
video_capture.release()
87+
88+
fig, ax = plt.subplots()
89+
image = rgb_image
90+
ax.imshow(image)
91+
92+
p = PatchCollection(patches, alpha=0.7)
93+
p.set_array(10 * np.ones(len(patches)))
94+
ax.add_collection(p)
95+
96+
globSelect = SelectFromCollection(ax)
97+
bbox = plt.connect('key_press_event', onkeypress)
98+
break_event = plt.connect('key_press_event', break_loop)
99+
plt.show()
100+
globSelect.disconnect()
101+
102+
103+
if __name__ == '__main__':
104+
parser = argparse.ArgumentParser()
105+
parser.add_argument('video_path', help="Path of the video file")
106+
parser.add_argument('--out_file', help="Name of the output file", default="regions.p")
107+
args = parser.parse_args()
108+
109+
video_path = args.video_path
110+
out_file = args.out_file
111+
112+
process_video(video_path, out_file)

0 commit comments

Comments
 (0)