[英]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){
}
我从我用来显示相机图像的GLSurfaceView
的onDrawFrame
获取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();
}
});
capturedImage
、 buffer
和bytes
都不等于 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.