В этой статье я кратко расскажу о своём опыте использования методов обработки изображений и использовании библиотеки дополненной реальности ARToolKit.
Дополненная реальность - модное и набирающее обороты направление. И поэтому, мне давно хотелось приобщиться к этим технологиям. Но такие системы использует довольно сложные графические алгоритмы, реализация которых весьма трудоёмка. Тем не менее, некоторые из них мне довелось попробовать, о них я напишу вскользь, но со ссылками на различные интересные материалы. Но если вдруг мой дорогой читатель не интересуется методами обработки изображений, то сразу может переходить к пункту про ARToolKit.
Необходимо заметить, что далее я буду говорить о системах с заранее подготовленными опорными образами(маркерами).
Отступление о методах обработки изображений
Начиная изучать данную тему я столкнулся с банальной проблемой: с чего начать? Хотя вскоре нашел множество интересных статей, ссылки на которые привожу далее по тексту.
Практически всегда, в таком случае, анализ изображения должен состоять из следующих этапов:
- бинаризация
Перевод изображения в однобитный вид - т.е. создать некую маску значащих объектов. Эти методы довольно просты в реализации, но они отнюдь не универсальны. Для каждой новой задачи приходится заново определять подходящий.
На мой взгляд самым наилучшим для наших целей является метод Оцу(исходники на С), но если нужно что-то по-быстрее, то стоит выбрать адаптивный метод.
- сегментация(выделение контуров, замкнутых областей)
Всё разнообразие методов сегментации вы можете увидеть ниже на рисунке.
Чуть подробнее об этом и о бинаризации можно прочитать здесь.
Очень часто для того, чтобы выделить на изображении какие-либо объекты сначала производится определение границ. Стандартом в этой области является метод Канни(C# код). Все они основаны на свертке изображений с соответствующими операторами. А для нахождения на изображении различных примитивов( кругов, многоугольников и т.д.) можно использовать преобразование Хафа.
Существует ещё много интересных методов, но мы не будем упоминать и использовать их в рамках этой статьи.
- анализ сегментов
Тут могут быть привлечены самые различные алгоритмы от простого перебора до нейросетей. Самым простым способом является сравнение объекта с шаблоном, а точнее сравнение так называемых моментов контуров объектов. В конце статьи приведена ссылка на проект робота "Зоркий" с машинным зрением. Там вы найдёте кое-что интересное на данную тему.
Что такое 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 отрисовка */
}
}
Просто, не правда ли? Пробуйте и будет вам профит.
Но если вы хотите затеять что-нибудь более масштабное с точки зрения обработки изображений, то вам больше подойдёт ныне популярная библиотека OpenCV и (для ознакомления) вот эта серия статей .
Ссылки
ARToolKit Home
Распознавание маркера дополненной реальности
Интересный проект робота с машинным зрением. (Внутри куча интересного материала)
Компьютерное зрение на Java для Android. Обзор библиотеки BoofCV
(BoofCV - Облегчённый аналог OpenCV)
Комментариев нет:
Отправить комментарий