Skip to content

Commit 1486471

Browse files
author
Mikhail Posevin
committed
first commit
0 parents  commit 1486471

28 files changed

+1596
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.idea
2+
*.DS_Store
3+
*.pyc
4+
*.log

api/m1_yolo/Dockerfile

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
FROM python:3.7
2+
3+
WORKDIR /opt/object_detection_video
4+
5+
RUN apt-get update
6+
RUN apt-get install ffmpeg libsm6 libxext6 -y
7+
8+
RUN /usr/local/bin/python -m pip install --upgrade pip
9+
COPY requirements.txt .
10+
RUN pip install -r requirements.txt
11+
12+
COPY app /opt/object_detection_video/app/
13+
COPY model /opt/object_detection_video/model/
14+
# COPY output /opt/object_detection_video/output/
15+
# COPY videos /opt/object_detection_video/videos/
16+
17+
18+
# for local build
19+
EXPOSE 8501
20+
CMD uvicorn app.app:app --host 0.0.0.0 --port 9000
21+

api/m1_yolo/app/app.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import fastapi
2+
from .config import VIDEO_PATH, OUTPUT_PATH
3+
from .yolo import detect_objects
4+
5+
6+
app = fastapi.FastAPI()
7+
8+
9+
@app.post("/m1_yolo")
10+
async def root(video: fastapi.UploadFile = fastapi.File(...), confidence: float = "0.5",
11+
non_max_suppression: float = "0.5", video_source: str = "nodb"):
12+
if video_source == "db":
13+
pass
14+
else:
15+
test_video = video.filename
16+
with open(config.VIDEO_PATH + test_video, "bw+") as f:
17+
f.write(video.file.read())
18+
print(f"[INFO] Processing Video....")
19+
total, elap = detect_objects(VIDEO_PATH + test_video, confidence, non_max_suppression)
20+
output_video = open(OUTPUT_PATH, 'rb')
21+
video_bytes = output_video.read()
22+
print(f"[INFO] The video has total of {total} frames")
23+
print(f"[INFO] Time required to process a single frame: {round(elap / 60, 2)} minutes")
24+
print(f"[INFO] Time required to process the entire video: {round((elap * total) / 60, 2)} minutes")
25+
return fastapi.Response(content=video_bytes, media_type="video/mp4", headers={"filename": "output.mp4",
26+
"content-disposition": "attachment"})

api/m1_yolo/app/config.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import numpy as np
2+
3+
4+
# Docker Path
5+
DIR_PATH = '/opt/object_detection_video/'
6+
7+
model = 'model/yolov3.weights'
8+
model_config = 'model/yolov3.cfg'
9+
labels = 'model/coco.names'
10+
input_videos = 'videos/'
11+
output_video = 'output/output_video.mp4'
12+
13+
MODEL_PATH = DIR_PATH + model
14+
CONFIG_PATH = DIR_PATH + model_config
15+
LABEL_PATH = DIR_PATH + labels
16+
OUTPUT_PATH = DIR_PATH + output_video
17+
INPUT_PATH = DIR_PATH + input_videos
18+
VIDEO_PATH = DIR_PATH + input_videos
19+
20+
LABELS = open(LABEL_PATH).read().strip().split('\n')
21+
22+
COLORS = np.random.randint(0, 255, size=(len(LABELS), 3), dtype='uint8')
23+
24+
DEFAULT_CONFIDENCE = 0.5
25+
NMS_THRESHOLD = 0.3
26+

