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并执行图像处理。
现在下一步是显示我的处理输出,但我不确定如何显示我处理过的图像。 任何帮助将不胜感激。
I'm trying to create an app that processes camera images in real time and displays them on screen. I'm using the camera2 API. I have created a native library to process the images using OpenCV.
So far I have managed to set up an ImageReader that receives images in YUV_420_888 format like this.
mImageReader = ImageReader.newInstance(
mPreviewSize.getWidth(),
mPreviewSize.getHeight(),
ImageFormat.YUV_420_888,
4);
mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mImageReaderHandler);
From there I'm able to get the image planes (Y, U and V), get their ByteBuffer objects and pass them to my native function. This happens in the 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();
On the native side I'm able to get the data pointers from the buffers, create a cv::Mat from the data and perform the image processing.
Now the next step would be to show my processed output, but I'm unsure how to show my processed image. Any help would be greatly appreciated.
原文:https://stackoverflow.com/questions/42450556
更新时间:2020-02-18 18:29
最满意答案
一般来说,您需要将处理后的图像数据发送到Android视图。
最高效的选项是获取一个android.view.Surface对象 - 你可以从SurfaceView(通过SurfaceHolder)或TextureView(通过SurfaceTexture)获得一个。 然后你可以通过JNI将Surface传递给你的本机代码,并使用NDK方法:
各种ANativeWindow方法设置输出缓冲区大小和格式,然后将处理后的数据绘制到其中。
使用setBuffersGeometry()配置输出大小,然后使用lock()获取ANativeWindow_Buffer。 将您的图像数据写入ANativeWindow_Buffer.bits,然后使用unlockAndPost()发送缓冲区。
通常,您应该坚持使用RGBA_8888作为最兼容的格式; 从技术上讲,只有它和其他两种RGB变体才得到官方支持。 因此,如果您处理的图像是YUV,则需要先将其转换为RGBA。
您还需要确保输出视图的宽高比与您设置的尺寸的宽高比相匹配; 默认情况下,Android的Views只会将这些内部缓冲区缩放到输出View的大小,可能会在此过程中拉伸它。
您还可以将格式设置为Android的内部YUV格式之一,但这不能保证正常工作!
I've tried the ANativeWindow approach, but it's a pain to set up and I haven't managed to do it correctly. In the end I just gave up and imported OpenCV4Android library which simplifies things by converting camera data to a RGBA Mat behind the scenes.
2017-03-02
相关问答
其实,检查API版本21+将工作。 camera2 API(包括CameraManager是系统的一部分,不依赖于硬件。 因此,您可以随时向CameraManager询问CameraDevice的列表,然后您可以单独进行查询。 但是,我认为你实际上的意思是“我怎么知道我是否可以使用camera2 API手动设置摄影参数?”,这取决于你所拥有的设备。 这取决于你需要什么样的控制,但你需要的信息可以通过获取REQUEST_AVAILABLE_CAPABILITIES 元数据字段来获得。 提示:寻找MA
...
因为您的问题我开始阅读并深入研究,我相信这就是它的工作方式。 根据文档( 链接 )说: 每个请求将生成一个CaptureResult并为一个或多个目标曲面生成新帧 注意它说“框架s ”。 复数。 说我相信你应该只考虑来自onCaptureCompleted回调的最后一帧。 since your question I started reading and digging into it, and I believe that's the way it works. As per doc (link
...
选项A:使用这两种API 步骤1:将您的compileSdkVersion设置为21或更高。 理想情况下,将其设置为25,以获得最新版本的Android。 步骤#2:为两个API编写代码。 步骤#3:当设备运行Android 5.0+时,只调用使用android.hardware.camera2类的代码: if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP) {
// use camera2
}
else {
// use Cam
...
Camera2不会自动播放任何声音。 相反,相机使用应用程序需要遵循无论哪个国家的快门声音强制执行的期望。MediaActionSound可用于此目的。 Camera2 does not play any sounds automatically. Instead, the camera-using application is required to follow the expectations on shutter sound enforcement in whatever country
...
您需要声明在创建CameraCaptureSession时可能要将图像数据发送到的所有输出Surface 。 这只是框架设计的方式。 无论何时创建CaptureRequest ,都可以添加(列表)目标输出Surface 。 这是来自捕获帧的图像数据将去的地方 - 它可能是与用于显示的TextureView关联的Surface ,或者用于保存的ImageReader ,或者用于处理的Allocation等。( Surface实际上只是一个缓冲区,可以获取摄像机输出的数据,缓冲区关联的对象类型决定了如
...
假设您正在谈论在捕获时发送到ImageReader或SurfaceTexture的帧(如在无处不在的camera2basic示例中),诀窍是比较标识图像的唯一时间戳。 将TotalCaptureResult保存在TotalCaptureResult的onCaptureComplete(...)调用中可用的onCaptureComplete(...) 。 然后,当通过ImageReader.OnAvailableListener或SurfaceTexture.OnFrameAvailableList
...
正如yakobom所提到的,您正在尝试将YUV_420_888图像直接复制到RGBA_8888目的地(如果您尚未更改,则默认为默认值)。 这不仅仅适用于memcpy。 你需要实际转换数据,你需要确保你不要复制太多 - 示例代码你有副本width*height*4字节,而YUV_420_888图像只占用stride*height*1.5字节(粗略) 。 因此,当您复制时,您正在缓冲区的末尾运行。 您还必须考虑Java级别提供的步幅以正确索引到缓冲区。 这个来自Microsoft的链接有一个有用的图表
...
一般来说,您需要将处理后的图像数据发送到Android视图。 最高效的选项是获取一个android.view.Surface对象 - 你可以从SurfaceView(通过SurfaceHolder)或TextureView(通过SurfaceTexture)获得一个。 然后你可以通过JNI将Surface传递给你的本机代码,并使用NDK方法: ANativeWindow_fromSurface获取ANativeWindow 各种ANativeWindow方法设置输出缓冲区大小和格式,然后将处理后的
...
回复你的评论,但把它变成一个正确的答案: 如果您从Samsung dev查看这些幻灯片。 幻灯片#22上的会议显示了camera2模型。 如您所见,有几个队列: 待处理请求队列 在飞行捕获队列中 将图像队列输出到Surface,显示摄像头预览 以及对onCaptureComplete的回调 这解释了为什么第一次捕获很慢,但在突发模式下,下一个图像速度非常快。 请求和处理排队,第一个需要300毫秒才能一直返回到回调,但下一个已经“正好在它后面”。 如果你对新的API感兴趣(谁也不会,相机2很棒),你
...
在支持摄像机状态输出的设备上,这些值都可以通过CaptureResult获得, CaptureResult是通过onCaptureCompleted为每个帧生成的 。 支持READ_SENSOR_SETTINGS功能的所有设备都将具有必要的值,例如SENSOR_SENSITIVITY 。 On devices that support camera status output, those values are all available via CaptureResult, which is p
...