来自 Android camera2 API 的图像数据在 Galaxy S5 上被翻转和挤压

Image data from Android camera2 API flipped & squished on Galaxy S5

我正在实现一个应用程序,该应用程序对来自相机的实时图像使用实时图像处理。它正在使用现已弃用的 android.hardware.Camera;为了提高灵活性和性能,我想使用新的 android.hardware.camera2 API。但是,我无法获取要处理的原始图像数据。这是在三星 Galaxy S5 上。 (不幸的是,我手边没有另一个 Lollipop 设备可以在其他硬件上进行测试)。

我得到了整个框架(灵感来自 'HdrViewFinder' 和 'Camera2Basic' 示例),实时图像通过 SurfaceTexture 和 GLSurfaceView 在屏幕上绘制。但是,我还需要访问图像数据(仅灰度就可以,至少目前如此)以进行自定义图像处理。根据 StreamConfigurationMap.isOutputSupportedFor(class), the recommended surface to obtain image data directly would be ImageReader 的文档(正确?)。

所以我将捕获请求设置为:

mSurfaceTexture.setDefaultBufferSize(640, 480);
mSurface = new Surface(surfaceTexture);
...
mImageReader = ImageReader.newInstance(640, 480, format, 2);
...
List<Surface> surfaces = new ArrayList<Surface>();
surfaces.add(mSurface);
surfaces.add(mImageReader.getSurface());
...
mCameraDevice.createCaptureSession(surfaces, mCameraSessionListener, mCameraHandler);

在 ImageReader 的 onImageAvailable 回调中,我按如下方式访问数据:

Image img = reader.acquireLatestImage();
ByteBuffer grayscalePixelsDirectByteBuffer = img.getPlanes()[0].getBuffer();

...但是虽然(如前所述)实时图像预览正在运行,但我在此处获取的数据(或获取数据的方式)存在问题。根据

mCameraInfo.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputFormats();

...应支持以下图像格式:NV21、JPEG、YV12、YUV_420_888。我已经尝试了所有(插入上面的 'format'),都支持根据 getOutputSizes(format) 设置的分辨率,但是 none 给出了想要的结果:

我在这里错过了什么?是什么导致图像被翻转和挤压?如何获得几何正确的灰度缓冲区?我应该使用不同类型的表面(而不是 ImageReader)吗?

感谢任何提示。

我找到了一个解释(虽然不一定是一个令人满意的解决方案):原来传感器阵列的纵横比是16:9(通过mCameraInfo.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);找到)。

至少在请求 YV12/YUV_420_888 时,流媒体似乎没有以任何方式裁剪图像,而是不均匀地缩放图像以达到请求的帧大小。当请求 16:9 格式时,图像具有正确的比例(不幸的是,其中只有两个更高分辨率的格式)。对我来说似乎有点奇怪——当请求 JPEG 时,或者使用等效的旧相机 API 功能,或者对于静止图像时,它似乎没有发生;而且我不确定非均匀缩放的帧有什么用。

我觉得这不是一个真正令人满意的解决方案,因为这意味着你不能依赖输出格式列表,而是必须先找到传感器尺寸,找到具有相同纵横比的格式,然后自己对图像进行下采样(根据需要)...

我不知道这是这里的预期结果还是 S5 的 'feature'。仍然欢迎提出意见或建议。

我遇到了同样的问题并找到了解决方案。 问题的第一部分是设置表面缓冲区的大小:

    // We configure the size of default buffer to be the size of camera preview we want.
    //texture.setDefaultBufferSize(width, height);

这是图像倾斜的地方,而不是在相机中。您应该将其注释掉,然后在显示图像时设置图像放大。

            int[] rgba = new int[width*height];
            //getImage(rgba);
            nativeLoader.convertImage(width, height, data, rgba);

            Bitmap bmp = mBitmap;
            bmp.setPixels(rgba, 0, width, 0, 0, width, height);

            Canvas canvas = mTextureView.lockCanvas();

            if (canvas != null) {
                //canvas.drawBitmap(bmp, 0, 0, null );//configureTransform(width, height),  null);
                //canvas.drawBitmap(bmp, configureTransform(width, height),  null);
                canvas.drawBitmap(bmp, new Rect(0,0,320,240), new Rect(0,0, 640*2,480*2), null );

                //canvas.drawBitmap(bmp, (canvas.getWidth() - 320) / 2, (canvas.getHeight() - 240) / 2, null);

                mTextureView.unlockCanvasAndPost(canvas);
            }

            image.close();

您可以尝试使用这些值来微调您的问题的解决方案。