OpenCV на python: поиск цветного объекта

Обнаружить объект заданного цвета — одна из базовых задач машинного зрения. Решение этой задачи может помочь совершенно разным роботам в выполнении их функций. Возьмем, к примеру, робота-футболиста. Чтобы забить гол, ему нужно сначала найти мяч на поле. Как правило, мяч в таких соревнованиях имеет цвет, отличный от цвета поля. OpenCV на python. Поиск цветного объекта Или другой пример — автоматическая пейтбольная турель. Это такой робот, который выискивает перед собой цель, поворачивает орудие на нужные углы и стреляет шариками с краской. Опять таки, цель может иметь яркую цветную метку, отличающуюся от фона (оранжевое пятно на куртке игрока). На этом уроке мы разберем алгоритм детектирования и вычисления координат цветового пятна в кадре. То есть будем водить объектом какого-то конкретного цвета перед камерой, а программа будет выдавать нам координаты этого объекта относительно краев видеокадра.

1. Алгоритм поиска цветового пятна в OpenCV. Моменты изображения

Стандартный прием в OpenCV для решения поставленной задачи складывается из двух этапов. На первом этапе мы применяем цветовой фильтр и превращаем каждый кадр в черно-белую картинку. После наложения фильтра объект заданного цвета превращается в белое пятно, а всё остальное заливается черным цветом. Вот так выглядит результат обработки фильтром кадра из прошлого урока. OpenCV на python. Цветовой фильтр На следующем этапе мы используем алгоритм вычисления моментов. Момент изображения — это суммарная характеристика пятна, представляющая собой сумму всех точек (пикселей) этого пятна. При этом, имеется множество подвидов моментов, характеризующие разные свойства изображения. Например, момент нулевого порядка 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)

2. Программа для поиска цветового пятна на 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 фильтр для зеленых объектов из прошлого урока
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 не может различить одно пятно в кадре или несколько. Так что, если в кадре окажется, например, два зеленых объекта, то они интерпретируются как один большой, и центр будет где-то между ними.

3. Программа для поиска цветового пятна на Raspberry Pi и python. Подсветка траектории

Для большей наглядности будем выводить в кадр траекторию движения объекта.
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 с обычной веб-камерой. 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 вполне хватает для выполнения поиска цветного объекта с помощью моментов. Ну вот и все на сегодня. На следующем уроке заставим роботов искать не просто цветные пятна, а целые геометрические фигуры!
0

Изменено:

OpenCV на python: поиск цветного объекта: 22 комментария

  1. У меня работает только с USB камеры. Как задействовать штатную камеру подключаемую к разъему MIPI Camera Serial Interface (CSI-2) ?

    0
  2. Доброго дня! Не подскажете ли вы мне, как можно изменять разрешение съёмки и частоту кадров применительно к этой программе (-ам)? Я видел похожий код от зарубежного автора, но там была лишь строчка изменяющая разрешение (представлена ниже), но о регулировке частоты нигде и ничего не находится.
    (cap = cv2.VideoCapture(0)
    # Reduce the size of video to 320×240 so rpi can process faster
    cap.set(3,320)
    cap.set(4,240))

    0
    • Частота кадров зависит от вычислительной мощности вашего компьютера и размера кадра. Уменьшая размер, вы тем самым ускоряете обработку каждого кадра, соответственно, увеличиваете частоту видеопотока на выходе.

      0
      • Да если бы это было так просто.. Я задаю разрешение 720p и загрузка процессора становится равной 60%, меняю на 480p и загрузка уменьшается на 5-10% (нет чёткой зависимости), при этом прироста частоты кадров не наблюдается (на 1-2, может, 3 больше становится, но это несерьёзно). Может ли проблема быть в самом OpenCV (в его неэффективных алгоритмах)?

        0
        • В OpenCv можно уменьшить частоту камеры, задается как у вас в set (точно не помню как называется, там для этого макрос есть, вродебы на CAP начинается). Так же можно через waitKey(задержка) задать, где задержка — число в миллисекундах. Но это повлияет на всю работы программы.

          0
  3. Подскажите пожалуйста как можно сделать чтобы при появлении в кадре «зеленого обьекта» загорелся светодиод на определненное время?

    0
  4. у меня распознаются объекты на видео и отмечаются.. как записать их координаты?

    0
    • Как вариант, можно воспользоваться функциями python для работы с файлами. Типа:
      file = open(«C:\\my_file.txt», «a»)
      file.write(«x=» + x + «,y=» + y)
      file.close()

      0
  5. В этом кусочке:

    if lastx > 0 and lasty > 0:
    cv2.line(path, (lastx, lasty), (x,y), path_color, 5)
    lastx = x
    lasty = y

    PyCharm ругается на то, что не определены переменные x/y
    Не подскажете, они определены где-то ранее, просто я не понял?

    0
    • Скорее всего при копировании кода из браузера скопировался скрытый символ, который все портит.

      0
  6. Здравствуйте. У меня проблема. Возникает ошибка
    flag, img = cap.read()
    AttributeError: ‘NoneType’ object has no attribute ‘read’

    Хотя драйвер камеры правильный и в прошлом уроке всё работало.

    0
  7. Здравствуйте. Прошла прошлый урок со встроенной распберри камерой и настроенным драйвером. Соответственно, кусок с настройкой вставлен в то жже начало программы. В первой-же задаче возникает
    flag, img = cap.read()
    AttributeError: ‘NoneType’ object has no attribute ‘read’
    Подскажите пожалуйста, что делать в этом случае.
    Если что, Код вот тут:
    https://pp.userapi.com/c844416/v844416612/1fd172/1A-_CJ7y8w0.jpg

    0
    • Видимо скрипт не находит камеру #0. Попробуйте cap=video.create_capture(1)

      0
      • Нее. То же самое….
        File «redline_col.py», line 28, in
        flag, img = cap.read()
        AttributeError: ‘NoneType’ object has no attribute ‘read’

        0

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.