嵌入式安卓开发:使用Camera2获取相机

Camera2介绍

  • Android 5.0开始,Google 引入了一套全新的相机框架 Camera2(android.hardware.camera2),并且废弃了旧的相机框架 Camera1(android.hardware.Camera)
  • Camera2相比于Camera的API不仅大幅提高了Android系统拍照的功能,还能支持RAW照片输出,甚至允许程序调整相机的对焦模式、曝光模式、快门等。
  • Camera2相比于Camera更加灵活的同时,也更加的复杂,包含的类更多。

Camera2的主要API类介绍

Camera2获取相机涉及的类如下:
在这里插入图片描述

CameraManager

摄像头管理器。这是一个全新的系统管理器,专门用于检测系统摄像头、打开系统摄像头。除此之外,调用CameraManager的getCameracharacteristics(String)方法即可获取指定摄像头的相关特性。代码如下:

	private int mCameraId = CameraCharacteristics.LENS_FACING_FRONT;//后置相机的ID
    String MyCameraIdStr = Integer.toString(mCameraId);
    private CameraManager mCameraManager;   //相机管理者
    private CameraCharacteristics mCameraCharacteristics;   //相机属性
    float EXPOSURE_TIME_RANGE_min_hz = 0, EXPOSURE_TIME_RANGE_max_hz = 0;
    Range EXPOSURE_TIME_RANGE_msg;//相机曝光时间范围,不可改变
    int CameraInfo_FPS_min, CameraInfo_FPS_max;
    Range[] CameraInfo_FPS_Range;
    int CameraInfo_ISO_min, CameraInfo_ISO_max;
    float[] CameraInfo_Aperture;
    float CameraInfo_Focal_Length[];
    boolean FlagOfCreate = false;

	private void CreateCamera() {
    
       //获取CameraManager,得到相机参数
        mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
        try {
    
    
            mCameraCharacteristics = mCameraManager.getCameraCharacteristics(MyCameraIdStr);
            Log.d("曝光补偿范围", mCameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE).toString());
            //上述语句获取相机设备支持的曝光补偿范围
            Log.d("快门时间", mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE).toString());

        } catch (CameraAccessException e) {
    
    
            e.printStackTrace();
        }
        FlagOfCreate = true;
        EXPOSURE_TIME_RANGE_msg = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE);
        EXPOSURE_TIME_RANGE_max_hz = (float) (1000000000.0 / (long) EXPOSURE_TIME_RANGE_msg.getLower());
        EXPOSURE_TIME_RANGE_min_hz = (float) (1000000000.0 / (long) EXPOSURE_TIME_RANGE_msg.getUpper());
//        Log.d("测试:",String.format("%d",EXPOSURE_TIME_RANGE_msg.getLower()));
//        CameraInfo_FPS_min = (Range[])(mCameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES))
        CameraInfo_FPS_Range = mCameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
        CameraInfo_FPS_min = (int) CameraInfo_FPS_Range[0].getLower();
        CameraInfo_FPS_max = (int) CameraInfo_FPS_Range[CameraInfo_FPS_Range.length - 1].getUpper();
//        for(int i = 0; i < CameraInfo_FPS_Range.length; ++ i)
//        {
    
    
//            Log.d("帧率:",CameraInfo_FPS_Range[i].toString());
//        }
        CameraInfo_ISO_min = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE).getLower();
        CameraInfo_ISO_max = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE).getUpper();

        CameraInfo_Aperture = mCameraCharacteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES);
        CameraInfo_Focal_Length = mCameraCharacteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS);
//
    }
    public void BtnClick_CameraInfo(View v) {
    
    
        if (FlagOfCreate != true) {
    
    
            CreateCamera();
        }


        String msg = "";
        msg += "快门速度:" + String.format("%.4f,%.4f", EXPOSURE_TIME_RANGE_min_hz, EXPOSURE_TIME_RANGE_max_hz) + "赫兹\n";
        msg += "相机帧率:" + String.format("%d,%d", CameraInfo_FPS_min, CameraInfo_FPS_max) + " fps\n";
        msg += "ISO::" + String.format("%d,%d", CameraInfo_ISO_min, CameraInfo_ISO_max) + "\n";
        msg += "光圈:";
        for (int i = 0; i < CameraInfo_Aperture.length; ++i) {
    
    
            msg += String.format("%f,", CameraInfo_Aperture[i]);
        }
        msg += "\n";
        msg += "焦距:";
        for (int i = 0; i < CameraInfo_Focal_Length.length; ++i) {
    
    
            msg += String.format("%f,", CameraInfo_Focal_Length[i]);
        }
        msg += "\n";
        TextMsg.setText(msg);

//        Log.d("CameraInfo","WCC");
    }

运行结果如下:
在这里插入图片描述

可以发现相机的光圈只有一个值,即手机的摄像头光圈是固定的,只有一个光圈值。

