0

我正在开发一个需要使用固定(手动)焦点并始终使用闪光灯的 Android 相机应用程序。我遇到了一些似乎与闪光时间有关的问题。闪光灯始终闪光并始终获取图像,但有时闪光灯实际上并未照亮捕获的帧。有的画面有闪光,有的曝光过度,有的很暗;基本上它是不一致和不可预测的。

我的代码基于Camera2Basic示例。我想我已经在这里展示了所有相关部分:

我的预览请求生成器具有以下设置

mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF);
float minimumLens = mCameraCharacteristics.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE);
mPreviewRequestBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE, minimumLens);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AWB_MODE,CaptureRequest.CONTROL_AWB_MODE_OFF);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_OFF);

那么获取图片的实际序列(几乎直接来自 Camera2Basic)是:

private void takePicture() {
    runPrecaptureSequence();
}

private CameraCaptureSession.CaptureCallback mCaptureCallback = new CameraCaptureSession.CaptureCallback() {

    private void process(CaptureResult result) {
        switch (mState) {
            case STATE_PREVIEW: {
                break;
            }
            case STATE_WAITING_PRECAPTURE: {
                Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                if (aeState == null ||
                        aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
                        aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
                    mState = STATE_CAPTURE;
                }
                break;
            }

            case STATE_CAPTURE: {
                // CONTROL_AE_STATE can be null on some devices
                Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
                    mState = STATE_PICTURE_TAKEN;
                    captureStillPicture();
                }
                break;
            }
        }
    }

    @Override
    public void onCaptureProgressed(**ARGS**) {
        process(partialResult);
    }

    @Override
    public void onCaptureCompleted(**ARGS**) {
        process(result);
    }

};

private void runPrecaptureSequence() {
    try {          mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
        mState = STATE_WAITING_PRECAPTURE;
        mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

private void captureStillPicture() {
    try {
        final Activity activity = getActivity();
        if (null == activity || null == mCameraDevice) {
            return;
        }

        final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
        captureBuilder.addTarget(mImageReader.getSurface());
        captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF);           CaptureBuilder.set(CaptureRequest.CONTROL_AWB_MODE,CaptureRequest.CONTROL_AWB_MODE_OFF);
        float minimumLens = mCameraCharacteristics.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE);
        captureBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE, minimumLens);
        captureBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
        captureBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_OFF);
        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
        captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));

        mFileName = getFileNameFromTime() + ".jpg";

        CameraCaptureSession.CaptureCallback CaptureCallback
                = new CameraCaptureSession.CaptureCallback() {

            @Override
            public void onCaptureCompleted(@NonNull CameraCaptureSession session,
                                           @NonNull CaptureRequest request,
                                           @NonNull TotalCaptureResult result) {
                resumePreview();
            }
        };

        mCaptureSession.stopRepeating();
        mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

保存图像发生在 ImageReader onImageAvailableListener 调用中,并且工作正常。

似乎在获取图像之前闪光灯正在触发,因此我尝试了此答案中的建议,但建议的 FLASH_FIRED 条件从未触发。

比我更熟悉 Camera2 的人能看出我在哪里搞砸了吗?

4

2 回答 2

2

我已经看到了 camera2basic 的代码https://github.com/googlearchive/android-Camera2Basic及其较新的 Java 版本https://github.com/android/camera-samples/tree/master/Camera2BasicJava

所以基本上代码中有三个地方设置了flash(我说的是较新的java版本)

1) 私有 void createCameraPreviewSession() 函数

2) 私有 void captureStillPicture()

3)私人无效解锁焦点()

1) createCameraPreviewSession() 函数在预览即将显示时被调用(所以我想从应用程序的开头开始 Flash 相应地调用这些函数)

2) captureStillPicture() 函数在要捕获高清图片时被调用

3) unlockFocus() 函数在您捕获图像并希望在单击高清图片时解锁焦点时调用

因此,如果闪光灯闪烁或图像被洗掉,您可能只在最后两个功能之一设置闪光灯模式手电筒在最后两个功能中设置闪光灯模式并尽量避免在启动闪光灯后捕获的第一帧我正在设置闪光灯这样

       int flashFlag=1;
private void setAutoFlash(CaptureRequest.Builder requestBuilder) {
    if (mFlashSupported) {


        if (flashFlag==1)
        {
            requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_ON);
            requestBuilder.set(CaptureRequest.FLASH_MODE,CaptureRequest.FLASH_MODE_TORCH);
        }
        else
        {
            requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
                CaptureRequest.CONTROL_AE_MODE_ON);
        }


    }
}

我将 flashFlag 设为全局变量并将其设置在两个地方并拒绝第一个 flash HD 帧,因为它通常会被淘汰

也不要尝试在未拍摄高清照片的情况下打开闪光灯,因为它会锁定您的焦点

于 2019-11-08T13:33:22.130 回答
-1

将以下三行添加到 Camera2Basic 示例:

mPreviewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_OFF);
mPreviewRequestBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, 4000);
mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE, FLASH_MODE_TORCH);

当 Flash 被激活并启动 repeatingRequest 时,手动设置将被某种默认设置(传感器灵敏度:100)覆盖。但请求明确指出 Sensor-Sensitivity 应为 4000。我在 onCaptureCompleted-method 中使用这两行对其进行了测试:

Log.d(TAG, "request: "+request.get(CaptureRequest.SENSOR_SENSITIVITY));
Log.d(TAG, "result: "+result.get(CaptureResult.SENSOR_SENSITIVITY)); 
于 2017-04-19T21:07:12.977 回答