Android Camere开发入门(1):初识Camera

Android Camere开发入门(1):初识Camera

初步了解

在Android开发中,相机(Camera)是一个常见而重要的功能模块。它允许我们通过设备的摄像头捕捉照片和录制视频,为我们的应用程序增加图像处理和视觉交互的能力。

随着Android系统的不断发展和更新,相机功能也不断改进和增强。每个相机版本都引入了新的特性、API和性能改进,以提供更好的用户体验和更强大的功能。

本篇内容先从Camera1的初始化、预览、拍照以及帧回调来和大家一起践行开发工作,从实践中去了解Camera1的功能特性。

初始化相机

在使用Camera1 API之前,我们首先需要进行相机的初始化。这涉及到获取相机实例、设置相机参数,以及配置相机的预览界面。通过使用Camera类和相关的回调接口,我们可以实现与相机的交互。

从简入繁,下面先来认识camera1最简单的初始化

// 定义相机实例
private Camera mCamera;
private int width = 1920;
private int height = 1080;

// 初始化相机方法,注意要想让代码跑起来,要钱申请Camera权限
private void initCamera() {
    try {
        // 获取相机实例
        mCamera = Camera.open();

        // 设置相机参数
        Camera.Parameters parameters = mCamera.getParameters();
        // 设置自动对焦模式
        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
        // 设置相机预览图像的尺寸
        parameters.setPreviewSize(width, height);
        // 设置其他相机参数...

        // 将参数应用到相机
        mCamera.setParameters(parameters);

        // 这里使用surfaceTexture来承载相机的预览,而不需要设置一个可见的view
        mCamera.setPreviewTexture(new SurfaceTexture(0));
        // 启动相机预览
        mCamera.startPreview();
    } catch (Exception e) {
        // 处理相机初始化异常
        e.printStackTrace();
    }
}

// 停止相机预览并释放相机资源
private void releaseCamera() {
 if (mCamera != null) {
      mCamera.stopPreview();
      mCamera.release();
      mCamera = null;
  }
}

kotlin

// 定义相机实例
var mCamera: Camera? = null
val surfaceTexture = SurfaceTexture(0)
val width = 1920
val height = 1080

// 初始化相机方法,注意要想让代码跑起来,要先申请相机权限
private fun initCamera() {
    try {
        // 获取相机实例
        mCamera = Camera.open()

        // 设置相机参数
        val parameters = mCamera?.parameters
        // 设置自动对焦模式
        parameters?.focusMode = Camera.Parameters.FOCUS_MODE_AUTO
        // 设置相机预览图像的尺寸
        parameters?.setPreviewSize(width, height)
        // 设置其他相机参数...

        // 将参数应用到相机
        mCamera?.parameters = parameters

        // 使用SurfaceTexture来承载相机的预览,而不需要设置一个可见的View
        mCamera?.setPreviewTexture(surfaceTexture)
        // 启动相机预览
        mCamera?.startPreview()
    } catch (e: Exception) {
        // 处理相机初始化异常
        e.printStackTrace()
    }
}

// 停止相机预览并释放相机资源
private fun releaseCamera() {
    mCamera?.apply {
        stopPreview()
        release()
    }
    mCamera = null
}

预览相机

预览功能是相机应用程序的核心之一。通过设置预览界面,我们可以实时显示摄像头捕捉到的图像。在Camera1 API中,我们可以使用SurfaceHolder或SurfaceTexture来获取和控制预览视图,设置预览显示和启动预览过程。

下面具体来看SurfaceHolder和SurfaceTexture的差异

//设置TextureView回调监听
binding!!.cameraTextureView.surfaceTextureListener = this@SurfaceTextureActivity
//TextureView回调方法
 override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
        initCamera()
    }

override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {
    }

override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
        releaseCamera()
        return true
    }

override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {
    }
//设置SurfaceView回调监听
binding.cameraSurfaceView.getHolder().addCallback(JavaSurfaceViewActivity.this);
//SurfaceView的SurfaceHolder.Callback回调
override fun surfaceCreated(holder: SurfaceHolder) {
        initCamera()
    }

override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
    }

override fun surfaceDestroyed(holder: SurfaceHolder) {
        releaseCamera()
    }
//有别与上面的初始化内容,这里我们添加了自适应角度设置
mCamera?.setDisplayOrientation(getDisplayOrientation())

