Как получить растровое изображение из session.update () в ARCore [Android Studio] - PullRequest
0 голосов
/ 28 августа 2018

Я пытаюсь получить растровое изображение из текущего кадра моей ARSession с ARCore. Но это всегда равно нулю. Я уже давно ищу в Интернете, но не могу понять, что я делаю неправильно.

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){

}

Я получаю mFrame от onDrawFrame моего GLSurfaceView, который я использую для отображения изображения с камеры. Все работает отлично, за исключением того, что мое растровое изображение равно нулю.

Я использую кнопку, так что используется только один кадр, как показано ниже:

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 все не равны нулю.

Возможно, что-то не так с mFrame.acquireCameraImage()?

Большое спасибо

Ответы [ 2 ]

0 голосов
/ 21 марта 2019

Я не знаю, есть ли еще кто-нибудь, кто ищет ответ, но это мой код.

        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);

0 голосов
/ 28 августа 2018

Возможно, что-то не так с mFrame.acquireCameraImage ()?

Нет, mFrame.acquireCameraImage() работает как задумано.

Но оно всегда равно нулю

Растровое изображение всегда будет равно нулю, поскольку фабрика растровых изображений не понимает данные изображения, которые передаются ей.

Метод mFrame.acquireCameraImage() отвечает объектом типа Image в формате YUV или YCbCr. Эти типы изображений имеют 3 плоскости, что очень хорошо объясняется здесь здесь . ByteArray, содержащийся в этих плоскостях, может быть прочитан непосредственно CPU / GPU в коде native. BitmapFactory не может прочитать данные этого типа. Следовательно, вам нужно преобразовать это изображение YUV во что-то другое.

Для этого вам нужно использовать класс YuvImage, чтобы создать экземпляр YUV, а затем преобразовать его в JPEG, используя метод compressToJpeg. Получив byteArray, вы можете просто сделать то, что делаете выше. Используйте BitmapFactory, чтобы преобразовать его в растровое изображение и добавить его в 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)

Это просто грубый код. Возможно, у него есть возможности для улучшения. Также см. здесь .

...