Как обнаруживать обьекты на изображениях

Как обнаруживать обьекты на изображениях

YOLO– это эффективный алгоритмический метод выделения объектов изображения. Мы будем использовать его для написания программы на языке Python, чтобы вычислить число людей в комнате, и попытаемся разгадать капчу. И тут же научимся как обнаруживать обьекты на изображениях.

Распознавание объектов сегодня полезно для решения самых разных задач: классификации видов растений и животных, распознавания лиц, определения размеров объектов — и это далеко не полный список.

Виды алгоритмов

Существует множество алгоритмов обнаружения объектов, которые были сделаны на изображениях и видео. А что они собой представляют сейчас будем разбирать.

Fast R-CNN, Fast Region-Based Convolutional Neural Network

Подход аналогичен алгоритму R-CNN. Но вместо предварительного выделения областей мы передаем входное изображение в CNN для создания сверточной карты ресурсов, где будет выполняться выборочный поиск, а специальный слой Softmax выполняет прогнозирование класса ресурсов.

Обработка в реальном времени: не поддерживается.

YOLO, You Only Look Once

Изображение разделено на квадратную сетку. Для каждой ячейки в сети CNN отображает вероятности присвоенного класса. Ячейки с вероятностью класса выше порога выбираются и используются для определения местоположения объекта на изображении.

Обработка в реальном времени: поддерживается!

R-CNN, Region-Based Convolutional Neural Network

Сначала на изображении с помощью алгоритма выборочного поиска выбираются области, которые должны содержать объект. Затем сверточная нейронная сеть (CNN) пытается идентифицировать характеристики объектов для каждой из этих областей, после чего вспомогательная векторная машина классифицирует полученные данные и сообщает класс обнаруженного объекта

.Обработка в реальном времени: не поддерживается.

Faster R-CNN, Faster Region-Based Convolutional Neural Network

Как и Fast R-CNN, изображение передается в CNN для создания сверточной карты симптомов, но вместо алгоритма выборочной проверки используется отдельная сеть для прогнозирования предложений по регионам.

Обработка в реальном времени: поддерживается при высокой вычислительной мощности.

Как видите, YOLO по-прежнему является лучшим выбором для обнаружения и распознавания образов. Он отличается высокой скоростью и точностью обнаружения объектов, и этот алгоритм также можно использовать в проектах на Android и Raspberry Pi с использованием нетребовательной крошечной версии сети, с которой мы будем работать с вами сегодня.

Версия Tiny немного проигрывает именно полноценной сетевой версии, но также требует меньших вычислительных мощностей, что позволит нам запустить проект, который мы будем делать сегодня, как на слабом компьютере, так и, при необходимости, на смартфоне.

Код

Что­бы написать лег­ковес­ное при­ложе­ние для обна­руже­ния объ­ектов на изоб­ражении, нам с тобой понадо­бят­ся:

До­пол­нитель­но уста­новим биб­лиоте­ки OpenCV и NumPy:

pip install opencv-python

pip install numpy

Те­перь напишем при­ложе­ние, которое будет находить объ­екты на изоб­ражении при помощи YOLO и отме­чать их.

Мы попытаемся обойти изображения грузовиков CAPTCHAкласс truck в наборе данных COCO. Кроме того, мы посчитаем количество обнаруженных объектов нужного нам класса и выведем всю информацию на экран.

Начнем с написания функции для использования YOLO. С ее помощью будут определены наиболее вероятные классы объектов на картинке, а также координаты их границ, которые мы позже будем использовать для рисования.

import cv2

import numpy as np
 
 
def apply_yolo_object_detection(image_to_process):
"""
Распознавание и определение координат объектов на изображении
:param image_to_process: исходное изображение
:return: изображение с размеченными объектами и подписями к ним
"""
height, width, depth = image_to_process.shape
blob = cv2.dnn.blobFromImage(image_to_process, 1 / 255, (608, 608), (0, 0, 0), swapRB=True, crop=False)
net.setInput(blob)
outs = net.forward(out_layers)
class_indexes, class_scores, boxes = ([] for i in range(3))
objects_count = 0
 
