Object Detection Using Python (Part 2)

PUTRI ERMAYANI
6 min readJan 10, 2021

--

Assalamualaikum Warahmatullahi Wabarakatuh.

Pada kesempatan ini akan dibahas penggunaan object detection YOLO untuk mendeteksi objek video menggunakan Deep Learning, OpenCV, dan Python. Sebelumnya telah dibahas penggunaaan object detection YOLO untuk mendeteksi objek pada gambar pada Object Detection Using Python (Part 1).

Langsung saja kita uraikan skrip yang digunakan. Skrip akan dibuat di notepad, maka simpan file sebagai “yolo_video.py” terlebih dahulu. Sama seperti object detection pada gambar, skrip awal akan dilakukan impor package dan membangun argumen parse dengan perintah sebagai berikut.

# import the necessary packages
import numpy as np
import argparse
import imutils
import time
import cv2
import os
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument(“-i”, “--input”, required=True,help=”path to input video”)
ap.add_argument(“-o”, “--output”, required=True,help=”path to output video”)
ap.add_argument(“-y”, “--yolo”, required=True,help=”base path to YOLO directory”)
ap.add_argument(“-c”, “--confidence”, type=float, default=0.5,help=”minimum probability to filter weak detections”)
ap.add_argument(“-t”, “--threshold”, type=float, default=0.3,help=”threshold when applyong non-maxima suppression”)
args = vars(ap.parse_args())

Pada skrip tersebut terlihat perbedaan dari skrip sebelumnya pada argumen parse yang digunakan. Skrip tersebut tidak terdapat argumen “--image”, namun digunakan 2 argumen lainnya yaitu “- -input” dan “- -output”.

Skrip selanjutnya untuk memuat label kelas COCO tempat model YOLO dilatih, mengatur warna acak untuk masing-masing label, turunkan jalur ke bobot YOLO dan konfigurasi model, serta memuat object detector YOLO yang dilatih pada kumpulan data COCO. Skrip ini identik dengan skrip yang digunakan untuk object detection pada gambar.

# load the COCO class labels our YOLO model was trained on
labelsPath = os.path.sep.join([args["yolo"], "coco.names"])
LABELS = open(labelsPath).read().strip().split("\n")
# initialize a list of colors to represent each possible class label
np.random.seed(42)
COLORS = np.random.randint(0, 255, size=(len(LABELS), 3),
dtype="uint8")
# derive the paths to the YOLO weights and model configuration
weightsPath = os.path.sep.join([args["yolo"], "yolov3.weights"])
configPath = os.path.sep.join([args["yolo"], "yolov3.cfg"])
# load our YOLO object detector trained on COCO dataset (80 classes)
# and determine only the *output* layer names that we need from YOLO
print("[INFO] loading YOLO from disk...")
net = cv2.dnn.readNetFromDarknet(configPath, weightsPath)
ln = net.getLayerNames()
ln = [ln[i[0] - 1] for i in net.getUnconnectedOutLayers()]

Selanjutnya, dibuat skrip untuk menangani khusus video.

# initialize the video stream, pointer to output video file, and
# frame dimensions
vs = cv2.VideoCapture(args["input"])
writer = None
(W, H) = (None, None)
# try to determine the total number of frames in the video file
try:
prop = cv2.cv.CV_CAP_PROP_FRAME_COUNT if imutils.is_cv2() \
else cv2.CAP_PROP_FRAME_COUNT
total = int(vs.get(prop))
print("[INFO] {} total frames in video".format(total))
# an error occurred while trying to determine the total
# number of frames in the video file
except:
print("[INFO] could not determine # of frames in video")
print("[INFO] no approx. completion time can be provided")
total = -1

Pada skrip tersebut terdapat perintah:

  1. Inisialisasi video “writer” dan dimensi frame.
  2. Menentukan “total” jumlah frame dalam file video sehingga dapat memperkirakan berapa lama waktu yang dibutuhkan untuk memproses seluruh video.

Kemudian mulai proses frame satu per satu dengan perintah sebagai berikut.

# loop over frames from the video file stream
while True:
# read the next frame from the file
(grabbed, frame) = vs.read()
# if the frame was not grabbed, then we have reached the end
# of the stream
if not grabbed:
break
# if the frame dimensions are empty, grab them
if W is None or H is None:
(H, W) = frame.shape[:2]

