我正在实施一个应用程序,它使用来自相机的实时图像进行实时图像处理。使用现已弃用的android.hardware.Camera,它有限制地工作;提高灵活性和性能我想使用新的android.hardware.camera2 API。然而,我无法获取原始图像数据进行处理。这是三星Galaxy S5。 (不幸的是,我没有其他Lollipop设备可以在其他硬件上进行测试。)
我得到了整体框架(灵感来自于' HdrViewFinder'和Camera2Basic'样本),并且通过SurfaceTexture和GLSurfaceView在屏幕上绘制实时图像。但是,我还需要访问图像数据(灰度级很好,至少目前为止),以进行自定义图像处理。根据{{3}}的文档,直接获取图像数据的推荐曲面是StreamConfigurationMap.isOutputSupportedFor(class)(正确吗?)。
所以我将捕获请求设置为:
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();
...应支持以下ImageFormats:NV21,JPEG,YV12,YUV_420_888。我已尝试全部(插入&#39;格式&#39;上面),都支持根据getOutputSizes(format)
设置的分辨率,但没有一个能够提供所需的结果:
我在这里缺少什么?是什么导致图像被翻转和压扁?如何获得几何正确的灰度缓冲区?我应该使用不同类型的表面(而不是ImageReader)吗?
任何提示都表示赞赏。
答案 0 :(得分:5)
我找到了一个解释(虽然不一定是令人满意的解决方案):事实证明传感器阵列的宽高比是16:9(通过mCameraInfo.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
找到)。
至少在请求YV12 / YUV_420_888时,拖缆似乎没有以任何方式裁剪图像,而是非均匀地缩放图像,以达到所请求的帧尺寸。在请求16:9格式时,图像具有正确的比例(不幸的是,其中只有两个高分辨率格式)。对我来说似乎有点奇怪 - 在请求JPEG,或使用等效的旧相机API函数或静止图像时似乎不会发生这种情况;而且我不确定非均匀缩放的帧会有什么用处。
我觉得这不是一个真正令人满意的解决方案,因为这意味着你不能依赖输出格式列表,而是必须首先找到传感器大小,找到具有相同宽高比的格式,然后下采样想象自己(根据需要)......
我不知道这是否是这里的预期结果或S5的“特征”。评论或建议仍然受到欢迎。
答案 1 :(得分:0)
我遇到了同样的问题并找到了解决方案。 问题的第一部分是设置表面缓冲区的大小:
// 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();
您可以使用这些值来微调问题的解决方案。