Детектирование светофора с помощью OpenCV

Как я выяснил в предыдущей статье, свёрточные, нейронные и другие сети для этого применять очень проблематично из-за их долгого времени работы.

Так как в перспективе данная разработка будет установлена в автомобиль, соответственно время работы алгоритма должно быть приближено к реальному времени. Напомню, что даже самая быстрая нейронная сеть, построенная на базе YOLO архитектуры, работала больше минуты. В статье я более подробно описывал измерение времени работы, но кратко напомню. Вычисления производятся на обычном ноутбуке со встроенной видеокартой. Я сознательно не использую Google Colab, так как в перспективе код будет залит на портативный компьютер на базе RaspberryPI, мощность которого точно не будет превышать мощность моего ноутбука. Соответственно и в этот раз выбор остановился на OpenCV.

Следующим этапом стал выбор алгоритма работы. Именно его я считаю наиболее ценным в этой статье и сейчас объясню почему. На просторах интернета можно найти два наиболее распространенных алгоритма: первый это перевод в цветовое пространство HSV и работа с цветами, накладывая маски на ненужные цвета, а второй это нахождение контуров на ЧБ изображении функцией Canny. Я решил остановиться на втором алгоритме.

Для нахождения контуров с помощью функции Canny нужно сделать изображение ЧБ и применить функцию Canny, после чего замкнуть контуры. Но, функция находит буквально все контуры и из-за этого выделить конкретный объект (светофор) не получается.

Детектирование светофора с помощью OpenCV

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

Детектирование светофора с помощью OpenCV

Код функции Canny :

image = cv.imread(img) frame_hsv = cv.cvtColor(image, cv.COLOR_BGR2GRAY) cv.imshow('hsv', frame_hsv) counturs = cv.Canny(frame_hsv, 350, 500) cv.imshow('counturs', counturs) kernel = cv.getStructuringElement(cv.MORPH_RECT, (2, 2)) cv.imshow('kernel', kernel) closed = cv.morphologyEx(counturs, cv.MORPH_CLOSE, kernel) cv.imshow('closed', closed) contours, hierarchy = cv.findContours(closed.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) sort = [] for i in contours: area = cv.contourArea(i) if 4 < area < 100000: # можно регулировать дальность sort.append(i) cv.drawContours(image, sort, -1, (0, 203, 44), 2)

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

После небольшого анализа и проб, я пришел к выводу, что правильнее всего будет использовать пространство RGB. В нем лучше всего получается замаскировать все цвета кроме чёрного.

img = cv.imread('images/images/img_2.png') spisok = [] image = cv.cvtColor(img, cv.COLOR_BGR2RGB) frame_mask = cv.inRange(image, (0, 0, 0), (51, 38, 51)) cv.imshow('mask', frame_mask) frame_dilate = cv.dilate(frame_mask, None, iterations=2) contours, hierarchy = cv.findContours(frame_dilate.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) sort = spisok for i in contours: area = cv.contourArea(i) if 400 < area: # можно регулировать дальность sort.append(i) cv.drawContours(image, sort, -1, (0, 232, 44), 2) cv.imshow('img', image) (x, y, w, h) = cv.boundingRect(sort[7]) detect = img[y:y + h, x:x + w] cv.imshow('cadr', detect) cv.imwrite('cadr.jpg', detect)

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

Детектирование светофора с помощью OpenCV

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

Детектирование светофора с помощью OpenCV
Детектирование светофора с помощью OpenCV
Детектирование светофора с помощью OpenCV

Программа обрезает фото не идеально, задевая часть заднего фона. Особенно тяжело, когда светофор находится на фоне листвы или других темных объектов. Но я считаю, что такого качества будет достаточно для работы с кадрированным изображением в дальнейшем.

Вывод: думаю, моя статья будет полезна тем, кому нужно детектировать темные или же совсем черные объекты и функция Canny, которую советуют использовать чаще всего, не подходит. Также полезно почерпнуть значения функции inRange, которая определяет разрешенные цвета и накладывает маску на все остальные. Я старался подобрать оптимальные значения, чтобы программа работала не в одном конкретном случае, а при разных обстоятельствах. На этом у меня все, желаю всем удачи в изучении компьютерного зрения.

44
5 комментариев

Круто, интересно было бы посмотреть на готовую реализацию. Дома а то лежит малинка, до которой так и не дошли руки, сделать что-нибудь полезное

1
Ответить

К сожалению, еще не реализовывал(

1
Ответить

Один вопрос.
Зачем?

1
Ответить

Главная цель - создать альтернативу, которая должна работать быстрее и быть менее требовательная к ресурсам, чем YOLO

1
Ответить