Selanjutnya, lakukan forward pass YOLO menggunakan arus “frame” sebagai input. Di sini akan dibangun “blob” dan menyebarkannya melalui jaringan untuk mendapatkan prediksi. Skrip dibuat untuk mengelilingi operasi forward pass dengan stempel waktu sehingga dapat menghitung waktu yang dihabiskan untuk membuat prediksi pada satu frame, hal tersebut akan membantu dalam memperkirakan waktu yang diperlukan untuk memproses keseluruhan video. Selain itu, terdapat skrip yang melanjutkan dan menginisialisasi tiga daftar yang sama yang digunakan di skrip pada pembahasan sebelumnya: “boxes”, “confidence”, dan “classID”. Berikut adalah skrip yang digunakan.

# construct a blob from the input frame and then perform a forward
# pass of the YOLO object detector, giving us our bounding boxes
# and associated probabilities
blob = cv2.dnn.blobFromImage(frame, 1 / 255.0, (416, 416),
swapRB=True, crop=False)
net.setInput(blob)
start = time.time()
layerOutputs = net.forward(ln)
end = time.time()
# initialize our lists of detected bounding boxes, confidences,
# and class IDs, respectively
boxes = []
confidences = []
classIDs = []

Skrip selanjutnya akan mulai mengisi daftar ini dengan data dari YOLO “layerOutputs”, skrip yang digunakan juga identik dengan pembahasan sebelumnya yaitu sebagai berikut.

# loop over each of the layer outputs
for output in layerOutputs:
# loop over each of the detections
for detection in output:
# extract the class ID and confidence (i.e., probability) of
# the current object detection
scores = detection[5:]
classID = np.argmax(scores)
confidence = scores[classID]
# filter out weak predictions by ensuring the detected
# probability is greater than the minimum probability
if confidence > args["confidence"]:
# scale the bounding box coordinates back relative to the
# size of the image, keeping in mind that YOLO actually
# returns the center (x, y)-coordinates of the bounding
# box followed by the boxes' width and height
box = detection[0:4] * np.array([W, H, W, H])
(centerX, centerY, width, height) = box.astype("int")
# use the center (x, y)-coordinates to derive the top and
# and left corner of the bounding box
x = int(centerX - (width / 2))
y = int(centerY - (height / 2))
# update our list of bounding box coordinates, confidences,
# and class IDs
boxes.append([x, y, int(width), int(height)])
confidences.append(float(confidence))
classIDs.append(classID)

Kemudian menerapkan penekanan non-maxima dan mulai melanjutkan memberi anotasi pada frame dengan perintah sebagai berikut.

# apply non-maxima suppression to suppress weak, overlapping
# bounding boxes
idxs = cv2.dnn.NMSBoxes(boxes, confidences, args["confidence"],
args["threshold"])
# ensure at least one detection exists
if len(idxs) > 0:
# loop over the indexes we are keeping
for i in idxs.flatten():
# extract the bounding box coordinates
(x, y) = (boxes[i][0], boxes[i][1])
(w, h) = (boxes[i][2], boxes[i][3])
# draw a bounding box rectangle and label on the frame
color = [int(c) for c in COLORS[classIDs[i]]]
cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
text = "{}: {:.4f}".format(LABELS[classIDs[i]],
confidences[i])
cv2.putText(frame, text, (x, y - 5),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)

Skrip terakhir adalah sebagai berikut.

# check if the video writer is None
if writer is None:
# initialize our video writer
fourcc = cv2.VideoWriter_fourcc(*"MJPG")
writer = cv2.VideoWriter(args["output"], fourcc, 30,
(frame.shape[1], frame.shape[0]), True)
# some information on processing single frame
if total > 0:
elap = (end - start)
print("[INFO] single frame took {:.4f} seconds".format(elap))
print("[INFO] estimated total time to finish: {:.4f}".format(
elap * total))
# write the output frame to disk
writer.write(frame)
# release the file pointers
print("[INFO] cleaning up...")
writer.release()
vs.release()

Skrip tersebut meliputi perintah untuk :

  • Inisialisasi video “writer” jika ada, maka penulis akan diinisialisasi pada iterasi pertama dari loop.
  • Cetak perkiraan tentang berapa lama waktu yang dibutuhkan untuk memproses video.
  • Tulis “frame” ke file video output.

Setelah semua skrip selesai dan tersimpan dalam file “yolo_video.py”, kita dapat menjalankan perintah untuk object detection video pada command prompt. Video yang digunakan adalah higway traffic yang telah di download sebelumnya, gunakan perintah “python yolo_video.py --input videos/ highway_traffic.mp4 --output output/ highway_traffic_output.avi --yolo yolo-coco”.

Dapat dilihat bahwa telah berhasil dilakukan object detection video higgway_traffic.mp4 pada video yang telah diubah menjadi format gif berikut.

highway_traffic_output.gif

Oke, cukup sekian pembahasan Object Detection video dengan Python. Semoga Bermanfaat.

--

--