上海古都建筑设计集团,上海办公室装修设计公司,上海装修公司高质量的内容分享社区,上海装修公司我们不是内容生产者,我们只是上海办公室装修设计公司内容的搬运工平台

Android Camera2开启电子防抖(EIS)和光学防抖(OIS)

guduadmin14小时前

刚好当前项目有录像功能,使用了第三方框架是基于Camera2引擎开发,当使用 Camera2 API 开发相机应用时,启用和关闭 EIS(电子防抖)是一个重要的功能。EIS 可以帮助减少相机拍摄时的抖动,从而提高图像和视频的稳定性;OIS是光学图片想稳定器,功能是通过镜头的浮动透镜来纠正“光轴偏移”,需要硬件的支持,两者同时开启在录像时效果更佳。

EIS原理:

使用CCD偏移来实现防抖,通过降低图像失真和抖动,从而提高图像质量,首先把CCD安置在一个可以上下左右移动的支架上,然后当陀螺传感器检测到抖动的时候,就会把抖动的方向、速度和移动量等参数经过处理,计算出足以抵消抖动的CCD移动量,简单说就是通过放大录像焦距,根据陀螺仪旋转时预留周边的视角通过进行补帧移动画面给人感觉没有那么抖动,但效果没有光学防抖的好。

OIS原理:

其原理是通过镜头内的陀螺仪侦测到微小的移动,然后将信号传至微处理器,处理器立即计算需要补偿的位移量,然后通过补偿镜片组,根据镜头的抖动方向及位移量加以补偿。

对比开启EIS和OIS的摄像对比

eis开

eis关

1. 检查设备支持的特性

在使用 Camera2 API 开启 EIS 之前,我们需要首先检查设备是否支持 EIS 特性。我们可以通过 CameraCharacteristics 类来获取相机设备的特性信息。

 CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
            CameraCharacteristics characteristics = manager.getCameraCharacteristics(mCameraDevice.getId());
            boolean isModeHaveStabilization = false; // 支持电子防抖
        
            final int[] availableVideoStabilization = characteristics.get(
                    CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES);
            if (availableVideoStabilization == null || availableVideoStabilization.length == 0) {
                Log.e(TAG, "Optical stabilization not available");
                return;
            }
            for (int mode : availableVideoStabilization) {
                if (mode == CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_ON) {
                    isModeHaveStabilization = true;
                    Log.d(TAG, "Using video stabilization.");
                    break;
                }
            }
  int[] stabilizationModes = characteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION);
            if (stabilizationModes == null || stabilizationModes.length == 0) {
                Log.e(TAG, "Optical stabilization not available");
                return;
            }
            for (int mode : stabilizationModes) {
                if (mode == CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE_ON) {
                    isModeSupported = true;   // 支持光学防抖
                    break;
                }
            }
2. 启用 EIS和关闭EIS

记得判断是否支持EIS

// 开启EIS
mPreviewBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_ON);
//关闭EIS
mPreviewBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_OFF);
3. 启用OIS和关闭OIS
 captureRequestBuilder.set(CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE,
                        mEisEnabled ? CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE_ON :
                                CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE_OFF);

在创建预览请求的时候注意一定要设置成录制模式,预览模式开启不了EIS,设置无效

mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);

下面时完整代码片段,希望可以帮助到有需要的人

