Python: распознавание объектов в реальном времени


В этой статье мы будем разбирать код программы, в которой используется Deep Learning и OpenCV. Её суть: распознавание объектов в реальном времени.

Этот пост разделён на две части. В первой части мы рассмотрим реализацию распознавания объектов в реальном времени, используем deep-learning и OpenCV, чтобы работать с видео потоками и видеофайлами. В этом нам поможет высокоэффективный класс VideoStream, подробнее о нём читайте здесь.
Оттуда мы возьмём Deep Learning, код для обнаружения объекта и код для измерения FPS.

Часть 1: распознавание объектов в реальном времени — работаем с кодом

Чтобы сделать детектор объектов в реальном времени, нам потребуется:
  1. Получить доступ к нашей веб-камере/видео потоку.
  2. Применить распознавание объекта для каждого кадра.
Чтобы посмотреть, как это делается, откройте новый файл, назовите его real_time_object_detection.py и вставьте следующий код:
# import the necessary packages
from imutils.video import VideoStream
from imutils.video import FPS
import numpy as np
import argparse
import imutils
import time
import cv2
Мы начали с импортирования библиотек (на строках 2-8). Для этого вам необходим imutils и OpenCV.

Пишем код для работы с командной строкой.

Далее анализируем аргументы командной строки:
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-p", "--prototxt", required=True,
 help="path to Caffe 'deploy' prototxt file")
ap.add_argument("-m", "--model", required=True,
 help="path to Caffe pre-trained model")
ap.add_argument("-c", "--confidence", type=float, default=0.2,
 help="minimum probability to filter weak detections")
args = vars(ap.parse_args())
  • —prototxt : Путь к prototxt Caffe файлу.
  • —model : Путь к предварительно подготовленной модели.
  • —confidence : Минимальный порог валидности (сходства) для распознавания объекта (значение по умолчанию — 20%).

Добавляем основные объекты.

Затем мы инициализируем список классов и набор цветов:
# initialize the list of class labels MobileNet SSD was trained to
# detect, then generate a set of bounding box colors for each class
CLASSES = ["background", "aeroplane", "bicycle", "bird", "boat",
 "bottle", "bus", "car", "cat", "chair", "cow", "diningtable",
 "dog", "horse", "motorbike", "person", "pottedplant", "sheep",
 "sofa", "train", "tvmonitor"]
COLORS = np.random.uniform(0, 255, size=(len(CLASSES), 3))
Теперь загрузим модель и настроим наш видео поток:
# load our serialized model from disk
print("[INFO] loading model...")
net = cv2.dnn.readNetFromCaffe(args["prototxt"], args["model"])
 
# initialize the video stream, allow the cammera sensor to warmup,
# and initialize the FPS counter
print("[INFO] starting video stream...")
vs = VideoStream(src=0).start()
time.sleep(2.0)
fps = FPS().start()
Загружаем нашу сериализованную модель, предоставляя ссылки на prototxt и модели (строка 30) — обратите внимание, насколько это просто в OpenCV.
Затем инициализируем видео поток (это может быть видеофайл или веб-камера). Сначала запускаем VideoStream, затем мы ждём, пока камера включится, и наконец, начинаем отсчёт кадров в секунду. Классы VideoStream и FPS являются частью пакета imutils.

Пишем код для работы с кадрами.

Теперь проходим по каждому кадру (чтобы увеличить скорость, можно пропускать кадры).
# loop over the frames from the video stream
while True:
 # grab the frame from the threaded video stream and resize it
 # to have a maximum width of 400 pixels
 frame = vs.read()
 frame = imutils.resize(frame, width=400)
 
 # grab the frame dimensions and convert it to a blob
 (h, w) = frame.shape[:2]
 blob = cv2.dnn.blobFromImage(cv2.resize(frame, (300, 300)),
 0.007843, (300, 300), 127.5)
 
 # pass the blob through the network and obtain the detections and
 # predictions
 net.setInput(blob)
 detections = net.forward()
Первое, что мы делаем — считываем кадр из потока, затем заменяем его размер.

Поскольку чуть позже нам понадобится ширина и высота, получим их сейчас. Затем следует преобразование кадра в blob с модулем dnn.

Теперь к сложному: мы устанавливаем blob как входные данные в нашу нейросеть и передаём эти данные через net, которая обнаруживает наши предметы.

«Фильтруем» объекты.