//绑定SurfaceView预览控件
mCamera.setPreviewDisplay(surfaceView.getHolder());
//绑定TextureView预览控件
mCamera.setPreviewTexture(binding?.cameraTextureView?.surfaceTexture)
	/**
     * 自适应相机角度
     * @return
     */
    private fun getDisplayOrientation(): Int {
        val windowManager = this.getSystemService(WINDOW_SERVICE) as WindowManager
        val display = windowManager.defaultDisplay
        val rotation = display.rotation
        var degrees = 0
        when (rotation) {
            Surface.ROTATION_0 -> degrees = 0
            Surface.ROTATION_90 -> degrees = 90
            Surface.ROTATION_180 -> degrees = 180
            Surface.ROTATION_270 -> degrees = 270
        }
        val cameraInfo = CameraInfo()
        Camera.getCameraInfo(CameraInfo.CAMERA_FACING_BACK, cameraInfo)
        var result: Int
        if (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {
            result = (cameraInfo.orientation + degrees) % 360
            result = (360 - result) % 360 // compensate the mirror
        } else {
            result = (cameraInfo.orientation - degrees + 360) % 360
        }
        return result
    }

不同的预览控件有点小差异,具体代码已同步Gitee和GitHub

拍摄照片

作为相机应用程序不可或缺的功能,拍照功能在Camera1 API中也得到了很好的支持。我们将学习如何设置相机参数以及捕捉高质量的照片。通过使用Camera类的takePicture()方法,我们可以触发相机拍摄照片的过程,并获取拍摄得到的图像数据。

获取图片的方式不止takePicture,你也可以通过帧回调进行保存或者直接调用拍照Intent

	//给按钮设置一个点击事件,点击时创建图片保存目录并生成图片名称并调用拍照方法
	File path = new File(this.getExternalFilesDir(null).getAbsolutePath() + "/img/");
    if (!path.exists()) path.mkdirs();
    binding.takePictureBtn.setOnClickListener(v -> {
            pictureFile = new File(path, s2.format(new Date()) + ".jpg");
            takePicture();
    });

	//拍照
    private SimpleDateFormat s2 = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
    private File pictureFile = null;
    private void takePicture() {
        mCamera.takePicture(null, null, (data, camera) -> {
            // 将照片数据保存为JPG文件
            if (pictureFile == null) {
                Log.d(TAG, "Error creating media file, check storage permissions");
                return;
            }

            try {
                FileOutputStream fos = new FileOutputStream(pictureFile);
                fos.write(data);
                fos.close();
                Log.d(TAG, "Picture saved: " + pictureFile.getAbsolutePath());
            } catch (FileNotFoundException e) {
                Log.d(TAG, "File not found: " + e.getMessage());
            } catch (IOException e) {
                Log.d(TAG, "Error accessing file: " + e.getMessage());
            }

            // 重新启动预览
            mCamera.startPreview();
        });
    }

注意:拍照要用到文件写入权限,切记要先申请

帧回调

帧回调是Camera1 API中一个强大的特性,通过它我们可以对相机捕捉到的每一帧进行处理和分析。我们将学习如何注册帧回调接口,并在回调方法中处理相机帧数据。这可以用于实现实时图像处理、面部识别、图像分析等功能。

设置帧回调1,需要对帧缓冲区进行消费后设置camera.addCallbackBuffer(yuvBuffer);再返回新一帧数据

 yuvBuffer = new byte[width * height * 3 / 2];
 mCamera.addCallbackBuffer(yuvBuffer);
 mCamera.setPreviewCallbackWithBuffer(previewCallback);

设置帧回调2,直接传递预览帧数据给回调函数

 mCamera.setPreviewCallback(previewCallback);
//帧回调
Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() {
        @Override
        public void onPreviewFrame(byte[] data, Camera camera) {
            //在这里对数据进行处理
            //帧缓冲区模式这个别忘记了
            camera.addCallbackBuffer(yuvBuffer);
        }
    };

总结

通过了解Camera1的初始化、预览、拍照以及帧回调的过程,我们可以更好地理解和掌握Camera1 API的使用方法。此外,在实际的应用开发中,我们可以根据具体需求进一步扩展和优化相机功能。如聚焦、夜视模式、手电筒等等,具体可参见官网Camera.Parameters

相机应用程序的开发是一个充满创造力和挑战性的过程,希望这篇博文能为你提供更多的参考和启示。

THE END


感谢查阅
玉念聿辉:编辑

https://gitee.com/yunianvh/camera-demo
https://github.com/yunianvh/CameraDemo

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

玉念聿辉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值