public class Camera2Activity extends AppCompatActivity {
    private static final String TAG = "Camera2Example";
    private TextureView mTextureView;
    private CameraDevice mCameraDevice;
    private CaptureRequest.Builder mPreviewBuilder;
    private CameraCaptureSession mCaptureSession;
    // private SurfaceTexture mSurfaceTexture;
    private Button captureModel;
    //private Camera2Helper mCamera2Helper;
    boolean mEisEnabled = true;
    private Handler backgroundHandler;
    private HandlerThread backgroundThread;
    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera);
        initView();
    }
    private void initView() {
        captureModel = (Button) findViewById(R.id.captureModel);
        mTextureView = findViewById(R.id.textureView);
        mCaptureButton = findViewById(R.id.captureButton);
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA}, 200);
            return;
        }
        findViewById(R.id.eisopen).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                enableEis();
            }
        });
        findViewById(R.id.eisclose).setOnClickListener(v -> {
            disableEis();
        });
        captureModel.setOnClickListener(v -> {
            switchMode();
        });
    }
    private TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
            openCamera();
        }
        @Override
        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
        }
        @Override
        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
            return false;
        }
        @Override
        public void onSurfaceTextureUpdated(SurfaceTexture surface) {
        }
    };
    //打开相机
    public void openCamera() {
        CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
        try {
            String cameraId = cameraManager.getCameraIdList()[0];
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                // 请求权限
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 200);
                return;
            }
            cameraManager.openCamera(cameraId, new CameraDevice.StateCallback() {
                @Override
                public void onOpened(@NonNull CameraDevice camera) {
                    mCameraDevice = camera;
                    createCameraPreviewSession();
                }
                @Override
                public void onDisconnected(@NonNull CameraDevice camera) {
                    mCameraDevice.close();
                    mCameraDevice = null;
                }
                @Override
                public void onError(@NonNull CameraDevice camera, int error) {
                    mCameraDevice.close();
                    mCameraDevice = null;
                }
            }, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
    // 创建CameraCaptureSession
    private void createCameraPreviewSession() {
        try {
            SurfaceTexture texture = mTextureView.getSurfaceTexture();
            // 设置预览尺寸
            texture.setDefaultBufferSize(mTextureView.getWidth(), mTextureView.getHeight());
            assert texture != null;
            // 创建预览Surface
            Surface surface = new Surface(texture);
            // 创建CaptureRequest.Builder
            mPreviewBuilder = mCameraDevice.createCaptureRequest(mCurrentMode);
            // 设置自动对焦模式
            mPreviewBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            // 设置自动曝光模式
            mPreviewBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
            mPreviewBuilder.addTarget(surface);
            toggleStabilization(mPreviewBuilder);
            // 创建CameraCaptureSession
            mCameraDevice.createCaptureSession(Collections.singletonList(surface),
                    new CameraCaptureSession.StateCallback() {
                        @Override
                        public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                            // 相机已经关闭
                            if (null == mCameraDevice) {
                                return;
                            }
                            // 会话准备好后,我们开始显示预览
                            mCaptureSession = cameraCaptureSession;
                            updatePreview();
                        }
                        @Override
                        public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
                            //   showToast("Failed");
                        }
                    }, backgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
    int mCurrentMode = CameraDevice.TEMPLATE_PREVIEW;
    // 在点击按钮时切换模式
    private void switchMode() {
        if (mCurrentMode == CameraDevice.TEMPLATE_PREVIEW) {
            // 切换到录制模式
            mCurrentMode = CameraDevice.TEMPLATE_RECORD;
            createCameraPreviewSession();
            captureModel.setText("切换到预览模式");
        } else {
            // 切换到预览模式
            mPreviewBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
            mCurrentMode = CameraDevice.TEMPLATE_PREVIEW;
            createCameraPreviewSession();
            captureModel.setText("切换到录制模式");
        }
    }
    // 电子防抖和光学防抖
    private void toggleStabilization(CaptureRequest.Builder captureRequestBuilder) {
        if (mPreviewBuilder == null) {
            return;
        }
        try {
            CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
            CameraCharacteristics characteristics = manager.getCameraCharacteristics(mCameraDevice.getId());
            boolean isModeHaveStabilization = false; // 支持电子防抖
            boolean isModeSupported = false; // 支持光学防抖
            final int[] availableVideoStabilization = characteristics.get(
                    CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES);
            if (availableVideoStabilization == null || availableVideoStabilization.length == 0) {
                Log.e(TAG, "Optical stabilization not available");
                return;
            }
            for (int mode : availableVideoStabilization) {
                if (mode == CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_ON) {
                    isModeHaveStabilization = true;
                    Log.d(TAG, "Using video stabilization.");
                    break;
                }
            }
            // 开启EIS电子防抖功能
            if (mEisEnabled && isModeHaveStabilization) {
                mPreviewBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_ON);
                mPreviewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_USE_SCENE_MODE);
                mPreviewBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_ACTION); // hrd 动作场景模式
            } else {
                mPreviewBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_OFF);
                mPreviewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_USE_SCENE_MODE);
                mPreviewBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_ACTION); // hrd  动作场景模式
            }
            int[] stabilizationModes = characteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION);
            if (stabilizationModes == null || stabilizationModes.length == 0) {
                Log.e(TAG, "Optical stabilization not available");
                return;
            }
            for (int mode : stabilizationModes) {
                if (mode == CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE_ON) {
                    isModeSupported = true;
                    break;
                }
            }
            // 开启OIS光学防抖功能
            if (isModeSupported) {
                captureRequestBuilder.set(CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE,
                        mEisEnabled ? CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE_ON :
                                CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE_OFF);
            }
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
    // 更新预览
    private void updatePreview() {
        if (null == mCameraDevice) {
            return;
        }
        try {
            mCaptureSession.setRepeatingRequest(mPreviewBuilder.build(), null, backgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
    // 开启EIS电子防抖功能
    private void enableEis() {
        mEisEnabled = true;
        toggleStabilization(mPreviewBuilder);
        updatePreview();
    }
    // 关闭EIS电子防抖功能
    private void disableEis() {
        mEisEnabled = false;
        toggleStabilization(mPreviewBuilder);
        updatePreview();
    }
    @Override
    protected void onResume() {
        super.onResume();
        startBackgroundThread();
        if (mTextureView.isAvailable()) {
            openCamera();
        } else {
            mTextureView.setSurfaceTextureListener(textureListener);
        }
    }
    @Override
    protected void onPause() {
        super.onPause();
        stopBackgroundThread();
        closeCamera();
    }
    private void closeCamera() {
        if (mCaptureSession != null) {
            mCaptureSession.close();
            mCaptureSession = null;
        }
        if (mCameraDevice != null) {
            mCameraDevice.close();
            mCameraDevice = null;
        }
    }
    private void startBackgroundThread() {
        backgroundThread = new HandlerThread("CameraBackground");
        backgroundThread.start();
        backgroundHandler = new Handler(backgroundThread.getLooper());
    }
    private void stopBackgroundThread() {
        backgroundThread.quitSafely();
        try {
            backgroundThread.join();
            backgroundThread = null;
            backgroundHandler = null;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

翻译

搜索

复制

网友评论