繁体   English   中英

如何从 ARCore [Android Studio] 中的 session.update() 获取位图

[英]How to get Bitmap from session.update() in ARCore [Android Studio]

我正在尝试使用 ARCore 从我的 ARSession 的当前帧中获取位图。 但它始终等于 null。 我已经在网上搜索了很长时间,但无法弄清楚我做错了什么。

try {
    capturedImage = mFrame.acquireCameraImage();

    ByteBuffer buffer = capturedImage.getPlanes()[0].getBuffer();

    byte[] bytes = new byte[buffer.capacity()];

    Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length,null);

    if (bitmap == null) 
        Log.e(TAG,"Bitmap was NOT initialized!");

} catch(Exception e){

}

我从我用来显示相机图像的GLSurfaceViewonDrawFrame获取mFrame 一切正常,除了我的位图等于 null。

我使用的是 Button,因此只使用了一个 Frame,如下所示:

scanButton = (Button) findViewById(R.id.scanButton);
scanButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        checkbox = false;
        if (capturedImage!=null) capturedImage.close();
            BitmapMethod();
    }
});

capturedImagebufferbytes都不等于 null。

mFrame.acquireCameraImage()可能有问题吗?

非常感谢

mFrame.acquireCameraImage() 可能有问题吗?

不, mFrame.acquireCameraImage()按预期工作。

但它总是等于 null

位图将始终等于 null,因为位图工厂不理解传递给它的图像数据。

mFrame.acquireCameraImage()方法以 YUV 格式或 YCbCr 格式的Image类型的对象进行响应。 这些类型的图像有 3 个平面, 这里有很好的解释。 这些平面中包含的ByteArray可以直接由 CPU/GPU 在native代码中读取。 BitmapFactory无法读取此类数据。 因此,您需要将此 YUV 图像转换为其他图像。

为此,您需要使用YuvImage类创建 YUV 的实例,然后使用compressToJpeg方法将其转换为 JPEG。 从中获得 byteArray 后,您可以简单地执行上面的操作。 使用BitmapFactory将其转换为 Bitmap 并将其添加到您的ImageView

注:YUV有3个平面。 从所有平面创建一个字节数组,然后将其传递给 YUV 构造函数。 虽然没有详细说明,但它看起来应该与此类似:

//The camera image received is in YUV YCbCr Format. Get buffers for each of the planes and use them to create a new bytearray defined by the size of all three buffers combined
val cameraPlaneY = cameraImage.planes[0].buffer
val cameraPlaneU = cameraImage.planes[1].buffer
val cameraPlaneV = cameraImage.planes[2].buffer

//Use the buffers to create a new byteArray that 
val compositeByteArray = ByteArray(cameraPlaneY.capacity() + cameraPlaneU.capacity() + cameraPlaneV.capacity())

cameraPlaneY.get(compositeByteArray, 0, cameraPlaneY.capacity())
cameraPlaneU.get(compositeByteArray, cameraPlaneY.capacity(), cameraPlaneU.capacity())
cameraPlaneV.get(compositeByteArray, cameraPlaneY.capacity() + cameraPlaneU.capacity(), cameraPlaneV.capacity())

val baOutputStream = ByteArrayOutputStream()
val yuvImage: YuvImage = YuvImage(compositeByteArray, ImageFormat.NV21, cameraImage.width, cameraImage.height, null)
yuvImage.compressToJpeg(Rect(0, 0, cameraImage.width, cameraImage.height), 75, baOutputStream)
val byteForBitmap = baOutputStream.toByteArray()
val bitmap = BitmapFactory.decodeByteArray(byteForBitmap, 0, byteForBitmap.size)
imageView.setImageBitmap(bitmap)

那只是一个粗略的代码。 它也许有改进的余地。 也参考这里

我也结束了重新创建与您所面临的相同情况。 我将 Image 对象设置为 Null。

经过一些研究,我发现问题出在逻辑流程中。

然后我写了下面的代码,它解决了我的问题:

我定义了以下布尔值以设置为在单击按钮时捕获当前帧:

private static boolean captureCurrentFrame = false;

我在 onClick() 函数中编写的这段代码用于获取当前帧的 RGB 和深度图像:

public void captureFrame(View view){
    Toast.makeText(getApplicationContext(),"Capturing depth and rgb photo",Toast.LENGTH_SHORT).show();
    captureCurrentFrame = true;
  }

在从 session.update() 获取帧之后,我在 onDrawFrame() 方法中编写了这一部分:

if(captureCurrentFrame) {
        RGBImage = frame.acquireCameraImage();
        DepthImage = frame.acquireDepthImage();

        Log.d("Image","Format of the RGB Image: " + RGBImage.getFormat());
        Log.d("Image","Format of the Depth Image: " + DepthImage.getFormat());

        RGBImage.close();
        DepthImage.close();

        captureCurrentFrame = false;
      }

在我的例子中得到 Null 的原因是 onClick 侦听器中的代码在通过 onDraw() 方法之前被触发,因此图像没有存储在变量中。

因此,我将逻辑转移到 onDraw() 并通过侦听器设置的布尔变量触发该流程。

我不知道是否还有人在寻找答案,但这是我的代码。

        Image image = mFrame.acquireCameraImage();
        byte[] nv21;
        // Get the three planes.
        ByteBuffer yBuffer = image.getPlanes()[0].getBuffer();
        ByteBuffer uBuffer = image.getPlanes()[1].getBuffer();
        ByteBuffer vBuffer = image.getPlanes()[2].getBuffer();

        int ySize = yBuffer.remaining();
        int uSize = uBuffer.remaining();
        int vSize = vBuffer.remaining();


        nv21 = new byte[ySize + uSize + vSize];

        //U and V are swapped
        yBuffer.get(nv21, 0, ySize);
        vBuffer.get(nv21, ySize, vSize);
        uBuffer.get(nv21, ySize + vSize, uSize);

        int width = image.getWidth();
        int height = image.getHeight();

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        YuvImage yuv = new YuvImage(nv21, ImageFormat.NV21, width, height, null);
        yuv.compressToJpeg(new Rect(0, 0, width, height), 100, out);
        byte[] byteArray = out.toByteArray();
        Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM