我正在尝试制作一个点云,每个点都有一个颜色。我可以得到点云,或者我可以让相机拍照,但我需要它们尽可能同时。如果我可以查找带有时间戳的RGB图像,或者在调用onXYZijAvailable()
时调用函数来获取当前帧,我就完成了。我可以翻看这些点,找出它与图像平面相交的位置,并获得该像素的颜色。
现在我还没有找到任何方法来获取图像的像素信息或获得彩色点。我已经看到了相机连接到CameraView
的AR应用程序,然后事物呈现在顶部,但应用程序从未触及相机流。
根据this帖子,应该可以获得我想要的数据,并通过简单的转换同步点云和图像平面。 This帖子也说了类似的话。但是,我不知道如何获取RGB数据。我找不到任何开源项目或教程。
我得到的最接近的是通过使用它来找出框架何时准备就绪:
public void onFrameAvailable(final int cameraId) {
if (cameraId == TangoCameraIntrinsics.TANGO_CAMERA_COLOR) {
//Get the new rgb frame somehow.
}
}
我正在使用Java API,我非常希望尽可能不深入研究JNI和NDK。如何获得与当前点云的时间戳最匹配的帧?
感谢您的帮助。
更新
我实现了它的CPU版本,甚至在优化它之后我只能在一个小点云上获得.5 FPS。这也是因为必须将颜色从android原生NV21颜色空间转换为GPU原生RGBA颜色空间。我可以进一步优化它,但我不会对此产生实时效果。 Android设备上的CPU执行得不够好。如果你想在超过几千点的情况下做到这一点,那就去使用GPU的额外麻烦或者在帖子中做到这一点。
答案 0 :(得分:3)
Tango通常将彩色像素数据直接传送到OpenGLES纹理。在Java中,您创建目标纹理并将其注册到Tango.connectTextureId(),然后在onFrameAvailable()回调中使用Tango.updateTexture()更新纹理。在纹理中获得彩色图像后,可以使用OpenGLES绘图调用和着色器访问它。
如果您的目标是为Tango点云着色,最有效的方法是在GPU中。也就是说,不是将彩色图像从GPU中拉出并用Java访问它,而是将点数据传递到GPU并使用OpenGLES着色器将3D点转换为2D纹理坐标并从纹理中查找颜色。如果你是第一次这样做的话,这是非常棘手的,但可能需要可接受的性能。
如果确实希望在不使用C API的情况下直接访问像素数据, 您需要将纹理渲染到缓冲区中,然后从缓冲区中读取颜色数据。如果您不习惯使用OpenGL和编写着色器,这有点棘手,但有一个Android Studio应用程序可以演示here,并在this answer中进一步说明。该项目演示了如何将相机纹理绘制到屏幕,以及如何绘制到屏幕外缓冲区并读取RGBA像素。
如果确实希望直接访问像素数据,但确定NDK可能不如OpenGLES痛苦,则C API具有TangoService_connectOnFrameAvailable(),可直接为您提供像素数据,即无需进行通过OpenGLES。但请注意,像素数据的格式为NV21,不是 RGB或RGBA。
答案 1 :(得分:1)
我现在通过使用onXYZijAvailable()捕获深度和使用onFrameAvailable()捕获图像来实现此目的。我使用的是本机代码,但同样适用于Java。对于每个onFrameAvailable(),我获取图像数据并将其放入预先分配的环形缓冲区中。我有10个插槽和一个计数器/指针。每个新图像递增计数器,计数器从9循环回到0.计数器是图像数组的索引。我将图像时间戳保存在类似的环形缓冲区中。当我得到深度图像onXYZijAvailable()时,我抓住了数据和时间戳。然后我回顾图像,从最近的图像开始向后移动,直到找到与深度数据具有最接近时间戳的图像。如您所述,您知道图像数据不会与深度数据位于同一帧中,因为它们使用相同的相机。但是,使用这两个调用(在JNI中)我在+/- 33毫秒内,即前一帧或下一帧,在一致的基础上。
我还没有检查过天真地使用最近更新的rgb图像帧有多接近,但这应该非常接近。
请确保使用onXYZijAvailable()来驱动时间,因为深度更新比rgb更慢。
我发现使用OpenCV :: imwrite()将单个图像写入文件系统并不能跟上相机的实时时间。我还没有尝试使用视频编解码器流式传输到文件。那应该快得多。根据您计划最终对数据的处理,您需要小心存储结果的方式。