Android Camera2 API显示已处理的预览图像

时间:2015-09-22 19:32:55

标签: android android-camera

New Camera 2 API与旧版本有很大不同。显示操纵的相机帧到管道的用户部分让我感到困惑。我知道Camera preview image data processing with Android L and Camera2 API有很好的解释,但显示帧仍然不清楚。我的问题是在一些处理过程中在ImageReaders回调函数中显示帧的方式是什么,同时保持Camera2 api管道的效率和速度?

示例流程:

camera.add_target(imagereader.getsurface) - >在图像读取器上回调做一些处理 - > (在屏幕上显示已处理的图像?)

解决方法构思:每次处理新帧时,都会将位图发送到imageview。

2 个答案:

答案 0 :(得分:15)

澄清问题后编辑;底部的原始答案

取决于您处理的位置。

如果您正在使用RenderScript,则可以将Surface从SurfaceView或TextureView连接到分配(使用setSurface),然后将处理后的输出写入该分配并使用Allocation.ioSend将其发送出去()。 HDR Viewfinder demo使用此方法。

如果您正在进行基于EGL着色器的处理,则可以使用eglCreateWindowSurface将Surface连接到EGLSurface,并将Surface作为native_window参数。然后你可以将最终输出渲染到EGLSurface,当你调用eglSwapBuffers时,缓冲区将被发送到屏幕。

如果您正在进行原生处理,可以使用NDK ANativeWindow methods写入从Java传递的Surface和convert到ANativeWindow。

如果你正在进行Java级处理,那真的很慢,你可能不想这样做。但是可以使用新的Android M ImageWriter类,或者每帧将纹理上传到EGL。

或者如您所说,每帧都绘制一个ImageView,但这样会很慢。

原始答案:

如果要捕获JPEG图像,只需将ByteBuffer的内容从Image.getPlanes()[0].getBuffer()复制到byte[],然后使用BitmapFactory.decodeByteArray将其转换为位图。

如果您正在捕获YUV_420_888图像,那么您需要将自己的转换代码从3平面YCbCr 4:2:0格式编写为可以显示的内容,例如RGB []的RGB值来创建位图从;遗憾的是,还没有一个方便的API。

如果您正在捕获RAW_SENSOR图像(拜耳模式未处理的传感器数据),那么您需要进行大量图像处理或只需保存DNG。

答案 1 :(得分:1)

我也有同样的需求,并希望对演示进行快速而肮脏的操作。我并不担心最终产品的高效处理。这可以使用以下 java 解决方案轻松实现。

我将camera2预览连接到TextureView的原始代码被注释掉并替换为ImageReader的表面:

    // Get the surface of the TextureView on the layout
    //SurfaceTexture texture = mTextureView.getSurfaceTexture();
    //if (null == texture) {
    //    return;
    //}
    //texture.setDefaultBufferSize(mPreviewWidth, mPreviewHeight);
    //Surface surface = new Surface(texture);

    // Capture the preview to the memory reader instead of a UI element
    mPreviewReader = ImageReader.newInstance(mPreviewWidth, mPreviewHeight, ImageFormat.JPEG, 1);
    Surface surface = mPreviewReader.getSurface();

    // This part stays the same regardless of where we render
    mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
    mCaptureRequestBuilder.addTarget(surface);
    mCameraDevice.createCaptureSession(...

然后我为图像注册了一个监听器:

mPreviewReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
    @Override
    public void onImageAvailable(ImageReader reader) {
        Image image = reader.acquireLatestImage();
        if (image != null) {
            Image.Plane plane = image.getPlanes()[0];
            ByteBuffer buffer = plane.getBuffer();
            byte[] bytes = new byte[buffer.capacity()];
            buffer.get(bytes);
            Bitmap preview = BitmapFactory.decodeByteArray(bytes, 0, buffer.capacity());
            image.close();
            if(preview != null ) {
                // This gets the canvas for the same mTextureView we would have connected to the
                // Camera2 preview directly above.
                Canvas canvas = mTextureView.lockCanvas();
                if (canvas != null) {
                    float[] colorTransform = {
                            0, 0, 0, 0, 0,
                            .35f, .45f, .25f, 0, 0,
                            0, 0, 0, 0, 0,
                            0, 0, 0, 1, 0};
                    ColorMatrix colorMatrix = new ColorMatrix();
                    colorMatrix.set(colorTransform); //Apply the monochrome green
                    ColorMatrixColorFilter colorFilter = new ColorMatrixColorFilter(colorMatrix);
                    Paint paint = new Paint();
                    paint.setColorFilter(colorFilter);
                    canvas.drawBitmap(preview, 0, 0, paint);
                    mTextureView.unlockCanvasAndPost(canvas);
                }
            }
        }
    }
}, mBackgroundPreviewHandler);