用摄像机2 API的图片是很黑 [英] Pictures with Camera2 API are really dark

查看:267
本文介绍了用摄像机2 API的图片是很黑的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在对Android和我试图拍摄一张照片,而不显示任何preVIEW。我试图通过一个类来简化这个过程。它的工作,但所有的照片都是真的黑了。
这里是我的类:

I'm working on Android and I'm trying to capture a picture without displaying any preview. I tried to simplify the process by making a class. It's working but all the pictures are really really dark. Here is my class :

public class Cam {
private Context context;
private CameraManager manager;
private CameraDevice camera;
private CameraCaptureSession session;
private ImageReader reader;
public static String FRONT="-1";
public static String BACK="-1";
private boolean available=true;
private String filepath;

private static final String NO_CAM = "No camera found on device!";
private static final String ERR_CONFIGURE = "Failed configuring session";
private static final String ERR_OPEN = "Can't open the camera";
private static final String CAM_DISCONNECT = "Camera disconnected";
private static final String FILE_EXIST = "File already exist";

private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
static {
    ORIENTATIONS.append(Surface.ROTATION_0, 90);
    ORIENTATIONS.append(Surface.ROTATION_90, 0);
    ORIENTATIONS.append(Surface.ROTATION_180, 270);
    ORIENTATIONS.append(Surface.ROTATION_270, 180);
}

public Cam(Context context) throws CameraAccessException {
    this.context = context;
    this.manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
    String ids[] = manager.getCameraIdList();
    if(ids.length==2){
        BACK=ids[0];
        FRONT=ids[1];
    }
    else if(ids.length==1){
        BACK=ids[0];
    }
    else{
        available=false;
        throw new CameraAccessException(-1, NO_CAM);
    }
}

public void takePicture(String camId, String filepath) throws CameraAccessException {
    if(available){
        this.filepath=filepath;
        StreamConfigurationMap map = manager.getCameraCharacteristics(camId).get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
        Size largest = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)), new CompareSizesByArea());
        reader=ImageReader.newInstance(largest.getWidth(), largest.getHeight(), ImageFormat.JPEG, 1);
        reader.setOnImageAvailableListener(imageListener, null);
        manager.openCamera(camId, cameraStateCallback, null);
    }
    else
        throwError(NO_CAM);
}

private CameraDevice.StateCallback cameraStateCallback = new CameraDevice.StateCallback() {
    @Override
    public void onOpened(CameraDevice camera) {
        Cam.this.camera=camera;
        try {
            camera.createCaptureSession(Collections.singletonList(reader.getSurface()), sessionStateCallback, null);
        } catch (CameraAccessException e) {
            throwError(e.getMessage());
        }
    }

    @Override
    public void onDisconnected(CameraDevice camera) {
        throwError(CAM_DISCONNECT);
    }

    @Override
    public void onError(CameraDevice camera, int error) {
        throwError(ERR_OPEN);
    }
};

private CameraCaptureSession.StateCallback sessionStateCallback = new CameraCaptureSession.StateCallback() {
    @Override
    public void onConfigured(CameraCaptureSession session) {
        Cam.this.session=session;
        try {
            CaptureRequest.Builder request = camera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            request.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            request.addTarget(reader.getSurface());
            int rotation = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
            request.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
            session.capture(request.build(), captureCallback, null);
        } catch (CameraAccessException e) {
            throwError(e.getMessage());
        }
    }

    @Override
    public void onConfigureFailed(CameraCaptureSession session) {
        throwError(ERR_CONFIGURE);
    }
};

private CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {
    @Override
    public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) {
        super.onCaptureFailed(session, request, failure);
        throwError(failure.toString());
    }
};

private ImageReader.OnImageAvailableListener imageListener = new ImageReader.OnImageAvailableListener() {
    @Override
    public void onImageAvailable(ImageReader reader) {
        Image image = reader.acquireLatestImage();
        try {
            File file = saveImage(image);
            // Send file via a listener
            closeCamera();
        } catch (IOException e) {
            throwError(e.getMessage());
        }
        reader.close();
    }
};

