Android camera2 API - 实时显示处理后的帧
Android camera2 API - Display processed frame in real time
我正在尝试创建一个实时处理相机图像并将其显示在屏幕上的应用程序。我正在使用 camera2 API。我创建了一个本地库来使用 OpenCV 处理图像。
到目前为止,我已经成功地设置了一个 ImageReader,它可以像这样以 YUV_420_888 格式接收图像。
mImageReader = ImageReader.newInstance(
mPreviewSize.getWidth(),
mPreviewSize.getHeight(),
ImageFormat.YUV_420_888,
4);
mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mImageReaderHandler);
从那里我可以获取图像平面(Y、U 和 V),获取它们的 ByteBuffer 对象并将它们传递给我的本机函数。这发生在 mOnImageAvailableListener
:
Image image = reader.acquireLatestImage();
Image.Plane[] planes = image.getPlanes();
Image.Plane YPlane = planes[0];
Image.Plane UPlane = planes[1];
Image.Plane VPlane = planes[2];
ByteBuffer YPlaneBuffer = YPlane.getBuffer();
ByteBuffer UPlaneBuffer = UPlane.getBuffer();
ByteBuffer VPlaneBuffer = VPlane.getBuffer();
myNativeMethod(YPlaneBuffer, UPlaneBuffer, VPlaneBuffer, w, h);
image.close();
在本机方面,我能够从缓冲区获取数据指针,从数据创建 cv::Mat
并执行图像处理。
现在下一步是显示我处理过的输出,但我不确定如何显示我处理过的图像。任何帮助将不胜感激。
一般来说,您需要将处理后的图像数据发送到Android视图。
最高效的选择是获取要绘制到的 android.view.Surface 对象 - 您可以从 SurfaceView(通过 SurfaceHolder)或 TextureView(通过 SurfaceTexture)获取对象。然后你可以通过 JNI 将 Surface 传递给你的本地代码,并在那里使用 NDK 方法:
- ANativeWindow_fromSurface 获取 ANativeWindow
- 设置输出缓冲区大小和格式的各种ANativeWindow methods,然后将处理后的数据绘制到其中。
使用 setBuffersGeometry() 配置输出大小,然后使用 lock() 获取 ANativeWindow_Buffer。将图像数据写入 ANativeWindow_Buffer.bits,然后使用 unlockAndPost() 发送缓冲区。
一般来说,您应该坚持使用 RGBA_8888 作为最兼容的格式;从技术上讲,只有它和其他两个 RGB 变体得到官方支持。因此,如果您处理的图像是 YUV 格式,则需要先将其转换为 RGBA。
您还需要确保输出视图的纵横比与您设置的尺寸相匹配;默认情况下,Android 的视图只会将这些内部缓冲区缩放到输出视图的大小,可能会在此过程中拉伸它。
您也可以将格式设置为 Android 的内部 YUV 格式之一,但这不能保证有效!
我已经尝试过 ANativeWindow 方法,但设置起来很麻烦,而且我还没有设法正确设置。最后我只是放弃并导入了 OpenCV4Android 库,它通过在幕后将相机数据转换为 RGBA Mat 来简化事情。
我正在尝试创建一个实时处理相机图像并将其显示在屏幕上的应用程序。我正在使用 camera2 API。我创建了一个本地库来使用 OpenCV 处理图像。
到目前为止,我已经成功地设置了一个 ImageReader,它可以像这样以 YUV_420_888 格式接收图像。
mImageReader = ImageReader.newInstance(
mPreviewSize.getWidth(),
mPreviewSize.getHeight(),
ImageFormat.YUV_420_888,
4);
mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mImageReaderHandler);
从那里我可以获取图像平面(Y、U 和 V),获取它们的 ByteBuffer 对象并将它们传递给我的本机函数。这发生在 mOnImageAvailableListener
:
Image image = reader.acquireLatestImage();
Image.Plane[] planes = image.getPlanes();
Image.Plane YPlane = planes[0];
Image.Plane UPlane = planes[1];
Image.Plane VPlane = planes[2];
ByteBuffer YPlaneBuffer = YPlane.getBuffer();
ByteBuffer UPlaneBuffer = UPlane.getBuffer();
ByteBuffer VPlaneBuffer = VPlane.getBuffer();
myNativeMethod(YPlaneBuffer, UPlaneBuffer, VPlaneBuffer, w, h);
image.close();
在本机方面,我能够从缓冲区获取数据指针,从数据创建 cv::Mat
并执行图像处理。
现在下一步是显示我处理过的输出,但我不确定如何显示我处理过的图像。任何帮助将不胜感激。
一般来说,您需要将处理后的图像数据发送到Android视图。
最高效的选择是获取要绘制到的 android.view.Surface 对象 - 您可以从 SurfaceView(通过 SurfaceHolder)或 TextureView(通过 SurfaceTexture)获取对象。然后你可以通过 JNI 将 Surface 传递给你的本地代码,并在那里使用 NDK 方法:
- ANativeWindow_fromSurface 获取 ANativeWindow
- 设置输出缓冲区大小和格式的各种ANativeWindow methods,然后将处理后的数据绘制到其中。
使用 setBuffersGeometry() 配置输出大小,然后使用 lock() 获取 ANativeWindow_Buffer。将图像数据写入 ANativeWindow_Buffer.bits,然后使用 unlockAndPost() 发送缓冲区。
一般来说,您应该坚持使用 RGBA_8888 作为最兼容的格式;从技术上讲,只有它和其他两个 RGB 变体得到官方支持。因此,如果您处理的图像是 YUV 格式,则需要先将其转换为 RGBA。
您还需要确保输出视图的纵横比与您设置的尺寸相匹配;默认情况下,Android 的视图只会将这些内部缓冲区缩放到输出视图的大小,可能会在此过程中拉伸它。
您也可以将格式设置为 Android 的内部 YUV 格式之一,但这不能保证有效!
我已经尝试过 ANativeWindow 方法,但设置起来很麻烦,而且我还没有设法正确设置。最后我只是放弃并导入了 OpenCV4Android 库,它通过在幕后将相机数据转换为 RGBA Mat 来简化事情。