使用 Project Tango 提取带有颜色的点云;冰。获取当前相机帧
Extract pointclouds WITH colour using the Project Tango; i.e. getting the current camera frame
我正在尝试生成一个点云,其中每个点都有一种颜色。我可以只获取点云,也可以让相机拍照,但我需要它们尽可能同步。如果我可以在调用 onXYZijAvailable()
时查找带有时间戳的 RGB 图像或调用函数来获取当前帧,我就完成了。我可以遍历这些点,找出它与图像平面相交的位置,并获得该像素的颜色。
因为现在我还没有找到任何方法来获取图像的像素信息或获取彩色点。我见过 AR 应用程序,其中相机连接到 CameraView
,然后在顶部呈现内容,但相机流从未被应用程序触及。
据 post it should be possible to get the data I want and synchronize the point cloud and the image plane by a simple transformation. This post 也有类似的说法。但是,我不知道如何获取 RGB 数据。我找不到任何开源项目或教程。
我得到的最接近的结果是通过使用以下命令找出框架何时准备就绪:
public void onFrameAvailable(final int cameraId) {
if (cameraId == TangoCameraIntrinsics.TANGO_CAMERA_COLOR) {
//Get the new rgb frame somehow.
}
}
我正在使用 Java API,如果可能的话,我非常不想深入研究 JNI 和 NDK。如何获得与我当前点云的时间戳最匹配的帧?
感谢您的帮助。
更新:
我实现了它的 CPU 版本,即使在对其进行了一些优化之后,我也只能在小型点云上获得 0.5 FPS。这也是由于颜色必须从 android 原生 NV21 颜色 space 转换为 GPU 原生 RGBA 颜色 space。我本可以进一步优化它,但我不会用它来获得实时效果。 CPU 在 android 设备上的表现根本不够好。如果您想在超过几千个点上执行此操作,请使用 GPU 或在 post.
中进行额外的麻烦。
Tango 通常将彩色像素数据直接传送到 OpenGLES 纹理。在 Java 中,您创建目标纹理并将其注册到 Tango.connectTextureId(), then in the onFrameAvailable() callback you update the texture with Tango.updateTexture()。在纹理中获得彩色图像后,您可以使用 OpenGLES 绘图调用和着色器访问它。
如果您的目标是为 Tango 点云着色,最有效的方法是在 GPU 中。也就是说,不是将彩色图像从 GPU 中拉出并在 Java 中访问它,而是将点数据传递到 GPU 并使用 OpenGLES 着色器将 3D 点转换为 2D 纹理坐标并查找颜色从纹理。如果您是第一次这样做,要做到这一点相当棘手,但可能需要获得可接受的性能。
如果您真的想要在不使用 C API 的情况下直接访问像素数据,
您需要将纹理渲染到缓冲区中,然后从缓冲区中读取颜色数据。如果您不习惯 OpenGL 和编写着色器,这会有点棘手,但有一个 Android Studio 应用程序可以演示 here, and is further described in this answer。该项目演示了如何将相机纹理绘制到屏幕上,以及如何绘制到屏幕外缓冲区和读取 RGBA 像素。
如果您真的想要直接访问像素数据,但认为 NDK 可能比 OpenGLES 更轻松,C API 有 TangoService_connectOnFrameAvailable()直接为您提供像素数据,即无需通过 OpenGLES。不过要注意,像素数据的格式是NV21,不是RGB或者RGBA。
我现在通过使用 onXYZijAvailable() 捕获深度和使用 onFrameAvailable() 捕获图像来执行此操作。我使用的是本机代码,但在 Java 中应该同样有效。对于每个 onFrameAvailable(),我都会获取图像数据并将其放入预分配的环形缓冲区中。我有 10 个插槽和一个 counter/pointer。每个新图像都会递增计数器,计数器从 9 循环回到 0。计数器是图像数组的索引。我将图像时间戳保存在类似的环形缓冲区中。当我获得深度图像时,onXYZijAvailable(),我获取数据和时间戳。然后我返回浏览图像,从最近的图像开始向后移动,直到找到时间戳与深度数据最接近的图像。正如您所提到的,您知道图像数据不会与深度数据来自同一帧,因为它们使用相同的相机。但是,使用这两个调用(在 JNI 中)我在 +/- 33 毫秒内获得,即上一帧或下一帧,在一致的基础上。
我还没有检查过天真地使用最近更新的 rgb 图像帧有多接近,但这应该非常接近。
只需确保使用 onXYZijAvailable() 来驱动时序,因为深度更新比 rgb 慢。
我发现使用 OpenCV::imwrite() 将单个图像写入文件系统跟不上相机的实时性。我没有尝试使用视频编解码器流式传输到文件。那应该快得多。根据您最终打算如何处理数据,您需要小心存储结果的方式。
我正在尝试生成一个点云,其中每个点都有一种颜色。我可以只获取点云,也可以让相机拍照,但我需要它们尽可能同步。如果我可以在调用 onXYZijAvailable()
时查找带有时间戳的 RGB 图像或调用函数来获取当前帧,我就完成了。我可以遍历这些点,找出它与图像平面相交的位置,并获得该像素的颜色。
因为现在我还没有找到任何方法来获取图像的像素信息或获取彩色点。我见过 AR 应用程序,其中相机连接到 CameraView
,然后在顶部呈现内容,但相机流从未被应用程序触及。
据
我得到的最接近的结果是通过使用以下命令找出框架何时准备就绪:
public void onFrameAvailable(final int cameraId) {
if (cameraId == TangoCameraIntrinsics.TANGO_CAMERA_COLOR) {
//Get the new rgb frame somehow.
}
}
我正在使用 Java API,如果可能的话,我非常不想深入研究 JNI 和 NDK。如何获得与我当前点云的时间戳最匹配的帧?
感谢您的帮助。
更新:
我实现了它的 CPU 版本,即使在对其进行了一些优化之后,我也只能在小型点云上获得 0.5 FPS。这也是由于颜色必须从 android 原生 NV21 颜色 space 转换为 GPU 原生 RGBA 颜色 space。我本可以进一步优化它,但我不会用它来获得实时效果。 CPU 在 android 设备上的表现根本不够好。如果您想在超过几千个点上执行此操作,请使用 GPU 或在 post.
中进行额外的麻烦。Tango 通常将彩色像素数据直接传送到 OpenGLES 纹理。在 Java 中,您创建目标纹理并将其注册到 Tango.connectTextureId(), then in the onFrameAvailable() callback you update the texture with Tango.updateTexture()。在纹理中获得彩色图像后,您可以使用 OpenGLES 绘图调用和着色器访问它。
如果您的目标是为 Tango 点云着色,最有效的方法是在 GPU 中。也就是说,不是将彩色图像从 GPU 中拉出并在 Java 中访问它,而是将点数据传递到 GPU 并使用 OpenGLES 着色器将 3D 点转换为 2D 纹理坐标并查找颜色从纹理。如果您是第一次这样做,要做到这一点相当棘手,但可能需要获得可接受的性能。
如果您真的想要在不使用 C API 的情况下直接访问像素数据, 您需要将纹理渲染到缓冲区中,然后从缓冲区中读取颜色数据。如果您不习惯 OpenGL 和编写着色器,这会有点棘手,但有一个 Android Studio 应用程序可以演示 here, and is further described in this answer。该项目演示了如何将相机纹理绘制到屏幕上,以及如何绘制到屏幕外缓冲区和读取 RGBA 像素。
如果您真的想要直接访问像素数据,但认为 NDK 可能比 OpenGLES 更轻松,C API 有 TangoService_connectOnFrameAvailable()直接为您提供像素数据,即无需通过 OpenGLES。不过要注意,像素数据的格式是NV21,不是RGB或者RGBA。
我现在通过使用 onXYZijAvailable() 捕获深度和使用 onFrameAvailable() 捕获图像来执行此操作。我使用的是本机代码,但在 Java 中应该同样有效。对于每个 onFrameAvailable(),我都会获取图像数据并将其放入预分配的环形缓冲区中。我有 10 个插槽和一个 counter/pointer。每个新图像都会递增计数器,计数器从 9 循环回到 0。计数器是图像数组的索引。我将图像时间戳保存在类似的环形缓冲区中。当我获得深度图像时,onXYZijAvailable(),我获取数据和时间戳。然后我返回浏览图像,从最近的图像开始向后移动,直到找到时间戳与深度数据最接近的图像。正如您所提到的,您知道图像数据不会与深度数据来自同一帧,因为它们使用相同的相机。但是,使用这两个调用(在 JNI 中)我在 +/- 33 毫秒内获得,即上一帧或下一帧,在一致的基础上。
我还没有检查过天真地使用最近更新的 rgb 图像帧有多接近,但这应该非常接近。
只需确保使用 onXYZijAvailable() 来驱动时序,因为深度更新比 rgb 慢。
我发现使用 OpenCV::imwrite() 将单个图像写入文件系统跟不上相机的实时性。我没有尝试使用视频编解码器流式传输到文件。那应该快得多。根据您最终打算如何处理数据,您需要小心存储结果的方式。