private File saveImage(Image image) throws IOException {
    File file = new File(filepath);
    if (file.exists()) {
        throwError(FILE_EXIST);
        return null;
    }
    else {
        ByteBuffer buffer = image.getPlanes()[0].getBuffer();
        byte[] bytes = new byte[buffer.remaining()];
        buffer.get(bytes);
        FileOutputStream output = new FileOutputStream(file);
        output.write(bytes);
        image.close();
        output.close();
        return file;
    }
}

static class CompareSizesByArea implements Comparator<Size> {
    @Override
    public int compare(Size lhs, Size rhs) {
        return Long.signum((long) lhs.getWidth() * lhs.getHeight() - (long) rhs.getWidth() * rhs.getHeight());
    }
}

private void closeCamera(){
    if(session!=null) {session.close();}
    if(reader!=null) {reader.close();}
    if(camera!=null) {camera.close();}
}

然后我打电话凸轮对象在我的活动:

Then I call the Cam object in my Activity :

Cam cam = new Cam(MainActivity.this);
cam.takePicture(Cam.BACK, "/sdcard/pic.jpg");

一个监听器prevent当图片可用,但我去掉了code清除位在MainActivity。

A listener prevent the MainActivity when the picture is available, but I removed the code to clear a bit.

我不知道我做错了,拍出来的照片很黑。也许一个标志或东西...任何帮助将AP preciated。

I don't know what I am doing wrong, the pictures are really dark. Maybe a flag or something... Any help will be appreciated.

推荐答案

如果您发送到相机的唯一捕获请求是一个最后的画面,这是不足为奇的。

If the only capture request you send to the camera is the one for the final picture, this is not surprising.

相机自动曝光,对焦和白平衡程序,通常需要一两秒钟流缓冲区他们收敛到很好的效果了。

The camera automatic exposure, focus, and white balance routines generally need a second or two of streaming buffers before they converge to good results.

虽然你并不需要在屏幕上绘制preVIEW,这里最简单的方法就是先运行一个重复请求为目标一两秒钟一个虚拟的表面纹理,然后关火JPEG捕获。
你可以只流了JPEG拍摄,但JPEG抓拍速度很慢,所以你需要的收敛时间较长(加上它更可能是相机的实现有一个bug反复JPEG捕捉和获得良好的曝光,不是一个典型的preVIEW)。

While you don't need to draw preview on screen, the simplest method here is to first run a repeating request targeting a dummy SurfaceTexture for a second or two, and then fire off the JPEG capture. You could just stream the JPEG capture, but JPEG capture is slow, so you'll need a longer time for convergence (plus it's more likely a camera implementation has a bug with repeated JPEG capture and getting good exposure, than with a typical preview).

所以,创建具有随机纹理ID参数虚表面纹理:

So, create a dummy SurfaceTexture with a random texture ID argument:

private SurfaceTexture mDummyPreview = new SurfaceTexture(1);
private Surface mDummySurface = new Surface(mDummyPreview);

和包括您的会话配置中的表面。一旦会话配置,创建针对虚拟preVIEW一个preVIEW请求,并在N捕获结果已经出来的,提交所需的JPEG捕获请求。你会想用N实验,但可能〜30帧就够了。

and include the Surface in your session configuration. Once the session is configured, create a preview request that targets the dummy preview, and after N capture results have come in, submit the capture request for the JPEG you want. You'll want to experiment with N, but probably ~30 frames is enough.

请注意,你还没有处理:

Note that you're still not dealing with:


  • AF锁定,以确保清晰的影像为您的JPEG

  • 运行AE precapture允许闪光测光,如果你想允许使用闪光灯

  • 有一些办法让用户知道他们会被捕捉,因为没有preVIEW,他们无法瞄准任何设备非常好。

自动对焦锁定和precapture触发序列这里包括Camera2Basic样本: https://开头的github .COM / googlesamples / Android的Camera2Basic 的,所以你可以看看它们能干什么。

The AF lock and precapture trigger sequences are included in Camera2Basic sample here: https://github.com/googlesamples/android-Camera2Basic, so you can take a look at what those do.

这篇关于用摄像机2 API的图片是很黑的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