# Запуск поиска объектов на изображении
for out in outs:
for obj in out:
scores = obj[5:]
class_index = np.argmax(scores)
class_score = scores[class_index]
if class_score > 0:
center_x = int(obj[0] * width)
center_y = int(obj[1] * height)
obj_width = int(obj[2] * width)
obj_height = int(obj[3] * height)
box = [center_x - obj_width // 2, center_y - obj_height // 2, obj_width, obj_height]
boxes.append(box)
class_indexes.append(class_index)
class_scores.append(float(class_score))
 
# Выборка
chosen_boxes = cv2.dnn.NMSBoxes(boxes, class_scores, 0.0, 0.4)
for box_index in chosen_boxes:
box_index = box_index[0]
box = boxes[box_index]
class_index = class_indexes[box_index]
 
# Для отладки рисуем объекты, входящие в искомые классы
if classes[class_index] in classes_to_look_for:
objects_count += 1
image_to_process = draw_object_bounding_box(image_to_process, class_index, box)
 
final_image = draw_object_count(image_to_process, objects_count)
return final_image

Да­лее добавим фун­кцию, которая поз­волит нам обвести най­ден­ные на изоб­ражении объ­екты с помощью коор­динат гра­ниц, которые мы получи­ли в apply_yolo_object_detection.

def draw_object_bounding_box(image_to_process, index, box):
"""
Рисование границ объекта с подписями
:param image_to_process: исходное изображение
:param index: индекс определенного с помощью YOLO класса объекта
:param box: координаты области вокруг объекта
:return: изображение с отмеченными объектами
"""
x, y, w, h = box
start = (x, y)
end = (x + w, y + h)
color = (0, 255, 0)
width = 2
final_image = cv2.rectangle(image_to_process, start, end, color, width)
 
start = (x, y - 10)
font_size = 1
font = cv2.FONT_HERSHEY_SIMPLEX
width = 2
text = classes[index]
final_image = cv2.putText(final_image, text, start, font, font_size, color, width, cv2.LINE_AA)
 
return final_image

До­бавим фун­кцию, которая выведет количес­тво рас­познан­ных объ­ектов на изоб­ражении.

def draw_object_count(image_to_process, objects_count):
"""
Подпись количества найденных объектов на изображении
:param image_to_process: исходное изображение
:param objects_count: количество объектов искомого класса
:return: изображение с подписанным количеством найденных объектов
"""
 
start = (45, 150)
font_size = 1.5
font = cv2.FONT_HERSHEY_SIMPLEX
width = 3
text = "Objects found: " + str(objects_count)
 
# Вывод текста с обводкой (чтобы было видно при разном освещении картинки)
white_color = (255, 255, 255)
black_outline_color = (0, 0, 0)
final_image = cv2.putText(image_to_process, text, start, font, font_size, black_outline_color, width * 3, cv2.LINE_AA)
final_image = cv2.putText(final_image, text, start, font, font_size, white_color, width, cv2.LINE_AA)
 
return final_image

На­пишем фун­кцию, которая будет ана­лизи­ровать изоб­ражение и выводить на экран резуль­тат работы написан­ных нами алго­рит­мов.

def start_image_object_detection():
"""
Анализ изображения
"""
try:
# Применение методов распознавания объектов на изображении от YOLO
image = cv2.imread("assets/truck_captcha.png")
image = apply_yolo_object_detection(image)
 
# Вывод обработанного изображения на экран
cv2.imshow("Image", image)
if cv2.waitKey(0):
cv2.destroyAllWindows()
 
except KeyboardInterrupt:
pass

А теперь мы соз­дадим фун­кцию main, в которой нас­тро­им нашу сеть и поп­робу­ем запус­тить ее.

if __name__ == '__main__':
 
# Загрузка весов YOLO из файлов и настройка сети
net = cv2.dnn.readNetFromDarknet("yolov4-tiny.cfg", "yolov4-tiny.weights")
layer_names = net.getLayerNames()
out_layers_indexes = net.getUnconnectedOutLayers()
out_layers = [layer_names[index[0] - 1] for index in out_layers_indexes]
 
# Загрузка из файла классов объектов, которые умеет обнаруживать YOLO
with open("coco.names.txt") as file:
classes = file.read().split("\n")
 
# Определение классов, которые будут приоритетными для поиска на изображении
# Названия находятся в файле coco.names.txt
# В данном случае определяется грузовик для прохождения CAPTCHA
classes_to_look_for = ["truck"]
 
start_image_object_detection()

Да­вай пос­мотрим, как алго­ритм YOLO спра­вил­ся с тес­том прос­той CAPTCHA.

Исходная CAPTCHA

Ис­ходная CAPTCHA

Результат применения YOLO

Ре­зуль­тат при­мене­ния YOLO

Не­кото­рая пог­решность все же есть, но два из трех гру­зови­ков алго­ритм выб­рал пра­виль­но.

Модификация приложения

Теперь мы с вами приступим к решению практической задачи, в которой нам будет важно контролировать количество людей в комнате. Более того, во время ограничительных мер, связанных с COVID-19, это не только интересно, но и актуально.

Чтобы сделать задачу «живым примером», воспользуемся общественной камерой, установленной в одной из парикмахерских Лондона. Благодаря небольшому пространству внутри может находиться не более десяти человек.

Для решения этой проблемы достаточно добавить функцию, которая будет обрабатывать видео кадр за кадром и отображать результат обработки на экране. Чтобы не загружать устройство обработкой каждого кадра, экран будет обновляться при нажатии любой клавиши. В этом нет необходимости на мощных компьютерах.

def start_video_object_detection():
"""
Захват и анализ видео в режиме реального времени
"""
while True:
try:
# Захват картинки с видео
video_camera_capture = cv2.VideoCapture("http://81.130.136.82:82/mjpg/video.mjpg")
 
while video_camera_capture.isOpened():
ret, frame = video_camera_capture.read()
if not ret:
break
 
# Применение методов распознавания объектов на кадре видео от YOLO
frame = apply_yolo_object_detection(frame)
 
# Вывод обработанного изображения на экран с уменьшением размера окна
frame = cv2.resize(frame, (1920 // 2, 1080 // 2))
cv2.imshow("Video Capture", frame)
if cv2.waitKey(0):
break
 
video_camera_capture.release()
cv2.destroyAllWindows()
 
except KeyboardInterrupt:
pass

Так­же нам пот­ребу­ется нем­ного модифи­циро­вать фун­кцию main, что­бы теперь запус­кать обра­бот­ку видео вмес­то обра­бот­ки изоб­ражения.

if __name__ == '__main__':
 
# Загрузка весов YOLO из файлов и настройка сети
net = cv2.dnn.readNetFromDarknet("yolov4-tiny.cfg", "yolov4-tiny.weights")
layer_names = net.getLayerNames()
out_layers_indexes = net.getUnconnectedOutLayers()
out_layers = [layer_names[index[0] - 1] for index in out_layers_indexes]
 
# Загрузка из файла классов объектов, которые умеет обнаруживать YOLO
with open("coco.names.txt") as file:
classes = file.read().split("\n")
 
# Определение классов, которые будут приоритетными для поиска на изображении
# Названия находятся в файле coco.names.txt
# В данном случае определяется грузовик для прохождения CAPTCHA и человек для анализа видео
classes_to_look_for = ["truck", "person"]
 
start_video_object_detection()

По­луча­ем резуль­тат: шесть из семи человек были рас­позна­ны.

Результат обработки видео

Ре­зуль­тат обра­бот­ки видео

Также можно добавить и другие полезные функции: например, отправлять на почту или в Telegram сообщение о том, что в барбершоп собралось много народу.

Итоги

Алгоритмы обнаружения объектов не дают стопроцентной точности, но они по-прежнему эффективны и могут работать намного быстрее, чем любой из нас.
Вы можете спросить себя, почему мы не соблюдаем расстояние в полтора метра. В реальной жизни проверить это будет сложно: например, когда у вас есть пара друзей, семья с ребенком или действие разворачивается невозможно без тесного контакта, а в парикмахерской это происходит постоянно. Кроме того, если камера расположена под неправильным углом, возрастает сложность измерения расстояния.
Для этого потребуются алгоритмы, которые в будущем будут определять размеры объектов и будут работать с трехмерным пространством. Они используются для обнаружения транспортных средств в беспилотных автомобилях — Aggregate View Object Detection или YOLO 3D Oriented Object Bounding Box Detection.

 

 

 

 

Click to rate this post!
[Total: 0 Average: 0]

Leave a reply:

Your email address will not be published.