首页 > 解决方案 > 如何在手动设置所有设置(包括闪光灯)的情况下拍摄照片,而不会丢失包含完整闪光灯的图像?

问题描述

我使用最新的 Camera2Basic 示例程序作为我的试验源:

https://github.com/android/camera-samples.git

基本上,我在 takePhoto() 函数中调用 capture() 函数之前配置了 CaptureRequest,如下所示:

    private fun prepareCaptureRequest(captureRequest: CaptureRequest.Builder) {
    //set all needed camera settings here
    captureRequest.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_OFF)

    captureRequest.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF);
    //captureRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);
    //captureRequest.set(CaptureRequest.CONTROL_AWB_LOCK, true);
    captureRequest.set(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_OFF);
    captureRequest.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
    //captureRequest.set(CaptureRequest.CONTROL_AE_LOCK, true);
    //captureRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL);
    //captureRequest.set(CaptureRequest.NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_FAST);

    //flash
    if (mState == CaptureState.PRECAPTURE){
        //captureRequest.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
        captureRequest.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF)
    }
    if (mState == CaptureState.TAKEPICTURE) {
        //captureRequest.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_SINGLE)
        //captureRequest.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
        captureRequest.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_SINGLE)
    }

    val iso = 100
    captureRequest.set(CaptureRequest.SENSOR_SENSITIVITY, iso)

    val fractionOfASecond = 750.toLong()
    captureRequest.set(CaptureRequest.SENSOR_EXPOSURE_TIME, 1000.toLong() * 1000.toLong() * 1000.toLong() / fractionOfASecond)
    //val exposureTime = 133333.toLong()
    //captureRequest.set(CaptureRequest.SENSOR_EXPOSURE_TIME, exposureTime)

    //val characteristics = cameraManager.getCameraCharacteristics(cameraId)
    //val configs: StreamConfigurationMap? = characteristics[CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP]
    //val frameDuration = 33333333.toLong()
    //captureRequest.set(CaptureRequest.SENSOR_FRAME_DURATION, frameDuration)

    val focusDistanceCm = 20.0.toFloat()    //20cm 
    captureRequest.set(CaptureRequest.LENS_FOCUS_DISTANCE, 100.0f / focusDistanceCm)

    //captureRequest.set(CaptureRequest.COLOR_CORRECTION_MODE, CameraMetadata.COLOR_CORRECTION_MODE_FAST)
    captureRequest.set(CaptureRequest.COLOR_CORRECTION_MODE, CaptureRequest.COLOR_CORRECTION_MODE_TRANSFORM_MATRIX)
    val colorTemp = 8000.toFloat();
    val rggb = colorTemperature(colorTemp)
    //captureRequest.set(CaptureRequest.COLOR_CORRECTION_TRANSFORM, colorTransform);
    captureRequest.set(CaptureRequest.COLOR_CORRECTION_GAINS, rggb);
}

但返回的图片绝不是闪光灯最亮的图片。这是在 Google Pixel 2 设备上。因为我只拍了一张照片,所以我也不确定如何检查一些 CaptureResult 状态以找到正确的照片,因为只有一张照片。我已经在这里查看了类似问题的其他解决方案,但它们要么从未真正解决,要么在捕获预览期间以某种方式拍摄了我不想要的照片。

其他奇怪的观察是,在不同的设备上拍摄图像(也不总是在正确的时刻),但是我设置的手动值在图像的 JPEG 元数据中没有观察到。

如果需要,我可以将我的 git fork 放在 github 上。

标签: androidkotlinandroid-camerax

解决方案


长曝光时间与闪光灯相结合似乎是基本问题,当结果不是那么好时,这意味着您的预设时间不是那么好。您必须根据闪光灯的时间优化曝光时间的持续时间(只需检查一些照片的 EXIF 以获取示例值)。您可以使用 an 来测量亮度ImageAnalysis.Analyzer(这已从示例应用程序中删除,但旧版本仍有示例)。我已经尝试过使用默认的摩托罗拉相机应用程序;那里的照片似乎也是在闪光后不久拍摄的,当时亮度已经衰减(为了避免耀眼的亮光)。那是CaptureState.PRECAPTURE,您关闭闪光灯的位置。在两个阶段闪烁是相当默认的,这可能会产生更好的结果。

如果你想让它耀眼夺目(即使这通常是不希望的),你也可以先打开手电筒,图像,再次关闭手电筒(我使用类似的东西,但仅用于条形码扫描) . 这至少可以防止任何曝光/闪光时间问题​​。

当 EXIF 中未表示更改的值时,您需要使用ExifInterface, 来更新它们(有一个更新方向的示例,但可以更新任何值)。


推荐阅读