В статье автор показывает, как можно реализовать программное средство для моделирования объектов окружающей среды на основе технологии Google Tango. Дополнительно автор приводит результаты экспериментов над полученным продуктом.
Ключевые слова: Google Tango, дополненная реальность, разработка, эксперимент.
Разработка программного продукта проходит в среде разработки Android Studio. Программный продукт состоит из самостоятельных основных модулей, показанных на рисунке 1.
Рис. 1. Основные программные модули приложения
Каждый из модулей можно реализовать различными способами, данное программное решение не является окончательным и в будущем будет редактироваться для оптимизации и улучшения качества моделей. Основные вычислительные модули реализованы на языке C, так как именно на этом языке представлен более мощный интерфейс для разработчиков в отличие от языков java или Kotlin.
Разработка модуля приложения
Модуль приложения состоит из основных разработок для запуска приложения на смартфонах под управление операционной системы Android. Данная часть проекта состоит из следующих пакетов: main, ui, viewer. Каждый из пакетов имеет свою зону ответственности.
Пакет main отвечает за работу основных других модулей проекта, фактически, является мостом между приложением и C библиотеками. Дополнительно он структурирует готовые модели в файловой системе, что позволяет получать набор путей к этим объектам. Основным рабочим классом является MainActivity, который отвечает за главный экран сканирования, отрисовывая при своей работе предварительно отсканированную 3D модель объекта. Также тут происходит инициализация модуля Tango Service. Самым интересным классом в этом пакете является JNI, который связывает низкоуровневую часть программного средства и приложение. Он состоит из ряда методов, которые вызываются на уровне приложения, но выполняются на языке C. Это вызывается за счет использования механизма Java Native Interface. В качестве примера можно выделить функцию texturize, при вызове которой работа предоставляется модулю текстурирования.
Пакет ui отвечает за основной интерфейс системы. Он состоит из таких основных классов, как FileManagerActivity, FileAdapter, Service. Первые два файла отвечают за отрисовку главного экрана приложения, на котором можно видеть список уже созданных 3D моделей объектов, удалить, изменить название файла. При нажатии на каждый элемент этого списка открывается экран просмотра моделей. Отсюда можно начать сканировать новый объект при нажатии на кнопку «+». Класс Service необходим для запуска трудоемких задач в другом потоке, чтобы не блокировать основной поток.
Пакет Viewer необходим для просмотра уже готов 3D моделей. Ядром этой части приложения является библиотека Android 3D Model Viewer. Она предоставляет интерфейс для отрисовки моделей различных форматов. Для успешного и удобного просмотра эти моделей разработаны следующие классы:
– TouchController — управляет жестами, позволяет вращать 3D модель по всем осям координатной плоскости. В этом классе также присутствуют и другие вычисления, например для приближения объекта.
– SceneLoader — отвечает за загрузку и открытие файла, управляет начальными состояниями сцены, такими как освещение, наложение текстур и другие.
– ModelRenderer — необходим для рендеринга модели в реальном времени, отвечает за прорисовку всех текстур, управляет анимацией движения света или сцены.
– ModelActivity — отвечает за полноценную работу остальных классов, объединяя их в одном месте, управляет общей работой этого экрана относительно операционной системы.
Разработка Tango Service
Модуль Tango Service необходим для инициализации всей работы с технологией дополненной реальности Google Tango. При старте нового сканирования объектов инициализируется специальный системный сервис для работы с Tango. После этого действия необходимо установить все настройки для этого сервиса. Их количество достаточно велико, но можно выделить несколько основных:
–config_enable_depth — отвечает за включение датчика глубины, который способен определять расстояние до объекта;
– config_depth_mode — для этой конфигурации используется константа TANGO_POINTCLOUD_XYZC, которая указывает на то, что структура, получаемая после сканирования кадра будет иметь 4 координаты: x, y, z и c, где последняя координата является значением «доверия» для точки. Значение c лежит в интервале [0;1], и, чем оно выше, тем меньше можно достичь шумов, поэтому, все значения ниже 1 фильтруются;
–max_depth — отвечает за максимальную дистанцию, на которую будут проецироваться лучи инфракрасного датчика глубины;
–generate_color — данная конфигурацию указывает, будет ли получаемая после сканирование кадра структура иметь цветовое значение;
Остальные параметры также являются достаточно важными для полноценной работы системы, но различных конфигураций в системе больше 30, поэтому нет смысла описывать каждую, так как они уже в меньшей степени влияют на качество получаемых объектов. В ходе опытов были установлены оптимальные значения всех конфигураций.
После успешного конфигурирования необходимо подписаться на обратные вызовы внутренних событий фреймворка Google Tango. Основных события два:
- connectOnPointCloudAvailable — при готовности получает от Tango соответствующую структуру, в которой находится информация о количестве найденных точек в текущем кадре и массиве, состоящем из координат x, y, z, c;
- connectOnFrameAvailable — позволяет получить буфер, состоящий из набора пикселей текущего отсканированного кадра.
По окончанию успешной подписки на эти события система сразу же начинает получать готовые кадры, после чего управление приложение передается следующему модулю.
Описание основных структур данных ивычислительных методов GoogleTango
В технологии Google Tango используется ряд специфических типов данных и методов для полноценной работы с дополненной реальностью и реконструкции кадра. Ниже представлено описание основных структур данных фреймворка Tango:
– TangoPointCloud — описывает и хранит информацию, возвращаемую от датчика глубины. Состоит из информации о количестве точек в текущем кадре и набора векторов из четырех значений, описывающие координаты точки в трехмерном пространстве и значения «уверенности», которое означает качество полученной точки, где 1 — максимально качественная точка.
– TangoEvent — структура, которая хранит информацию о событиях, пришедших от системы, например, недостаточной освещенности. Хранит в себе время события, тип и описание.
– TangoPose — хранит в себе информации о смещении и повороте кадра относительно начального или первого кадра. Содержит массив translation из трех координат смещения и массив orientation из 4 элементов, который является кватернионом.
– TangoImageBuffer — структура, содержащая информации о буфере байт изображения полученного кадра. Состоит из указания размеров картинки, номере кадра и набора цветных пикселей в цветовой модели YUV. В процессе работы прложения данная структура преобразуется в ранее описанный объект Image.
– TangoMesh — описывает структуру полигональной сетки текущего кадра. Содержит информацию о наборах вершин, нормалей, цветов и текстур. Используется для получения полноценной модели.
– Tango3DR_GridIndexArray — используется для хранения набора индексов векселей в трехмерной сетке. Совместно с TangoMesh описывают структуру объекта.
Фреймворк Google Tango дополнительно содержит в себе несколько функций, которые облегчают работу с вышеописанными структурами. Так, например, чтобы получить позу из системы в определенный момент времени можно вызвать метод Tango3DR_GetPoseAtTime. Для извлечения определенного сегмента меша из системы используется метод Tango3DR_extractMeshSegment, а для удаление некачественных полигональных сеток вызывается функция Tango3DR_Mesh_Destroy. Метод Tango3DR_updateFromPointCloud необходим для создания мешей набора облака точек. На вход передается структура описания облака точек и цветов для каждой точки, что необходимо при реконструкции объектов. На выходе функции получается обновленная структура векселей для меширования.
В самой технологии и в разработке приложения используется гораздо больше структур данных и функций, который оказывают меньшее влияние на качество получаемых моделей. Описанные выше типы и методы являются основными и без их наличия реконструкция объектов окружающей среды не представлялась бы возможной.
Разработка модуля сканирования окружения
Модуль сканирования окружения является одним из самых важных в системе и, одновременно, одним из самых массивных и сложных. Его суть заключается в обработке данных, пришедших из модуля Tango Service, а именно в манипуляции данными структур TangoPointCloud, Tango3DR_Image_Buffer и Tango3DR_Pose. После успешной подписки на события получения текущего кадра и получения доступного облака точек приложение начинает их периодически получать. Обработка этих событий описана ниже.
При получении нового события о наличии обновленного облака точек с помощью колбэка OnPointCloudAailable необходимо его сохранить. Запись в оперативную память устройства этих данных происходит с помощью следующего кода:
Void App::onPointCloudAvailable(TangoPointCloud *pc) {
std::vector
= tango.Pose(pc->timestamp, 0);
if (transform[DEPTH_CAMERA].status_code != TANGO_POSE_VALID)
return;
point_cloud_matrix_=tango.Convert(transform)[DEPTH_CAMERA];
TangoSupport_updatePointCloud(tango.Pointcloud(), pc);
point_cloud_available_ = true;
}
Первым делом необходимо получить коллекцию из специальных матриц преобразования TangoMatrixTransformData для двух типов камеры: обычной цветной камеры и датчика глубины. Данная матрица преобразования состоит из вектора из 16 элементов. Для работы вектора недостаточно, поэтому необходимо преобразовать все данные в матрицу размером 4x4, которая в итоге содержит информацию о текущем положении устройства относительно реального мира, а именно смещение и поворот. В конечном итоге полученная матрица сохраняется в специальное хранилище. Этот обратный системный вызов приходит примерно раз в секунду. Пример итогового объекта в виде облака точек можно увидеть на рисунке 2.
Рис. 2. готовый объект в виде цветного облака точек
При получении события о наличии доступного кадра необходимо сохранить в структуру Tango3DR_ImageBuffer информацию о текущем кадре в виде набора байт из пикселей. После этого уже начинается один из самых сложных процессов обработки каждого кадра. Для этого создаётся отдельный поток каждый раз по приходу нового изображения, что может достигать 60 кадров в секунду. На данном этапе работы приложения можно выделить следующие действия:
- получить вектор из матриц преобразования для разных типов камер текущего кадра;
- проверить статус матрицы преобразования для цветной камеры, и, если она является недействительной, закончить выполнение потока;
- получить «позу» для текущего кадра путем извлечения данных из полученной выше матрицы преобразования для цветной камеры, состоящей из векторов смещения и кватерниона поворота;
- получить «позу» для последнего сохраненного облака точек;
- провести реконструкции для текущего цветного кадра и облака точек с помощью вызова внутреннего метода библиотеки Tango3DR_updateFromPointCloud передав туда все ранее полученные данные;
- сохранить полученное облако точек в файл, перевести в формат.jpg полученный кадр и сохранить его в оперативной памяти в классе Dataset;
- создать вектор, состоящий из пар, которые включают в себя индексы трехмерной сетки и меш, созданный для этого индекса. Фактически, на данном этапе с помощью вызова библиотечного метода Tango3DR_extractMeshSecgment создаётся промежуточная текстура для временной отрисовки ее на экране смартфона. Данный меш объединяется с уже раннее созданными, что образует целостную картинку уже отсканированной местности;
После выполнение этих методов до 60 раз в секунду обновляется глобальное облако точек, создаётся промежуточная полигональная сетка для ее отображения на экране телефона и сохраняются полученные «позы» для текущей сессии сканирование окружающей среды. Для этих же 60 раз в секунду модуль приложения вызывает метод onDrawFrame для обновления временного превью модели для пользователя приложения. Сокращенный код этого метода представлен ниже:
void App::OnDrawFrame() {
std::vector
= tango.Pose(0, landscape);
glm::mat4 matrix = tango.Convert(transform)[OPENGL_CAMERA];
scene.renderer->camera.SetTransformation(matrix);
glm::vec4 move = scene.renderer>camera.GetTransformation()
* glm::vec4(0, 0, movez, 0);
scene.renderer->camera.position
+= glm::vec3(move.x, move.y, move.z);
for (std::pair
scene.renderer->Render(
&s.second->vertices[0][0], 0, 0,
(unsigned int*)&s.second->colors[0][0],
s.second->num_faces * 3, &s.second->faces[0][0]
);
}
}
Первым этапом необходимо получить матрицу преобразования для типа камеры OPENGL_CAMERA. После этого происходит сохранение текущей позиции, кватерниона поворота и значения увеличения для объекта камеры. Далее необходимо обновить реальное текущее положение камеры относительно виртуальной сцены путем прибавления к текущему вектору позиции камеры сдвига относительно всех осей. На заключительном этапе обновления кадра на экране смартфона вызывается метод Render у класса Scene. В данный метод передаётся ранее обновленный меш. Меш состоит из набора вершин, нормалей и цвета этих элементов. Тем самым с помощью библиотека OpenGL отрисовывается актуальная на текущий момент полигональная сетка.
Разработка модуля реконструкции итекстурирования
После завершения сканирования окружения необходимо реконструировать всю полученную временную сцену в качественный объект в формате.obj. Именно для этого сохраняются в оперативной памяти и временных файлах полученные данные в модуле сканирования окружения. Реконструкция объекта является достаточно трудоемким процессом, поэтому может достигать несколько минут. Если пытаться обрабатывать текстурирование на стороне сервера или настольного компьютера скорость работы может значительно вырасти, поэтому, в будущем, планируется перенести данную обработку с мобильного телефона.
Управление этому модулю происходит по нажатии на кнопку «сохранить». Сам по себе участок кода может быть достаточно маленьким, потому что средства Google Tango позволяют провести полную реконструкцию объекта самостоятельно, однако, чаще всего, качество моделей в таких случаях достаточно спорное. Ниже представлен код реконструкции сцены посредством инструментов технологии:
Status TangoTexturize::Process(std::string filename) {
Tango3DR_Mesh mesh;
Tango3DR_Status ret;
ret = Tango3DR_getTexturedMesh(context, &mesh);
ret = Tango3DR_Mesh_saveToObj(&mesh, filename.c_str());
ret = Tango3DR_Mesh_destroy(&mesh);
ret = Tango3DR_TexturingContext_destroy(context);
return ret;
}
Как видно из этого участка кода идет последовательный вызов функций фреймворка. В метод Tango3DR_getTextiredMesh передается объект context типа Tango3DR_TexturingContext, который обновляется по мере сканирования окружения и сохраняет общую структуру текстур всей сцены. Данный метод возвращает полную полигональную текстурированную сетку всей сцены. Далее идет запись в файл информации о созданных мешах. Уже ранее созданный файл не перезаписывается заново, он обновляется в зависимости от сохраненных ранее вершин, нормалей, цветов. Дополнительно этот метод создает файл специального формата, который описывает набор текстур всех полигональных сеток в виде треугольников. На заключительном этапе просто идет очистка данных. На текущем этапе выполнения программы можно сказать, что модель готова, однако в ходе экспериментов было выявлено, что такие модели имеют много ошибочных мешей и пустых пространств, или дыр. Для того, чтобы это исправить, используется библиотека Poisson для реконструирования объектов. Такая постобработка занимает дополнительное время. Для улучшения качества итоговой модели можно использовать различные входные параметры библиотеки или пытаться исправить недочеты в вычислениях. Так, например, в приложении был разработан метод, который корректирует все полученные позы относительно траектории движения и самой первой полученной позы. Это действие помогает сгладить резкие рывки камеры, удаление или приближения к объекту. Этот этап не является сложным в реализации, однако занимает много вычислительного времени.
Проведение экспериментов
Так как система имеет достаточно большое количество конфигураций было принято решение выбрать экспериментальным путем наилучший вариант создания 3D моделей окружающей среды для достижения оптимального соотношения качества модели и времени обработки объекта. Качество полученных отсканированных моделей может меняться в зависимости от использования таких основных параметров, как:
– коррекция поз — сглаживание всех полученных кадров, что приводит к повышению качества итоговой модели;
– удаление шумов кадров — фильтрация недостоверных точек с получаемого на каждом кадре облака точек;
– реконструкция модели для удаления дыр, или Poisson реконструкция.
Ниже представлены несколько экспериментов с различными комбинациями этих параметров.
Входные данные и результат по времени первого эксперимента показан в таблице 1 и на рисунке 3. Как видно из результата, при стандартном сканировании без дополнительных улучшений получается модель среднего качества с достаточно маленькой затратой времени. Как и предполагалось, без дополнительной постобработки на создание такой модели уходит 84 секунды, что является наилучшим показателем по времени. Такую модель камня можно использовать, например, в компьютерных играх с невысоким качеством текстурирования.
Таблица 1
Входные данные ирезультат первого эксперимента
Конфигурация |
Используется |
Коррекция поз |
нет |
Фильтрация шумов |
нет |
Poisson реконструкция |
нет |
Итоговое время текстурирования, с 84 |
|
Рис. 3. Полученная модель после первого эксперимента без дополнительных постобработок
Таблица 2
Входные данные ирезультат второго эксперимента
Конфигурация |
Используется |
Коррекция поз |
да |
Фильтрация шумов |
да |
Poisson реконструкция |
да |
Итоговое время текстурирования, с 496 |
|
Для проведения второго эксперимента были включены все дополнительные конфигурации для постобработки. Качество итоговый модели получилось достаточно высоким. На камне видны все углубления и различные шероховатости. В данном случае необходимо ручным способом удалить ненужные текстуры земли. С минимальной ручной корректировкой на выходе может получится качественная модель камня. Затраченное на постобработку время превысило 8 минут ожидания, что очень много. Для ускорения времени можно перенести процесс текстурирования на сервер. В будущем планируется добавление распараллеливания покадровой обработки, но это может сказаться на качестве, потому что в текущей версии высокое качество достигается путем последовательного постпроцессинга. Полученная итоговая модель показана на рисунке 4. В таблице 2 указаны конфигурации и итог эксперимента.
Рис. 4. Полученная модель после второго эксперимента со всеми постобработками
В третьем эксперименте в качестве дополнительных постобработок применялась только коррекция поз. Относительно второго эксперимента время текстурирования модели уменьшилось до 4 минут, что в два раза меньше. Качество полученной модели среднее, также видны углубления камня и шероховатости, но при этом присутствует некоторое количество черных дыр. В некоторых местах структура камня кажется несглаженной. Дополнительно, был проведен тест, который не попал в описание. В нем одновременно использовались корректировка поз и удаление дыр. Эффект такого теста аналогичен второму как по времени, так и по качеству модели. В таблице 3 указаны входные параметры 3 эксперимента и результат, а на рисунке 5 показан полученная модель камня.
Таблица 3
Входные данные ирезультат третьего эксперимента
Конфигурация |
Используется |
Коррекция поз |
да |
Фильтрация шумов |
нет |
Poisson реконструкция |
нет |
Итоговое время текстурирования, с 267 |
|
Рис. 5. полученная модель после третьего эксперимента с применением корректировки поз
Таблица 4
Входные данные ирезультат шестого эксперимента
Конфигурация |
Используется |
Коррекция поз |
нет |
Фильтрация шумов |
да |
Poisson реконструкция |
да |
Итоговое время текстурирования, с 228 |
|
Рис. 6. Полученная модель после четвертого эксперимента с применением фильтрации шумов и Poisson реконструкции
Для проведения последнего эксперимента применялись фильтрация шумов и Poisson реконструкция одновременно. В таблице 4.4 представлены конфигурации, а на рисунке 4.4 показан результат постобработки сцены. Можно выделить, что после проведение такого эксперимента отсутствуют дыры, четко видны изгибы объекта, но не хватает сглаженности. Такая модель однозначна одна из наилучших по качеству и времени выполнения. Однако для полноценного использования необходимо вручную отредактировать землю вокруг сцены.
В главе были проведены эксперименты по моделированию одинаковой сцены с использованием различных конфигураций. Таких тестовых моделирований было гораздо больше, но они не вошли в описание эксперимента, так как результаты по времени и качеству были идентичными описанным выше экспериментам.
Литература:
- Доступно о кватернионах и их преимущества — [Электронный ресурс] — Режим доступа: https://habr.com/ru/post/426863/
- Android 3D Model Viewer — [Электронный ресурс] — Режим доступа: https://github.com/andresoviedo/android-3D-model-viewer
- Poisson Surface Reconstruction manual — [Электронный ресурс] — Режим доступа: https://doc.cgal.org/latest/Poisson_surface_reconstruction_3/index.html
- Google Tango examples C — [Электронный ресурс] — Режим доступа: https://github.com/googlearchive/tango-examples-c
- Tango (платформа) — [Электронный ресурс] — Режим доступа: https://web.archive.org/web/20170323065226/https://developers.google.com/tango/overview/concepts.