На данный момент, мы обнаружили объекты в видео потоке. Теперь пришло время посмотреть на значения валидности и решить, должны ли мы нарисовать квадрат вокруг объекта и повесить лейбл.
# loop over the detections
 for i in np.arange(0, detections.shape[2]):
 # extract the confidence (i.e., probability) associated with
 # the prediction
 confidence = detections[0, 0, i, 2]
 
 # filter out weak detections by ensuring the `confidence` is
 # greater than the minimum confidence
 if confidence > args["confidence"]:
 # extract the index of the class label from the
 # `detections`, then compute the (x, y)-coordinates of
 # the bounding box for the object
 idx = int(detections[0, 0, i, 1])
 box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
 (startX, startY, endX, endY) = box.astype("int")
 
 # draw the prediction on the frame
 label = "{}: {:.2f}%".format(CLASSES[idx],
 confidence * 100)
 cv2.rectangle(frame, (startX, startY), (endX, endY),
 COLORS[idx], 2)
 y = startY - 15 if startY - 15 > 15 else startY + 15
 cv2.putText(frame, label, (startX, y),
 cv2.FONT_HERSHEY_SIMPLEX, 0.5, COLORS[idx], 2)

Мы начинаем проходить циклами через наши detections, помня, что несколько объектов могут быть восприняты как единое изображение. Мы также делаем проверку на валидность (т.е. вероятность) для каждого обнаружения. Если валидность достаточно велика (т.е. выше заданного порога), отображаем предсказание в терминале, а также рисуем на видео потоке предсказание (обводим объект в цветной прямоугольник и вешаем лейбл).
Давайте разберём по строчкам:
Проходим по detections, получаем значение валидности.
Если значение валидности выше заданного порога, извлекаем индекс лейбла в классе и высчитываем координаты рамки вокруг обнаруженного объекта.
Затем, извлекаем (x;y)-координаты рамки, которые будем использовать для отображения прямоугольника и текста.
Делаем текстовый лейбл, содержащую имя из CLASS и значение валидности.
Также, рисуем цветной прямоугольник вокруг объекта, используя цвета класса и раннее извлечённые (x;y)-координаты.
В целом, нужно, чтобы лейбл располагался над цветным прямоугольником, однако, может возникнуть такая ситуация, что сверху будет недостаточно места, поэтому в таких случаях выводим лейбл под верхней стороной прямоугольника.
Наконец, мы накладываем цветной текст и рамку на кадр, используя значение ‘y’, которое мы только что вычислили.

Оставшиеся задачи:

  1. Отображение кадра
  2. Проверка ключа выхода
  3. Обновление счётчика FPS
# show the output frame
 cv2.imshow("Frame", frame)
 key = cv2.waitKey(1) & 0xFF
 
 # if the `q` key was pressed, break from the loop
 if key == ord("q"):
 break
 
 # update the FPS counter
 fps.update()

Код вверху довольно очевиден: во-первых, выводим кадр. Затем фиксируем нажатие клавиши, проверяя, не нажата ли клавиша «q» (quit). Если условие истинно, мы выходим из цикла.
Наконец, обновляем наш счётчик FPS.
Если происходит выход из цикла (нажатие клавиши «q» или конец видео потока), у нас есть вещи, о которых следует позаботиться:
# stop the timer and display FPS information
fps.stop()
print("[INFO] elapsed time: {:.2f}".format(fps.elapsed()))
print("[INFO] approx. FPS: {:.2f}".format(fps.fps()))
 
# do a bit of cleanup
cv2.destroyAllWindows()
vs.stop()
При выходе из цикла, останавливаем счётчик FPS и выводим информацию о конечном значении FPS в терминал.
Закрываем окно программы, прекращая видео поток.
Если вы зашли так далеко, вероятно, вы готовы попробовать программу на своей веб-камере. Чтобы посмотреть, как это делается, перейдём к следующему разделу.

Часть 2: тестируем распознавание объектов в реальном времени на веб-камере

Чтобы увидеть детектор объектов в реальном времени в действии, убедитесь, что вы скачали исходники и предварительно подготовленную Convolutional Neural Network.
Оттуда открываете терминал и выполняете следующие команды:
python real_time_object_detection.py \
 --prototxt MobileNetSSD_deploy.prototxt.txt \
 --model MobileNetSSD_deploy.caffemodel
[INFO] loading model...
[INFO] starting video stream...
[INFO] elapsed time: 55.07
[INFO] approx. FPS: 6.54
При условии, что OpenCV может получить доступ к вашей веб-камере, вы должны увидеть выходной кадр с любыми обнаруженными объектами. 
Заметьте, что распознаватель объектов может обнаруживать не только меня (человека), но и диван, на котором я сижу и стул рядом со мной. И всё это в реальном времени.
Код тут.
Оригинал статьи тут.
Добавить комментарий

Оставить комментарий