Опубликовано: 27.08.2018
Обнаружить объект заданного цвета — одна из базовых задач машинного зрения. Решение этой задачи может помочь совершенно разным роботам в выполнении их функций.
Возьмем, к примеру, робота-футболиста. Чтобы забить гол, ему нужно сначала найти мяч на поле. Как правило, мяч в таких соревнованиях имеет цвет, отличный от цвета поля.
Или другой пример — автоматическая пейтбольная турель. Это такой робот, который выискивает перед собой цель, поворачивает орудие на нужные углы и стреляет шариками с краской. Опять таки, цель может иметь яркую цветную метку, отличающуюся от фона (оранжевое пятно на куртке игрока).
На этом уроке мы разберем алгоритм детектирования и вычисления координат цветового пятна в кадре. То есть будем водить объектом какого-то конкретного цвета перед камерой, а программа будет выдавать нам координаты этого объекта относительно краев видеокадра.
Стандартный прием в OpenCV для решения поставленной задачи складывается из двух этапов.
На первом этапе мы применяем цветовой фильтр и превращаем каждый кадр в черно-белую картинку. После наложения фильтра объект заданного цвета превращается в белое пятно, а всё остальное заливается черным цветом. Вот так выглядит результат обработки фильтром кадра из прошлого урока.
На следующем этапе мы используем алгоритм вычисления моментов. Момент изображения — это суммарная характеристика пятна, представляющая собой сумму всех точек (пикселей) этого пятна. При этом, имеется множество подвидов моментов, характеризующие разные свойства изображения.
Например, момент нулевого порядка m00 — это количество всех точек, составляющих пятно. Момент первого порядка m10 представляет собой сумму X координат точек, а m01 — сумму Y координат. Имеются также моменты m11, m20, m02, m22 и т.д.
Формула для вычисления моментов очень проста , и мы можем посчитать пиксели вручную. Однако, стандартные функции OpenCV написаны на языках более низкого уровня, чем python, и работают быстрее. Воспользуемся стандартной функцией для вычисления моментов кадра:
moments( кадр, двоичный )Аргумент кадр представляет собой нашу предобработанную картинку. Аргумент двоичный определяет то, как алгоритм будет вычислять вес каждой точки. Напомню, что предыдущий метод inRange дал нам черно-белую картинку, в которой пиксели могут быть черными, белыми, а могут быть и серыми. Так вот, если аргумент двоичный равен 1, то вес всех точек с цветом, отличным от нуля будет равен единице. В противном случае, вес черной точки будет равен 0, а белой точки — 255.
Функция moments вернет нам массив моментов вплоть до третьего порядка. Но для вычисления координат центра пятна нам потребуются только моменты первого порядка m01 и m10, а также момент m00.
dM01 = moments['m01'] dM10 = moments['m10'] dArea = moments['m00']Чтобы получить координаты X и Y искомого пятна, нам следует поделить полученные моменты m10 и m01 на нулевой момент m00. Таким образом мы найдем средние координаты X и Y всех точек, а это и есть центр пятна.
x = int(dM10 / dArea) y = int(dM01 / dArea)Основываясь на предыдущих уроках, напишем программу, которая будет искать в кадре объект зеленого цвета и рисовать небольшую окружность в его центре.
import cv2 import numpy as np import video if __name__ == '__main__': def callback(*arg): print (arg) cv2.namedWindow( "result" ) cap = video.create_capture(0) # HSV фильтр для зеленых объектов из прошлого урока hsv_min = np.array((53, 55, 147), np.uint8) hsv_max = np.array((83, 160, 255), np.uint8) while True: flag, img = cap.read() # преобразуем RGB картинку в HSV модель hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV ) # применяем цветовой фильтр thresh = cv2.inRange(hsv, hsv_min, hsv_max) # вычисляем моменты изображения moments = cv2.moments(thresh, 1) dM01 = moments['m01'] dM10 = moments['m10'] dArea = moments['m00'] # будем реагировать только на те моменты, # которые содержать больше 100 пикселей if dArea > 100: x = int(dM10 / dArea) y = int(dM01 / dArea) cv2.circle(img, (x, y), 10, (0,0,255), -1) cv2.imshow('result', img) ch = cv2.waitKey(5) if ch == 27: break cap.release() cv2.destroyAllWindows()Запускаем программу и пробуем водить перед камерой зеленым объектом.
Примечание! Функция moment не может различить одно пятно в кадре или несколько. Так что, если в кадре окажется, например, два зеленых объекта, то они интерпретируются как один большой, и центр будет где-то между ними.
Для большей наглядности будем выводить в кадр траекторию движения объекта.
import cv2 import numpy as np import video if __name__ == '__main__': def callback(*arg): print (arg) def createPath( img ): h, w = img.shape[:2] return np.zeros((h, w, 3), np.uint8) cv2.namedWindow( "result" ) cap = video.create_capture(0) hsv_min = np.array((53, 55, 147), np.uint8) hsv_max = np.array((83, 160, 255), np.uint8) lastx = 0 lasty = 0 path_color = (0,0,255) flag, img = cap.read() path = createPath(img) while True: flag, img = cap.read() hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV ) thresh = cv2.inRange(hsv, hsv_min, hsv_max) moments = cv2.moments(thresh, 1) dM01 = moments['m01'] dM10 = moments['m10'] dArea = moments['m00'] if dArea > 100: x = int(dM10 / dArea) y = int(dM01 / dArea) cv2.circle(img, (x, y), 10, (0,0,255), -1) if lastx > 0 and lasty > 0: cv2.line(path, (lastx, lasty), (x,y), path_color, 5) lastx = x lasty = y # накладываем линию траектории поверх изображения img = cv2.add( img, path) cv2.imshow('result', img) ch = cv2.waitKey(5) if ch == 27: break cap.release() cv2.destroyAllWindows()Пример работы программы на Raspberry Pi с обычной веб-камерой.
Your browser does not support the video tag.
4. Программа для поиска цветового пятна на Raspberry Pi и python. Вывод координат
И еще одна модификация. Будем рядом с обнаруженным центром пятна выводить его координаты.
import cv2 import numpy as np import video if __name__ == '__main__': def callback(*arg): print (arg) cv2.namedWindow( "result" ) cap = video.create_capture(0) hsv_min = np.array((53, 55, 147), np.uint8) hsv_max = np.array((83, 160, 255), np.uint8) color_yellow = (0,255,255) while True: flag, img = cap.read() img = cv2.flip(img,1) # отражение кадра вдоль оси Y hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV ) thresh = cv2.inRange(hsv, hsv_min, hsv_max) moments = cv2.moments(thresh, 1) dM01 = moments['m01'] dM10 = moments['m10'] dArea = moments['m00'] if dArea > 100: x = int(dM10 / dArea) y = int(dM01 / dArea) cv2.circle(img, (x, y), 5, color_yellow, 2) cv2.putText(img, "%d-%d" % (x,y), (x+10,y-10), cv2.FONT_HERSHEY_SIMPLEX, 1, color_yellow, 2) cv2.imshow('result', img) ch = cv2.waitKey(5) if ch == 27: break cap.release() cv2.destroyAllWindows()Запускаем программу и проверяем работу алгоритма. Снова используем Raspberry Pi. Как видно на видео, мощности Raspberry Pi вполне хватает для выполнения поиска цветного объекта с помощью моментов.
Your browser does not support the video tag.
Ну вот и все на сегодня. На следующем уроке заставим роботов искать не просто цветные пятна, а целые геометрические фигуры!
Разделы
» RSS
Категории
Новости
О сайте
ПОПУЛЯРНОЕ
РЕКЛАМА