Извлеките облака точек С цветом, используя Project Tango; то есть получение текущего кадра камеры

Я пытаюсь создать облако точек, где каждая точка имеет цвет. Я могу получить только облако точек или заставить камеру сделать снимок, но мне нужно, чтобы они были как можно более одновременными. Если бы я мог найти изображение RGB с отметкой времени или вызвать функцию для получения текущего кадра, когда вызывается onXYZijAvailable(), я бы сделал. Я мог просто пройтись по точкам, узнать, где они пересекаются с плоскостью изображения, и получить цвет этого пикселя.

Как и сейчас, я не нашел способа получить информацию о пикселях изображения или получить цветные точки. Я видел AR-приложения, в которых камера подключается к CameraView, а затем что-то рендерится поверх, но приложение никогда не затрагивает поток с камеры.

Согласно этот должно быть возможно получить нужные мне данные и синхронизировать облако точек и плоскость изображения с помощью простого преобразования. Этот пост также говорит нечто подобное. Однако я понятия не имею, как получить данные RGB. Я не могу найти какие-либо проекты или учебные пособия с открытым исходным кодом.

Самое близкое, что я получил, это узнать, когда кадр готов, используя это:

     public void onFrameAvailable(final int cameraId) {
          if (cameraId == TangoCameraIntrinsics.TANGO_CAMERA_COLOR) {
               //Get the new rgb frame somehow.
          }
     }

Я работаю с Java API и очень хотел бы не углубляться в JNI и NDK, если это вообще возможно. Как я могу получить кадр, который наиболее точно соответствует отметке времени моего текущего облака точек?

Спасибо за помощь.

Обновление:

Я реализовал его версию для процессора, и даже после небольшой оптимизации мне удалось получить только 0,5 FPS на небольшом облаке точек. Это также связано с тем, что цвета должны быть преобразованы из собственного цветового пространства Android NV21 в собственное цветовое пространство RGBA графического процессора. Я мог бы оптимизировать его дальше, но я не собираюсь получать эффект в реальном времени с этим. Процессор на устройстве Android просто не может работать достаточно хорошо. Если вы хотите сделать это на более чем нескольких тысячах точек, сделайте дополнительные хлопоты с использованием графического процессора или сделайте это сразу.


person Noobs DeSroobs    schedule 07.12.2015    source источник


Ответы (2)


Обычно Tango передает данные цветных пикселей непосредственно в текстуру OpenGLES. В Java вы создаете целевую текстуру и регистрируете ее с помощью Tango.connectTextureId(), затем в onFrameAvailable() вы обновляете текстуру с помощью Tango.updateTexture(). Когда у вас есть цветное изображение в текстуре, вы можете получить к нему доступ с помощью вызовов рисования OpenGLES и шейдеров.

Если ваша цель — раскрасить облако точек Tango, наиболее эффективный способ сделать это — использовать графический процессор. То есть вместо извлечения цветного изображения из графического процессора и доступа к нему на Java вы вместо этого передаете данные точек в графический процессор и используете шейдеры OpenGLES для преобразования трехмерных точек в координаты двухмерной текстуры и поиска цветов из текстуры. Это довольно сложно сделать правильно, если вы делаете это в первый раз, но это может потребоваться для приемлемой производительности.

Если вам действительно нужен прямой доступ к пиксельным данным без использования C API, вам нужно отобразить текстуру в буфере, а затем прочитать данные о цвете из буфера. Это довольно сложно, если вы не привыкли к OpenGL и написанию шейдеров, но есть приложение Android Studio, которое демонстрирует, что здесь и далее описано в этом ответе. Этот проект демонстрирует как отрисовку текстуры камеры на экран, так и отрисовку в закадровый буфер и чтение пикселей RGBA.

Если вам действительно нужен прямой доступ к пиксельным данным, но вы считаете, что NDK может быть менее болезненным, чем OpenGLES, C API имеет TangoService_connectOnFrameAvailable(), который предоставляет данные о пикселях напрямую, то есть без использования OpenGLES. Обратите внимание, однако, что формат данных пикселей — NV21, а не RGB или RGBA.

