- PVSM.RU - https://www.pvsm.ru -

DIY или Сделай Сам / Детектор попадания мячика используя OpenCV

Не давно мне довелось поучаствовать в одном интересном проекте. Моя сестра учиться на дизайнера в БВШД, и им дали задание сделать проект на тему Street Interactive. Идея была выбрана довольно простая. На экране демонстрируется анимация движущегося медведя, всем желающим предлагается попасть в него из рогатки импровизированным снежком. Результат продемонстрирован на видео, кому интересна техническая реализация, добро пожаловать под кат.

Описание

Первоначальной идеей было использовать для трекинга кинект. Казалось, что для подобной задачи кинект подойдёт идеально — он обладает неплохой встроенной камерой, а так же позволяет ослеживать глубину (и определять с некоторой точностью положение тела в трёхмерном пространстве). Однако после непродолжительного тестирования от использования кинекта пришлось отказаться. Он не позволяет отслеживать объекты на дальнем расстоянии, а кроме того, яркий свет от проектора мешает его сенсорам.

Затем у меня появилась идея использовать для трекинга обычную веб камеру. Расположить камеру рядом с проектором и направить на экран. С её помощью отслеживать положение мячика в плоскости экрана. Но оставалась ещё одна проблема — определить момент столкновения мячика со стенкой. В качестве варианта рассматривался Arduino с датчиком движения. Однако в итоге было решено использовать вторую камеру, расположенную вблизи экрана в качестве детектора движения. С помощью неё можно фиксировать момент, когда мячик подлетает к экрану, и брать координаты удара через несколько миллисекунд после этого момента.

Программную реализацию было решено сделать на C++, используя библиотеку OpenCV. Она позволяет не изобретать велосипед, а пользоваться готовым функционалом для получения изображения с камеры, и последующей его обработке.

Отслеживание мячика

Для определения координат мячика, я воспользовался следующим алгоритмом.
1) Перевёл изображение из RGB представления в HSV. Это облегчает определение похожих цветов, так как в отличие от RGB, HSV хранит в отдельном канале цветовой тон, насыщенность и яркость.
2) Перевёл изображение в двоичное (bitmap). Те цвета, которые ближе всех к требуемуму цвету (цвету мячика) — преобразовались в белый. Остальные — в чёрный.
3) Отфильтровал шумы медианным фильтром.
4) Определил среднюю координату и количество белых пикселей. Если количество больше порогового значения — значит в кадре есть мячик.
Получившийся код:

        clr=ballColor;         frame=cvQueryFrame(capture); // Получаем изображение с камеры         cvtColor(frame,frameHSV,CV_BGR2HSV); // Переводим в HSV         inRange(frameHSV,Scalar(clr-ballThres,120,120),Scalar(clr+ballThres,255,255),frameBitmap);                                                           // Переводим в bitmap         medianBlur(frameBitmap,frameBitmap,5); // фильтруем шумы         for(int i = screenLeft; i < screenRight; i++) {             for(int j = screenUp; j < screenDown; j++) {                  cl=frameBitmap.at<char>(j,i);                 if (cl!=0) { // Находим центр тяжести                     x+=i;                     y+=j;                     n++;                 }             }         }         if (n>ballDifNum) { // Отсекаем некоторые случайные сробатывания             x/=n;             y/=n;         }

Определение удара

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

        frame=cvQueryFrame(captureHit);         cvtColor(frame, frame, CV_RGB2GRAY );   // из цветного в серое         GaussianBlur(frame,frameCurrent,cv::Size( 3, 3 ), -1);  // убираем шумы         absdiff(frameCurrent,framePriv,mask);  // смотрим разницу между кадрами         framePriv=frameCurrent.clone(); // сохраняем предыдущий кадр         threshold(mask,mask,motionTreshold,255,cv::THRESH_BINARY);         if (countNonZero(mask)>motionDifNum)               ttl3=detectDelay; // если мячик влетел в кадр, запускаем обратный отсчёт до столкновения
Результат

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

Ссылки

source.txt [1] — Полный листинг программы
wikipedia.org [2] — Об OpenCV на Википедии
robocraft.ru [3] — OpenCV шаг за шагом. Уроки OpenCV по-русски от Чеширского Кота.
aishack.in [4] — Tracking colored objects in OpenCV
britishdesign.ru [5] — Британская Высшая Школа Дизайна

Автор: bak


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/diy/2615

Ссылки в тексте:

[1] source.txt: http://quantion.ru/files/source.txt

[2] wikipedia.org: http://ru.wikipedia.org/wiki/OpenCV

[3] robocraft.ru: http://robocraft.ru/tag/%D1%88%D0%B0%D0%B3%20%D0%B7%D0%B0%20%D1%88%D0%B0%D0%B3%D0%BE%D0%BC/

[4] aishack.in: http://www.aishack.in/2010/07/tracking-colored-objects-in-opencv/

[5] britishdesign.ru: http://britishdesign.ru/