通过CameraManage获取Cameracharacteristics

摄像头特性。该对象通过CameraManager来获取,用于描述特定摄像头所支持的各种特性。

相比于旧 API 中的 CameraInfo 类。Cameracharacteristics包括:

曝光补偿(Exposure compensation)、
自动曝光/自动对焦/自动白平衡模式(AE / AF / AWB mode)、
自动曝光/自动白平衡锁(AE / AWB lock)、
自动对焦触发器(AF trigger)、
拍摄前自动曝光触发器(Precapture AE trigger)、
测量区域(Metering regions)、
闪光灯触发器(Flash trigger)、
曝光时间(Exposure time)、
感光度(ISO Sensitivity)、
帧间隔(Frame duration)、
镜头对焦距离(Lens focus distance)、
色彩校正矩阵(Color correction matrix)、
JPEG 元数据(JPEG metadata)、
色调映射曲线(Tonemap curve)、
裁剪区域(Crop region)、
目标 FPS 范围(Target FPS range)、
拍摄意图(Capture intent)、
硬件视频防抖(Video stabilization)等。

在上段的例程中,我们展示了通过CameraManage获取CameraCharacteristics,并显示在界面上。
想更详细地了解相关信息,可以参考:
Android Camera2 之 CameraCharacteristics 详解
官方介绍链接

通过CameraManage获取CameraDevice

在最上面的流程图中,CameraManage只是从Context获取摄像头,并进行管理,此时我们可以获取相机的一些参数。如果想进行拍照获取图像,则还需要获取CameraDevice类对象。
CameraDevice通过CameraManage的openCamera方法在回调函数中获取打开的摄像头,具体代码如下:

	CameraDevice.StateCallback MyDeviceCallback; //摄像头监听,在回调中获取camera device
	CameraDevice MyCameraDevice;
	MyDeviceCallback = new CameraDevice.StateCallback() {
    
    
    @Override
    public void onOpened(@NonNull CameraDevice camera) {
    
    //@NonNull后,便会自动对该参数值进行判空。
        Log.d("Camera调试:", "成功获取Camera Device");
        MyCameraDevice = camera;
        takePreview();//获取Camera device后,从Camera device获取Capture Session
    }

    @Override
    public void onDisconnected(@NonNull CameraDevice camera) {
    
    
        Log.d("Camera调试:", "获取Camera Device失败");
    }

    @Override
    public void onError(@NonNull CameraDevice camera, int error) {
    
    
        Log.d("Camera调试:", "获取Camera Device错误");
    }
};

首先,我们声明了一个CameraDevice.StateCallback类型的对象,该对象的作用是在执行CameraDevice.OpenCamera方法时,将该回调对象传进去,执行OpenCamera后,会自动地调用该回调函数对象。如下:

	if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
    
    
        Log.d("相机调试:", "没有权限");
        return;
    }
    try {
    
    
        mCameraManager.openCamera(MyCameraIdStr, MyDeviceCallback, null);
        //打开相机,监听回调,在回调函数中获取camera device
    } catch (CameraAccessException e) {
    
    
        Log.e("相机错误:", "打开摄像头失败");
    }

从CameraDevice获取CameraCaptureSession

CameraCaptureSession的作用是控制相机进行预览或者拍照,可以通过CameraDevice的createCaptureSession方法创建,代码如下:

	CameraCaptureSession MyCameraCaptureSession;    //由CameraDvice创建,控制摄像头预览或拍照
	List<Surface> surfaces;
	surfaces = new ArrayList<>();
	surfaces.add(MySurfaceView.getHolder().getSurface());
try {
    
    
			/*
             * 参数
             * outputs 相机流输出的地方
             * callback
             * handler 表示 createCaptureSession 代码运行所在的线程,传null,表示运行在当前线程
             */
	MyCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
    
    
   @Override
    public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
    
    
        MyCameraCaptureSession = cameraCaptureSession;
        Log.d("MyCameraDevice.createCaptureSession:","成功获取CameraCaptureSession");
    }
    @Override
    public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
    
    
        Log.d("MyCameraDevice.createCaptureSession:", "获取camera capture session错误");
    }
}, null);
} catch (CameraAccessException e) {
    
    
Log.e("开启预览:", "错误,不能访问摄像头");
}

其中createCaptureSession的第一个参数surfaces是指明预览数据流输出的地方,这里我们从界面上获取一个SurfaceView,将SurfaceView目前的Surface放入List surfaces,作为形参传给createCaptureSession,至此,就可以在界面上看到预览的效果了。

预览效果

如下图所示:
在这里插入图片描述

参考

android camera2 详解说明(一)
Camera2 教程 一概览
Android:Camera2的简单使用
Camera参考详述
camera2使用相机

猜你喜欢

转载自blog.csdn.net/wcc243588569/article/details/130282904