пятница, 19 февраля 2016 г.

Дополненная реальность с помощью ARToolKit на C


Дополненная реальность — добавление к поступающим из реального мира ощущениям мнимых объектов, обычно вспомогательно-информативного свойства. Применяется в проектах различнейшего сорта: от систем свой-чужой до хирургии или компьютерных игр.

В этой статье я кратко расскажу о своём опыте использования методов обработки изображений и использовании библиотеки дополненной реальности 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

Комментариев нет:

Отправить комментарий