В этой статье я кратко расскажу о своём опыте использования методов обработки изображений и использовании библиотеки дополненной реальности ARToolKit.
Дополненная реальность - модное и набирающее обороты направление. И поэтому, мне давно хотелось приобщиться к этим технологиям. Но такие системы использует довольно сложные графические алгоритмы, реализация которых весьма трудоёмка. Тем не менее, некоторые из них мне довелось попробовать, о них я напишу вскользь, но со ссылками на различные интересные материалы. Но если вдруг мой дорогой читатель не интересуется методами обработки изображений, то сразу может переходить к пункту про ARToolKit.
Необходимо заметить, что далее я буду говорить о системах с заранее подготовленными опорными образами (маркерами).
Отступление о методах обработки изображений
Начиная изучать данную тему я столкнулся с банальной проблемой: с чего начать? Хотя вскоре нашел множество интересных статей, ссылки на которые привожу далее по тексту.
Практически всегда, в таком случае, анализ изображения должен состоять из следующих этапов:
- бинаризация
Перевод изображения в однобитный вид - т.е. создать некую маску значащих объектов. Эти методы довольно просты в реализации, но они отнюдь не универсальны. Для каждой новой задачи приходится заново определять подходящий.
На мой взгляд самым наилучшим для наших целей является метод Оцу(исходники на С), но если нужно что-то по-быстрее, то можно выбрать адаптивный метод.
- сегментация(выделение контуров, замкнутых областей)
Всё разнообразие методов сегментации вы можете увидеть ниже на рисунке.
Чуть подробнее об этом и о бинаризации можно прочитать здесь.
Очень часто для того, чтобы выделить на изображении какие-либо объекты сначала производится определение границ. Стандартом в этой области является метод Канни. Все они основаны на свертке изображений с соответствующими операторами. А для нахождения на изображении различных примитивов ( кругов, многоугольников и т.д.) можно использовать преобразование Хафа. Существует ещё много интересных методов, но мы не будем упоминать и использовать их в рамках этой статьи.
- анализ сегментов
Тут могут быть привлечены самые различные алгоритмы от простого перебора до нейросетей. Самым простым способом является сравнение объекта с шаблоном, а точнее сравнение так называемых моментов контуров объектов. В конце статьи приведена ссылка на проект робота "Зоркий" с машинным зрением. Там вы найдёте кое-что интересное на данную тему.
Что такое ARToolKit
ARToolKit - свободная для некоммерческого использования (GNU GPL) библиотека с открытым кодом для построения систем дополненной реальности. Я выбрал именно её из за простоты и наличия простых и понятных примеров.
Она позволяет отслеживать положение и ориентацию квадратного маркера, а так же калибровать камеру.
Присутствует поддержка Linux, Windows, мобильных платформ.
Простейшее приложение для WIN32 выглядит следующим образом:
#ifdef _WIN32 #include <windows.h> #endif #include <stdio.h> #include <stdlib.h> #ifndef __APPLE__ #include <GL/gl.h> #include <GL/glut.h> #include <GL/glu.h> #else #include <OpenGL/gl.h> #include <GLUT/glut.h> #endif #include <AR/gsub.h> #include <AR/video.h> #include <AR/param.h> #include <AR/ar.h> // // Camera configuration. // #ifdef _WIN32 char *vconf = "Data\\WDM_camera_flipV.xml"; #else char *vconf = ""; #endif int xsize, ysize; int thresh = 100; int count = 0; char *cparam_name = "Data/camera_para.dat"; ARParam cparam; char *patt_name = "Data/patt.hard"; // Файл с паттерном маркера // Можно создать свой(с помощью mk_patt) или взять один из стандартных int patt_id; double patt_width = 80.0; double patt_center[2] = {0.0, 0.0}; double patt_trans[3][4]; static void init(void); static void cleanup(void); static void keyEvent( unsigned char key, int x, int y); static void mainLoop(void); static void draw( void ); int main(int argc, char **argv) { glutInit(&argc, argv); init(); // Настраиваем устройство захвата arVideoCapStart(); // Запускаем его argMainLoop( NULL, keyEvent, mainLoop ); return (0); } static void keyEvent( unsigned char key, int x, int y) { /* quit if the ESC key is pressed */ if( key == 0x1b ) { printf("*** %f (frame/sec)\n",
(double)count/arUtilTimer()); cleanup(); exit(0); } } /* main loop */ static void mainLoop(void) { ARUint8 *dataPtr; ARMarkerInfo *marker_info; int marker_num; int j, k; /* захватываем кадр */ if( (dataPtr = (ARUint8 *)arVideoGetImage()) == NULL ) { arUtilSleep(2); return; } if( count == 0 ) arUtilTimerReset(); count++; argDrawMode2D(); argDispImage( dataPtr, 0,0 ); /* Определяем маркеры в кадре */ if( arDetectMarker(dataPtr, thresh, &marker_info, &marker_num) < 0 ) { cleanup(); exit(0); } arVideoCapNext(); // Вызываем следующий захваченный кадр /* проверка видимости объекта */ k = -1; for( j = 0; j < marker_num; j++ ) { if( patt_id == marker_info[j].id ) { if( k == -1 ) k = j; else if( marker_info[k].cf < marker_info[j].cf ) k = j; } } if( k == -1 ) { argSwapBuffers(); return; } /* get the transformation between the marker and the real camera */ arGetTransMat(&marker_info[k],
patt_center,
patt_width,
patt_trans); draw(); // отризовка OpenGL argSwapBuffers(); } static void init( void ) { ARParam wparam; /* open the video path */ if( arVideoOpen( vconf ) < 0 ) exit(0); /* find the size of the window */ if( arVideoInqSize(&xsize, &ysize) < 0 ) exit(0); printf("Image size (x,y) = (%d,%d)\n", xsize, ysize); /* set the initial camera parameters */ if( arParamLoad(cparam_name, 1, &wparam) < 0 ) { printf("Camera parameter load error !!\n"); exit(0); } arParamChangeSize( &wparam, xsize, ysize, &cparam ); arInitCparam( &cparam ); printf("*** Camera Parameter ***\n"); arParamDisp( &cparam ); if( (patt_id=arLoadPatt(patt_name)) < 0 ) { printf("pattern load error !!\n"); exit(0); } /* open the graphics window */ argInit( &cparam, 1.0, 0, 0, 0, 0 ); } /* cleanup function called when program exits */ static void cleanup(void) { arVideoCapStop(); arVideoClose(); argCleanup(); } static void draw( void ) { argDrawMode3D(); argDraw3dCamera( 0, 0 ); /* извлекаем и загружаем матрицу трансформации для камеры */ argConvGlpara(patt_trans, gl_para); glMatrixMode(GL_MODELVIEW); glLoadMatrixd( gl_para ); /* тут должна быть собственно OpenGL отрисовка */ } }
Кстати, нужно упомянуть, что у ARToolKit есть биндинги для других языков, например для python.
Ссылки
ARToolKit Home
Распознавание маркера дополненной реальности
Интересный проект робота с машинным зрением.
Статья от 05.09.12
Комментариев нет:
Отправить комментарий