使用Camera2 API的图片非常暗

oma*_*lak 12 api camera android image android-camera

我正在使用Android,而我正在尝试捕获图片而不显示任何预览.我试着通过上课来简化这个过程.它工作但所有的图片都非常黑暗.这是我的班级:

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();}
}
Run Code Online (Sandbox Code Playgroud)

然后我在我的Activity中调用Cam对象:

Cam cam = new Cam(MainActivity.this);
cam.takePicture(Cam.BACK, "/sdcard/pic.jpg");
Run Code Online (Sandbox Code Playgroud)

当图片可用时,监听器会阻止MainActivity,但我删除了代码以清除一点.

我不知道我做错了什么,照片真的很黑.也许是旗帜或其他......任何帮助将不胜感激.

编辑: 工人阶级:https://github.com/omaflak/Android-Camera2-Library/blob/master/ezcam/src/main/java/me/aflak/ezcam/EZCam.java

示例:https://github.com/omaflak/Android-Camera2-Library/blob/master/app/src/main/java/me/aflak/libraries/MainActivity.java

Edd*_*ala 19

如果您发送给相机的唯一捕获请求是最终图片的捕获请求,这并不奇怪.

相机自动曝光,聚焦和白平衡程序通常需要一个或两个流缓冲器才能收敛到良好的效果.

虽然您不需要在屏幕上绘制预览,但最简单的方法是首先运行针对虚拟SurfaceTexture的重复请求一两秒,然后触发JPEG捕获.您可以直接进行JPEG捕获,但JPEG捕获速度很慢,因此您需要更长的时间进行收敛(此外,相对于典型的预览,相机实现更有可能出现重复JPEG捕获和获得良好曝光的错误) .

因此,使用随机纹理ID参数创建一个虚拟SurfaceTexture:

private SurfaceTexture mDummyPreview = new SurfaceTexture(1);
private Surface mDummySurface = new Surface(mDummyPreview);
Run Code Online (Sandbox Code Playgroud)

并在会话配置中包含Surface.配置会话后,创建一个以虚拟预览为目标的预览请求,并在N个捕获结果进入后,提交所需JPEG的捕获请求.你想要尝试N,但可能~30帧就足够了.

请注意,您仍然没有处理:

  • 锁定自动对焦以确保JPEG的清晰图像
  • 如果要允许闪光灯使用,请运行AE预捕获以允许闪光测光
  • 有一些方法让用户知道他们将捕获什么,因为没有预览,他们无法将设备瞄准任何东西.

AF锁定和预捕获触发序列包含在Camera2Basic示例中:https://github.com/googlesamples/android-Camera2Basic,因此您可以查看它们的作用.

  • 对不起,我改变了我的SO账号,没看到你的留言.我为它创建了库,检查代码:[GITHUB](https://github.com/omaflak/Android-Camera2-Library/blob/master/ezcam/src/main/java/me/aflak/ezcam/EZCam的.java) (3认同)