Camera2-获取静止图像位图的最有效方法

时间:2018-07-14 05:46:29

标签: android bitmap android-camera2

首先要提出一个问题:知道我总是要将捕获的图像转换为autoload的情况下,使用camera2 api初始化和使用ImageReader的最有效方法是什么?

我正在玩Android camera2示例,并且一切工作都很好。但是,出于我的目的,我始终需要对捕获的静止图像执行一些后期处理,为此我需要一个Bitmap对象。目前,我正在使用Bitmap中的字节来使用BitmapFactory.decodeByteArray(...)(我在解释)。尽管这可以接受,但我仍然觉得应该有一种方法来提高性能。捕获内容以ImageReader.acquireNextImage().getPlanes()[0].getBuffer()进行编码,需要再次解码才能获得ImageFormat.Jpeg,这似乎是多余的。理想情况下,我将在Bitmap中获得它们,然后使用PixelFormat.RGB_888将其复制到位图,但是用这种格式初始化Bitmap.copyPixelsFromBuffer(...)似乎不具有可靠的设备支持。 ImageReader可能是另一种选择,但是环顾四周似乎需要跳过一些箍才能解码成YUV_420_888。有推荐的方法吗?

3 个答案:

答案 0 :(得分:1)

问题是您要优化什么。

Jpeg 无疑是所有设备支持的最简单格式。似乎将其解码为位图并不是多余的,因为将图片编码为 jpeg 通常是由某种硬件执行的。这意味着使用最小的带宽将图像从传感器传输到您的应用程序。在某些设备上,这是获得最大分辨率的唯一方法。 BitmapFactory.decodeByteArray(...)通常也由特殊的硬件解码器执行。此调用的主要问题是,由于输出位图太大,可能导致内存不足异常。因此,您会发现很多示例,这些示例做了do二次采样解码,针对必须在电话屏幕上显示位图的用例进行了调整。

如果您的设备使用 RGB_8888 支持所需的分辨率,请继续使用:这需要最少的后处理。但是,与处理 Jpeg 相比,缩小此类图像可能会占用更多的CPU资源,并且内存消耗可能会很大。无论如何,只有很少的设备支持这种格式的相机捕获。

对于 YUV_420_888 和其他 YUV 格式, 与 Jpeg 相比,其优势甚至小于 RGB

如果您需要最优质的图像,并且没有内存限制,则应该使用 RAW 图像,这些图像最近在大多数高端设备上都受支持。您将需要自己的转换算法,并且可能对不同的设备进行不同的修改,但是至少您将完全掌握图片的获取。

答案 1 :(得分:1)

过了一会儿,我现在对自己的问题有一个答案,尽管不是一个很令人满意的问题。经过深思熟虑,我尝试了以下操作:

  • 设置所需输出尺寸的ScriptIntrinsicYuvToRGB RenderScript
  • 获取已使用的输入分配的Surface,并将其设置为静态捕捉的目标表面
  • 在有新分配可用时运行此RenderScript,并将结果字节转换为Bitmap

这实际上就像一种魅力,而且速度很快。然后,我开始注意到相机的奇怪行为,这在其他设备上也发生过。事实证明,相机HAL并未真正将其识别为静止图像。这意味着(a)在这种情况下,闪光灯/曝光例程在需要时不会触发;(b)如果您在捕获自动曝光之前就启动了预捕获序列,则它将保持锁定状态,除非您设法使用{ {1}}(API> = 23)或其他一些我无法在任一设备上使用的锁定/解锁魔术。除非您对此感到满意,否则只能在不需要调整曝光的最佳照明条件下工作,否则这种方法将完全无用。

我还有一个主意,那就是设置一个AE_PRECAPTURE_TRIGGER_CANCEL输出为ImageReader并合并conversion routine from this answer以从中获取RGB像素。但是,我实际上正在使用YUV_420_888,并且那里不支持RenderScript用户脚本。我也许可以解决这个问题,但这绝非易事。

对于我的特定用例,我已经设法通过在处理的多个阶段仔细安排背景任务和对我需要的版本的子采样解码,来将JPEG解码加快到可接受的水平,因此实现这一点可能不值得我花时间任何时候很快。但是,如果有人在寻找有关如何处理类似问题的想法;这就是您可以所能做的。

答案 2 :(得分:0)

使用不同的ImageFormat更改Imagereader实例,如下所示:

ImageReader.newInstance(width, height, ImageFormat.JPEG, 1)