События‎ > ‎

Модуль слежения за оранжевым шариком

Отправлено 19 февр. 2013 г., 11:28 пользователем Олег Евсегнеев   [ обновлено 19 февр. 2013 г., 11:41 ]
Итак, изготовленный ранее модуль слежения на двух сервоприводах был благополучно оживлен с помощью библиотеки OpenCV. По сути, созданное устройство можно назвать роботом-наблюдателем. Главной целью существования такого робота является слежение за каким-нибудь конкретным объектом, например, цветным шариком или за лицом человека.

По началу, в качестве объекта слежения я выбрал обычный теннисный шарик. Шарик этот имеет классический ярко-зеленый цвет, и теоретически должен был легко выделяться из явно не зеленого окружения. Однако, в дальнейшем пришлось заменить большой зеленый шар на маленький оранжевый шарик для пинг-понга. Причина замены будет описана ниже.

Кодировать было решено на python, так как робот в будущем будет портирован на Raspberry PI, и станет учебным проектом для юных робототехников. Алгоритм работы python-скрипта для распознавания состоит из шести основных шагов:
  1. Преобразование кадра в формат HSV
  2. Фильтрация в заданном диапазоне HSV
  3. Морфологическое преобразование
  4. Размывание
  5. Детектирование окружностей
  6. Передача управляющих сигналов на сервоприводы

HSV изображение   
Результат фильтрации по цвету   
Морфологическое преобразование   
Опознанный шарик


Преобразование в HSV

hsv = cv2.cvtColor(img, cv.CV_BGR2HSV )

Здесь всё просто. Даем изображение с веб-камеры, получаем - конвертированное в HSV изображение (первая картинка).
Почему HSV? Потому что в HSV проще создать правильную маску для выделения нужного цвета.

Фильтрация по цвету

thresh = cv2.inRange(hsv, h_min, h_max)

Очень важный шаг. Функция inRange преобразует цветную картинку в черно-белую маску. В этой маске, все пиксели, попадающие в заданный диапазон - становятся белыми. Прочие - черными. Результат работы inRange представлен на второй картинке.

Морфологическое преобразование

st1 = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 21), (10, 10))
st2 = cv2.getStructuringElement(cv2.MORPH_RECT, (11, 11), (5, 5))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, st1) 
thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, st2) 

Данная процедура нужна для того, чтобы убрать из кадра мелкий мусор и замазать возможные дефекты в выделяемом объекте. Например, морфологическое преобразование позволяет убрать из теннисного шарика прожилку, которая имеет отличный цвет. Либо, как в моем случае, можно убрать надпись и засвеченные участки шарика (третья картинка).

Размывание

thresh = cv2.GaussianBlur(thresh, (5, 5), 2)

Банальное размывание методом Гаусса. Как и предыдущая процедура, размывание необходимо для сглаживания шероховатостей.

Детектирование окружностей
            
circles = cv2.HoughCircles( thresh,
                                        cv.CV_HOUGH_GRADIENT,
                                        2, mcr, np.array([]),
                                        cet1, cet2, mcs, xcs) 

Собственно, само детектирование. Процедура HoughCircles находит на изображении все окружности, используя при этом преобразование Хафа. Важными параметрами здесь являются:
  • mcr - минимальное расстояние между окружностями (h/4);
  • cet1 и cet2 - параметры оператора Кэнни, используемого для построения границ объекта (80 и 50);
  • mcs, xcs - минимальный и максимальный радиус окружностей (5 и 0).
На последнем шаге, на основе координат обнаруженной окружности, рассчитываются углы поворота сервоприводов.

sctrl.shift(0, (x*1./w)*20-10)
sctrl.shift(1, -((y*1./h)*20-10))

Проблемы

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

1. Камера

Изначально, я хотел использовать старенькую 300-килопиксельную веб-камеру.  Я даже вытащил её из родного корпуса и прикрутил к монтировке (см. предыдущий пост). Однако, после попытки провести распознавание, меня ждало разочарование. Цвета изображения были каким-то блеклыми, и зеленый шарик выглядел совсем не зеленым. Никак не получалось подобрать маску для отделения этого шарик от фона. Кроме того, изрядно тормозил видеопоток, вероятно из-за встроенного алгоритма автоматический экспозиции, который старался осветлить темную картинку. 

Ввиду такого безобразия, я решил заменить камеру на что-то более качественное и настраиваемое. Посмотрев различные ролики на ютубе, мой выбор пал на доступную Microsoft LifeCam HD 3000. Подключив эту камеру к роботу, я снова немного разочаровался :( Опять тормоза и непонятная цветопередача. Благо, отключение автоматической экспозиций решило проблему с тормозами, а отключение TrueColor и авто-баланса белого - немного стабилизировало цветопередачу.

2. Инфракрасное излучение

Несмотря на новую камеру, мне по-прежнему долго не удавалось настроить маску для выделения нужного цвета. Лишь спустя множество попыток, я понял что камера видит этот мир совсем не так как я. Смотря на оранжевый шарик, я вижу оранжевый шарик. Когда на этот же шарик смотрит веб-камера - она видит чертовски яркий оранжевый шарик. Такой яркий, что он уже не оранжевый, а желтый. Как это обычно со мной бывает, причина явления лежала на поверхности. Дело в том, что матрица камеры очень хорошо чувствует ближнее инфракрасное излучение (Near-infrared). Эти ИК лучи в больших количествах излучаются галогеновыми (и не только) лампами и солнцем.

Как показала практика, настройка цветовой маски в условиях ИК засветки является весьма непростой задачей. Решением здесь может стать ИК фильтр, который устанавливается в хороших фотоаппаратах для обеспечения адекватной цветопередачи. Но проблему можно попытаться решить и немного иначе, хоть и не так качественно как с фильтром. Для выделения засвеченного шарика я попробовал применить сразу два фильтра. Один - для засвеченного участка шарика, другой - для затененного. Получилось сносно, но наверняка есть и другие варианты.

3. Настройка цветовой маски

Как уже говорилось, для каждого объекта требуется специально настраивать цветовую маску (даже две). Для настройки этой маски, а именно параметров h_min, h_max функции inRange пришлось сделать отдельное приложение с кучей бегунков. Чтобы выделить нужный цвет необходимо подобрать границы компонента H (Hue). Параметр S (Saturation) отвечает за насыщенность цвета. Например, кожа человека имеет оранжево-желтый цвет (H) как у шарика, но слабую насыщенность. Наконец V (Value) определяет яркость цвета. Затененный шарик будет иметь низкое значение V.

Для моего оранжевого шарика я подобрал такие маски:

светлый шарик - (20, 70, 170) - (40, 170, 255)
темный шарик - (0, 170, 120) - (20, 240, 255)


Несмотря на возникшие трудности, робот-наблюдатель всё-таки ожил. Следующий этап - установка ИК фильтра и распознавание лиц. Небольшое видео представлено ниже. 


Comments