person rhashimoto    schedule 10.12.2015
comment
К счастью, у меня нет проблем с OpenGL. Это Android и API танго, с которыми я борюсь. В итоге я использовал NDK для извлечения данных. Я знаю, что могу напрямую связать цветное изображение с текстурой, но мне нужен доступ к данным, чтобы изменить его и передать данные на сервер для анализа. Я написал функцию TangoService_connectOnFrameAvailable() перед тем, как отправиться домой сегодня, поэтому завтра я буду работать над извлечением данных. Я так взволнован, увидев производительность пересечения границы между c и java и насколько дорого обходится извлечение изображения! Спасибо за ваш ответ. - person Noobs DeSroobs; 11.12.2015
comment
Даже если вам нужны цветные точки вне графического процессора, весьма вероятно, что наиболее эффективным способом их окрашивания является использование графического процессора. То есть будет дешевле передавать поток данных облака точек, делать магию OpenGL в буфере рендеринга и выводить данные из буфера рендеринга, чем выполнять эти поиски (возможно, с интерполяцией) и преобразования цветового пространства на ЦП. . - person rhashimoto; 11.12.2015
comment
Сначала я хочу увидеть peeformance, поскольку программирование GPGPU на Android может быть более затруднительным. Если это слишком медленно, то я попробую сделать это. У вас есть какие-то данные по этому поводу? - person Noobs DeSroobs; 11.12.2015
comment
Я реализовал путь графического процессора для точек окраски (к буферу рендеринга, но без вызова glReadPixels(), что вам нужно было бы сделать), и это довольно быстро. Я никогда не реализовывал это на процессоре, поэтому я не могу сравнивать яблоки с яблоками. Но, основываясь на моем опыте работы с другим кодом ЦП, я предсказываю, что поиск сам по себе (только генерация адреса и выборка памяти, без преобразования 3D в 2D, интерполяции и преобразования цветового пространства) по полному полю точек XYZ будет чрезвычайно трудоемким. обложение налогом. Удачи, и дайте нам знать, так это или нет. - person rhashimoto; 11.12.2015
comment
Я реализовал его версию для процессора, и даже после небольшой оптимизации мне удалось получить 0,5 FPS на небольшом облаке точек. Это также связано с тем, что цвета должны быть преобразованы из цветового пространства NV21 в цветовое пространство RGBA. - person Noobs DeSroobs; 03.02.2016

Я делаю это сейчас, фиксируя глубину с помощью onXYZijAvailable() и изображения с помощью onFrameAvailable(). Я использую собственный код, но то же самое должно работать и в Java. Для каждого onFrameAvailable() я получаю данные изображения и помещаю их в предварительно выделенный кольцевой буфер. У меня есть 10 слотов и счетчик/указатель. Каждое новое изображение увеличивает счетчик, который возвращается от 9 к 0. Счетчик является индексом в массиве изображений. Я сохраняю метку времени изображения в подобном кольцевом буфере. Когда я получаю изображение глубины, onXYZijAvailable() я получаю данные и метку времени. Затем я просматриваю изображения, начиная с самого последнего и двигаясь назад, пока не найду изображение с самой близкой отметкой времени к данным о глубине. Как вы упомянули, вы знаете, что данные изображения не будут из того же кадра, что и данные глубины, потому что они используют одну и ту же камеру. Но, используя эти два вызова (в JNI), я постоянно получаю +/- 33 мс, то есть предыдущий или следующий кадр.

Я не проверял, насколько близко было бы просто наивно использовать самую последнюю обновленную рамку изображения rgb, но это должно быть довольно близко.

Просто убедитесь, что вы используете onXYZijAvailable() для управления временем, потому что глубина обновляется медленнее, чем rgb.

Я обнаружил, что запись отдельных изображений в файловую систему с использованием OpenCV::imwrite() не соответствует реальному времени камеры. Я не пробовал потоковую передачу в файл с использованием видеокодека. Это должно быть намного быстрее. В зависимости от того, что вы планируете делать с данными в конечном итоге, вам нужно быть осторожным при хранении результатов.

person Ken    schedule 06.01.2016
comment
API-интерфейсы Java и C ведут себя неодинаково. Хотя обратный вызов C onFrameAvailable() передает пиксельные данные, обратный вызов Java этого не делает. Для получения данных о пикселях в чистой Java требуется пройти через OpenGL. - person rhashimoto; 28.01.2016