来自 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 给出了想要的结果:
- NV21:ImageReader.newInstance 抛出 java.lang.IllegalArgumentException:不支持 NV21 格式
- JPEG:这确实有效,但实时应用程序对每一帧进行 JPEG 编码和解码似乎没有意义...
- YV12 和 YUV_420_888:这是最奇怪的结果——我可以看到得到灰度图像,但它是 垂直翻转(是的,翻转,没有旋转!) 并且显着 squished(显着水平缩放,但不是垂直缩放)。
我在这里错过了什么?是什么导致图像被翻转和挤压?如何获得几何正确的灰度缓冲区?我应该使用不同类型的表面(而不是 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();
您可以尝试使用这些值来微调您的问题的解决方案。
我正在实现一个应用程序,该应用程序对来自相机的实时图像使用实时图像处理。它正在使用现已弃用的 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 给出了想要的结果:
- NV21:ImageReader.newInstance 抛出 java.lang.IllegalArgumentException:不支持 NV21 格式
- JPEG:这确实有效,但实时应用程序对每一帧进行 JPEG 编码和解码似乎没有意义...
- YV12 和 YUV_420_888:这是最奇怪的结果——我可以看到得到灰度图像,但它是 垂直翻转(是的,翻转,没有旋转!) 并且显着 squished(显着水平缩放,但不是垂直缩放)。
我在这里错过了什么?是什么导致图像被翻转和挤压?如何获得几何正确的灰度缓冲区?我应该使用不同类型的表面(而不是 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();
您可以尝试使用这些值来微调您的问题的解决方案。