Skip to content

Commit 2ed3fae

Browse files
Merge pull request #928 from Jaykumaran/master
update readme
2 parents 29cd4b7 + 4175dd0 commit 2ed3fae

File tree

7 files changed

+3532
-0
lines changed

7 files changed

+3532
-0
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Object Detection on Edge Device
2+
3+
**This repository contains code for [Object Detection on Edge Device - OAK-D-Lite](https://learnopencv.com/object-detection-on-edge-device) blogpost**.
4+
5+
---
6+
7+
![](readme_images/Feature-image.gif)
8+
9+
[<img src="https://learnopencv.com/wp-content/uploads/2022/07/download-button-e1657285155454.png" alt="download" width="200">](https://www.dropbox.com/scl/fi/9itcfugejlcf11v2fcb33/Deployment-YOLOv8-OAK-D-Lite.zip?rlkey=vpag2p6x1ifhfj70ydhkiqkly&st=mw9d0j3e&dl=1)
10+
11+
12+
13+
# AI Courses by OpenCV
14+
15+
Want to become an expert in AI? [AI Courses by OpenCV](https://opencv.org/courses/) is a great place to start.
16+
17+
<a href="https://opencv.org/courses/">
18+
19+
<p align="center">
20+
<img src="https://learnopencv.com/wp-content/uploads/2023/01/AI-Courses-By-OpenCV-Github.png">
21+
</p>
22+
</a>
23+

Object-Detection-on-Edge-Devices/YOLOv8-Pothole-Training.ipynb

Lines changed: 3117 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# !python3 -m pip install depthai
2+
3+
import os
4+
import json
5+
import numpy as np
6+
import cv2
7+
from pathlib import Path
8+
import depthai as dai
9+
import time
10+
11+
# Define path to the model and configuration
12+
YOLOV8N_MODEL = "Yolov8-2022.1-blob/yolov8n-pothole-best_openvino_2022.1_8shave.blob" #Adjust path accordingly
13+
YOLOV8N_CONFIG = "Yolov8-2022.1-blob/yolov8n-pothole-best.json" #Adjust path accordingly
14+
15+
OUTPUT_VIDEO = "vid_result/960-oak-d-live_video.mp4" #Adjust path accordingly
16+
17+
CAMERA_PREV_DIM = (960, 960)
18+
LABELS = ["Pot-hole"]
19+
20+
def load_config(config_path):
21+
with open(config_path) as f:
22+
return json.load(f)
23+
24+
def create_camera_pipeline(config_path, model_path):
25+
pipeline = dai.Pipeline()
26+
model_config = load_config(config_path)
27+
nnConfig = model_config.get("nn_config", {})
28+
metadata = nnConfig.get("NN_specific_metadata", {})
29+
classes = metadata.get("classes", {})
30+
coordinates = metadata.get("coordinates", {})
31+
anchors = metadata.get("anchors", {})
32+
anchorMasks = metadata.get("anchor_masks", {})
33+
iouThreshold = metadata.get("iou_threshold", {})
34+
confidenceThreshold = metadata.get("confidence_threshold", {})
35+
36+
# Create camera node
37+
camRgb = pipeline.create(dai.node.ColorCamera)
38+
camRgb.setPreviewSize(CAMERA_PREV_DIM[0], CAMERA_PREV_DIM[1])
39+
camRgb.setInterleaved(False)
40+
camRgb.setBoardSocket(dai.CameraBoardSocket.RGB)
41+
camRgb.setResolution(dai.ColorCameraProperties.SensorResolution.THE_1080_P)
42+
43+
detectionNetwork = pipeline.create(dai.node.YoloDetectionNetwork)
44+
nnOut = pipeline.create(dai.node.XLinkOut)
45+
46+
nnOut.setStreamName("nn")
47+
48+
detectionNetwork.setConfidenceThreshold(confidenceThreshold)
49+
detectionNetwork.setNumClasses(classes)
50+
detectionNetwork.setCoordinateSize(coordinates)
51+
detectionNetwork.setAnchors(anchors)
52+
detectionNetwork.setAnchorMasks(anchorMasks)
53+
detectionNetwork.setIouThreshold(iouThreshold)
54+
detectionNetwork.setBlobPath(model_path)
55+
detectionNetwork.setNumInferenceThreads(2)
56+
detectionNetwork.input.setBlocking(False)
57+
58+
# Linking
59+
camRgb.preview.link(detectionNetwork.input)
60+
detectionNetwork.out.link(nnOut.input)
61+
62+
return pipeline
63+
64+
def annotate_frame(frame, detections, fps):
65+
color = (0, 0, 255)
66+
for detection in detections:
67+
bbox = frame_norm(frame, (detection.xmin, detection.ymin, detection.xmax, detection.ymax))
68+
cv2.putText(frame, LABELS[detection.label], (bbox[0] + 10, bbox[1] + 25), cv2.FONT_HERSHEY_TRIPLEX, 1, color)
69+
cv2.putText(frame, f"{int(detection.confidence * 100)}%", (bbox[0] + 10, bbox[1] + 60), cv2.FONT_HERSHEY_TRIPLEX, 1, color)
70+
cv2.rectangle(frame, (bbox[0], bbox[1]), (bbox[2], bbox[3]), color, 2)
71+
72+
# Annotate the frame with the FPS
73+
cv2.putText(frame, f"FPS: {fps:.2f}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
74+
return frame
75+
76+
def to_planar(arr: np.ndarray, shape: tuple) -> np.ndarray:
77+
resized = cv2.resize(arr, shape)
78+
return resized.transpose(2, 0, 1)
79+
80+
def frame_norm(frame, bbox):
81+
norm_vals = np.full(len(bbox), frame.shape[0])
82+
norm_vals[::2] = frame.shape[1]
83+
return (np.clip(np.array(bbox), 0, 1) * norm_vals).astype(int)
84+
85+
# Create pipeline
86+
pipeline = create_camera_pipeline(YOLOV8N_CONFIG, YOLOV8N_MODEL)
87+
88+
# Ensure output directory exists
89+
os.makedirs(os.path.dirname(OUTPUT_VIDEO), exist_ok=True)
90+
91+
# Connect to device and start pipeline
92+
with dai.Device(pipeline) as device:
93+
# Define the queue that will be used to receive the neural network output
94+
detectionNN = device.getOutputQueue("nn", maxSize=4, blocking=False)
95+
96+
# Video writer to save the output video
97+
fps = 30 # Assuming 30 FPS for the OAK-D camera
98+
frame_width, frame_height = CAMERA_PREV_DIM
99+
out = cv2.VideoWriter(OUTPUT_VIDEO, cv2.VideoWriter_fourcc(*'mp4v'), fps, (frame_width, frame_height))
100+
101+
start_time = time.time()
102+
frame_count = 0
103+
104+
while True:
105+
inDet = detectionNN.get()
106+
detections = []
107+
if inDet is not None:
108+
detections = inDet.detections
109+
print("Detections", detections)
110+
111+
# Retrieve the frame from the camera preview
112+
frame = inDet.getFrame()
113+
frame_count += 1
114+
115+
# Calculate the FPS
116+
elapsed_time = time.time() - start_time
117+
fps = frame_count / elapsed_time if elapsed_time > 0 else 0
118+
119+
# Annotate the frame with detections and FPS
120+
frame = annotate_frame(frame, detections, fps)
121+
122+
# Display the frame
123+
cv2.imshow("Frame", frame)
124+
125+
# Write the frame to the output video
126+
out.write(frame)
127+
128+
# Break the loop if 'q' is pressed
129+
if cv2.waitKey(1) & 0xFF == ord('q'):
130+
break
131+
132+
out.release()
133+
cv2.destroyAllWindows()
134+
135+
print(f"[INFO] Processed live stream and saved to {OUTPUT_VIDEO}")
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
#Install Dependencies
2+
# !python3 -m pip install depthai
3+
4+
import os
5+
import json
6+
import numpy as np
7+
import cv2
8+
from pathlib import Path
9+
import depthai as dai
10+
import time
11+
12+
# Define path to the model, test data directory, and results
13+
14+
YOLOV8N_MODEL = "/home/jaykumaran/Blogs/Poth-hole-Detection/Final Media/Yolov8-2022.1-blob/yolov8n-pothole-best_openvino_2022.1_8shave.blob" #Adjust path accordingly
15+
YOLOV8N_CONFIG = "/home/jaykumaran/Blogs/Poth-hole-Detection/Final Media/Yolov8-2022.1-blob/yolov8n-pothole-best.json" #Adjust path accordingly
16+
17+
INPUT_VIDEO = "videoplayback.mp4"
18+
OUTPUT_VIDEO = "vid_result/960-oak-d-videoplayback_video.mp4"
19+
20+
CAMERA_PREV_DIM = (960, 960)
21+
LABELS = ["Pot-hole"]
22+
23+
def load_config(config_path):
24+
with open(config_path) as f:
25+
return json.load(f)
26+
27+
28+
29+
def create_image_pipeline(config_path, model_path):
30+
pipeline = dai.Pipeline()
31+
model_config = load_config(config_path)
32+
nnConfig = model_config.get("nn_config", {})
33+
metadata = nnConfig.get("NN_specific_metadata", {})
34+
classes = metadata.get("classes", {})
35+
coordinates = metadata.get("coordinates", {})
36+
anchors = metadata.get("anchors", {})
37+
anchorMasks = metadata.get("anchor_masks", {})
38+
iouThreshold = metadata.get("iou_threshold", {})
39+
confidenceThreshold = metadata.get("confidence_threshold", {})
40+
41+
detectionIN = pipeline.create(dai.node.XLinkIn)
42+
detectionNetwork = pipeline.create(dai.node.YoloDetectionNetwork)
43+
nnOut = pipeline.create(dai.node.XLinkOut)
44+
45+
nnOut.setStreamName("nn")
46+
detectionIN.setStreamName("detection_in")
47+
48+
detectionNetwork.setConfidenceThreshold(confidenceThreshold)
49+
detectionNetwork.setNumClasses(classes)
50+
detectionNetwork.setCoordinateSize(coordinates)
51+
detectionNetwork.setAnchors(anchors)
52+
detectionNetwork.setAnchorMasks(anchorMasks)
53+
detectionNetwork.setIouThreshold(iouThreshold)
54+
detectionNetwork.setBlobPath(model_path)
55+
detectionNetwork.setNumInferenceThreads(2)
56+
detectionNetwork.input.setBlocking(False)
57+
# Linking
58+
detectionIN.out.link(detectionNetwork.input)
59+
detectionNetwork.out.link(nnOut.input)
60+
61+
return pipeline
62+
63+
def annotate_frame(frame, detections, fps):
64+
color = (0, 0, 255)
65+
for detection in detections:
66+
bbox = frame_norm(frame, (detection.xmin, detection.ymin, detection.xmax, detection.ymax))
67+
cv2.putText(frame, LABELS[detection.label], (bbox[0] + 10, bbox[1] + 25), cv2.FONT_HERSHEY_TRIPLEX, 1, color)
68+
cv2.putText(frame, f"{int(detection.confidence * 100)}%", (bbox[0] + 10, bbox[1] + 60), cv2.FONT_HERSHEY_TRIPLEX, 1, color)
69+
cv2.rectangle(frame, (bbox[0], bbox[1]), (bbox[2], bbox[3]), color, 2)
70+
71+
# Annotate the frame with the FPS
72+
cv2.putText(frame, f"FPS: {fps:.2f}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
73+
return frame
74+
75+
def to_planar(arr: np.ndarray, shape: tuple) -> np.ndarray:
76+
resized = cv2.resize(arr, shape)
77+
return resized.transpose(2, 0, 1)
78+
79+
def frame_norm(frame, bbox):
80+
norm_vals = np.full(len(bbox), frame.shape[0])
81+
norm_vals[::2] = frame.shape[1]
82+
return (np.clip(np.array(bbox), 0, 1) * norm_vals).astype(int)
83+
84+
# Create pipeline
85+
pipeline = create_image_pipeline(YOLOV8N_CONFIG, YOLOV8N_MODEL)
86+
87+
# Ensure output directory exists
88+
os.makedirs(os.path.dirname(OUTPUT_VIDEO), exist_ok=True)
89+
90+
cap = cv2.VideoCapture(INPUT_VIDEO)
91+
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
92+
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
93+
fps = cap.get(cv2.CAP_PROP_FPS)
94+
out = cv2.VideoWriter(OUTPUT_VIDEO, cv2.VideoWriter_fourcc(*'mp4v'), fps, (frame_width, frame_height))
95+
96+
# Connect to device and start pipeline
97+
with dai.Device(pipeline) as device:
98+
# Define the queues that will be used in order to communicate with depthai
99+
detectionIN = device.getInputQueue("detection_in")
100+
detectionNN = device.getOutputQueue("nn")
101+
102+
start_time = time.time()
103+
frame_count = 0
104+
105+
while cap.isOpened():
106+
ret, frame = cap.read()
107+
if not ret:
108+
break
109+
110+
frame_count += 1
111+
112+
image_res = cv2.resize(frame, CAMERA_PREV_DIM)
113+
114+
# Initialize depthai NNData() class which is fed with the image data resized and transposed to model input shape
115+
nn_data = dai.NNData()
116+
nn_data.setLayer("input", to_planar(frame, CAMERA_PREV_DIM))
117+
118+
# Send the image to detectionIN queue further passed to the detection network for inference as defined in pipeline
119+
detectionIN.send(nn_data)
120+
121+
# Fetch the neural network output
122+
inDet = detectionNN.get()
123+
detections = []
124+
if inDet is not None:
125+
detections = inDet.detections
126+
print("Detections", detections)
127+
128+
# Calculate the FPS
129+
elapsed_time = time.time() - start_time
130+
fps = frame_count / elapsed_time if elapsed_time > 0 else 0
131+
132+
# Annotate the frame with detections and FPS
133+
frame = annotate_frame(frame, detections, fps)
134+
135+
out.write(frame)
136+
137+
cap.release()
138+
out.release()
139+
140+
print(f"[INFO] Processed video {INPUT_VIDEO} and saved to {OUTPUT_VIDEO}")

0 commit comments

Comments
 (0)