Как сделать снимок, где все настройки установлены вручную, включая вспышку, не пропуская изображение, содержащее полную вспышку?

#android #kotlin #android-camerax

#Android #kotlin #android-camerax

Вопрос:

Я использовал последнюю программу Camera2Basic sample program в качестве источника для своих испытаний:

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

В основном я настроил CaptureRequest перед вызовом функции capture() в функции takePhoto () следующим образом:

     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.

Ответ №1:

Длительное время экспозиции в сочетании со вспышкой, по-видимому, является основной проблемой, и когда результаты не настолько хороши, это означает, что время вашего пресета не так хорошо. Вам придется оптимизировать продолжительность экспозиции в зависимости от времени вспышки (просто проверьте EXIF некоторых фотографий для примера значений). Вы могли бы измерить яркость с помощью ImageAnalysis.Analyzer (это было удалено из примера приложения, но в старых версиях все еще есть пример). И я пробовал использовать приложение Motorola Camera по умолчанию; там также кажется, что фотография сделана вскоре после вспышки, когда яркость уже уменьшается (чтобы избежать ослепительно яркого). Это CaptureState.PRECAPTURE то место, где вы выключаете вспышку. По умолчанию используется двухступенчатая перепрошивка, и это может дать лучшие результаты.

Если вы хотите, чтобы изображение было ослепительно ярким (даже если это обычно нежелательно), вы могли бы сначала включить фонарик, чтобы изображение снова выключилось (я использую что-то подобное, но только для сканирования штрих-кода). Это, по крайней мере, предотвратило бы любые проблемы с экспозицией / синхронизацией вспышки.

Когда измененные значения не представлены в EXIF, вам нужно будет использовать ExifInterface , чтобы обновить их (есть пример, который обновляет ориентацию, но можно обновить любое значение).