New Camera 2 API与旧版本有很大不同。显示操纵的相机帧到管道的用户部分让我感到困惑。我知道Camera preview image data processing with Android L and Camera2 API有很好的解释,但显示帧仍然不清楚。我的问题是在一些处理过程中在ImageReaders回调函数中显示帧的方式是什么,同时保持Camera2 api管道的效率和速度?
示例流程:
camera.add_target(imagereader.getsurface) - >在图像读取器上回调做一些处理 - > (在屏幕上显示已处理的图像?)
解决方法构思:每次处理新帧时,都会将位图发送到imageview。
答案 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);