api/m1_yolo/app/yolo.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import numpy as np
2+
import imutils
3+
import cv2
4+
import time
5+
from .config import MODEL_PATH, CONFIG_PATH, OUTPUT_PATH, COLORS, LABELS
6+
7+
8+
def detect_objects(video, confidence_threshold, nms_threshold):
9+
# get video frames and pass to YOLO for output
10+
11+
# load YOLO from cv2.dnn
12+
# determine only the output layer names we need from YOLO
13+
net = cv2.dnn.readNetFromDarknet(CONFIG_PATH, MODEL_PATH)
14+
ln = net.getLayerNames()
15+
ln = [ln[i - 1] for i in net.getUnconnectedOutLayers()]
16+
17+
# initialize video stream, pointer to output video file and grabbing frame dimension
18+
vs = cv2.VideoCapture(video)
19+
fps = vs.get(cv2.CAP_PROP_FPS)
20+
writer_width = int(vs.get(cv2.CAP_PROP_FRAME_WIDTH))
21+
writer_height = int(vs.get(cv2.CAP_PROP_FRAME_HEIGHT))
22+
23+
writer = None
24+
(W, H) = (None, None)
25+
26+
# determine the total number of frames in a video
27+
try:
28+
prop = cv2.CAP_PROP_FRAME_COUNT if imutils.is_cv2() else cv2.CAP_PROP_FRAME_COUNT
29+
total = int(vs.get(prop))
30+
print(f"[INFO] {total} frames in the video")
31+
32+
# if error occurs print
33+
except:
34+
print(f"[INFO] {total} frames in the video")
35+
total = -1
36+
37+
# loop over on entire video frames
38+
while True:
39+
# read next frame
40+
(grabbed, frame) = vs.read()
41+
42+
# if no frame is grabbed, we reached the end of video, so break the loop
43+
if not grabbed:
44+
break
45+
# if the frame dimensions are empty, grab them
46+
if W is None or H is None:
47+
(H, W) = frame.shape[:2]
48+
49+
# build blob and feed forward to YOLO to get bounding boxes and probability
50+
blob = cv2.dnn.blobFromImage(frame, 1 / 255.0, (416, 416), swapRB=True, crop=False)
51+
start = time.time()
52+
net.setInput(blob)
53+
layerOutputs = net.forward(ln)
54+
end = time.time()
55+
56+
# get metrics from YOLO
57+
58+
boxes = []
59+
confidences = []
60+
classIDs = []
61+
62+
# loop over each output from layeroutputs
63+
for output in layerOutputs:
64+
# loop over each detecton in output
65+
for detection in output:
66+
# extract score, ids and confidence of current object detection
67+
score = detection[5:]
68+
classID = np.argmax(score)
69+
confidence = score[classID]
70+
71+
# filter out weak detections with confidence threshold
72+
if confidence > confidence_threshold:
73+
# scale bounding box coordinates back relative to image size
74+
# YOLO spits out center (x,y) of bounding boxes followed by
75+
# boxes width and heigth
76+
box = detection[0:4] * np.array([W, H, W, H])
77+
(centerX, centerY, width, height) = box.astype('int')
78+
79+
# grab top left coordinate of the box
80+
x = int(centerX - (width / 2))
81+
y = int(centerY - (height / 2))
82+
83+
boxes.append([x, y, int(width), int(height)])
84+
confidences.append(float(confidence))
85+
classIDs.append(classID)
86+
87+
# Apply Non-Max Suppression, draw boxes and write output video
88+
89+
idxs = cv2.dnn.NMSBoxes(boxes, confidences, confidence_threshold, nms_threshold)
90+
# ensure detection exists
91+
if len(idxs) > 0:
92+
for i in idxs.flatten():
93+
# getting box coordinates
94+
(x, y) = (boxes[i][0], boxes[i][1])
95+
(w, h) = (boxes[i][2], boxes[i][3])
96+
97+
# color and draw boxes
98+
color = [int(c) for c in COLORS[classIDs[i]]]
99+
cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
100+
text = f"{LABELS[classIDs[i]]}: {confidences[i]}"
101+
cv2.putText(frame, text, (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
102+
103+
if writer is None:
104+
# initialize video writer by setting fourcc
105+
# and writing output video to output path
106+
# fourcc = cv2.VideoWriter_fourcc(*'H264')
107+
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
108+
if not fourcc:
109+
break
110+
writer = cv2.VideoWriter(OUTPUT_PATH, fourcc, fps, (writer_width, writer_height), True)
111+
112+
if total > 0:
113+
elap = (end - start)
114+
print(f"[INFO] single frame took {round(elap / 60, 2)} minutes")
115+
print(f"[INFO] total estimated time to finish: {(elap * total) / 60} minutes")
116+
117+
writer.write(frame)
118+
119+
writer.release()
120+
vs.release()
121+
122+
return total, elap

api/m1_yolo/model/coco.names

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
person
2+
bicycle
3+
car
4+
motorbike
5+
aeroplane
6+
bus
7+
train
8+
truck
9+
boat
10+
traffic light
11+
fire hydrant
12+
stop sign
13+
parking meter
14+
bench
15+
bird
16+
cat
17+
dog
18+
horse
19+
sheep
20+
cow
21+
elephant
22+
bear
23+
zebra
24+
giraffe
25+
backpack
26+
umbrella
27+
handbag
28+
tie
29+
suitcase
30+
frisbee
31+
skis
32+
snowboard
33+
sports ball
34+
kite
35+
baseball bat
36+
baseball glove
37+
skateboard
38+
surfboard
39+
tennis racket
40+
bottle
41+
wine glass
42+
cup
43+
fork
44+
knife
45+
spoon
46+
bowl
47+
banana
48+
apple
49+
sandwich
50+
orange
51+
broccoli
52+
carrot
53+
hot dog
54+
pizza
55+
donut
56+
cake
57+
chair
58+
sofa
59+
pottedplant
60+
bed
61+
diningtable
62+
toilet
63+
tvmonitor
64+
laptop
65+
mouse
66+
remote
67+
keyboard
68+
cell phone
69+
microwave
70+
oven
71+
toaster
72+
sink
73+
refrigerator
74+
book
75+
clock
76+
vase
77+
scissors
78+
teddy bear
79+
hair drier
80+
toothbrush

0 commit comments

Comments
 (0)