Android camera2对焦设置

本文介绍如何使用Android Camera2 API进行手动焦距设置。首先需要关闭自动焦距模式,然后设置焦距值。文章还提到了实现该功能的前置条件,包括检查设备是否支持焦距设置。

在android camera2 api 开始,提供了对焦距值(非zoom值)的设置,大概步骤如下:

(1)先关闭自动焦距模式    mPreviewBuilder.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_OFF); 

mPreviewBuilder.set(CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_OFF); 

(2)再设置上焦距值  mPreviewBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE, 焦距值) 


注意点:在android 5.0后开始提供了camera2 api的支持,但不是所有的机器都可以支持焦距的设置。

前提检查是: 

1.CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE值是否为空(一般非空才可以)。

2.还有检查一下HARD_LEVEL值是否达到。




<think>我们使用Camera2 API来实现对焦和拍照功能。主要步骤包括: 1. 初始化相机:获取CameraManager,打开相机设备,创建预览会话。 2. 设置对焦:通过CaptureRequest设置对焦模式,并触发自动对焦。 3. 拍照:创建CaptureRequest.Builder用于拍照,设置输出Surface,然后捕获静态图像。 注意:我们需要在合适的时机(例如预览会话建立后)触发自动对焦,并在用户触发拍照时捕获图像。 以下是Kotlin示例代码的关键步骤: ### 1. 定义必要的变量 ```kotlin private lateinit var cameraManager: CameraManager private lateinit var cameraId: String private lateinit var cameraDevice: CameraDevice private lateinit var captureSession: CameraCaptureSession private lateinit var previewRequestBuilder: CaptureRequest.Builder ``` ### 2. 打开相机 ```kotlin cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager // 这里我们选择后置摄像头(根据需求调整) cameraId = cameraManager.cameraIdList.first { val characteristics = cameraManager.getCameraCharacteristics(it) characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_BACK } // 打开相机 cameraManager.openCamera(cameraId, object : CameraDevice.StateCallback() { override fun onOpened(device: CameraDevice) { cameraDevice = device // 创建预览会话 createPreviewSession() } override fun onDisconnected(device: CameraDevice) { device.close() } override fun onError(device: CameraDevice, error: Int) { device.close() } }, null) ``` ### 3. 创建预览会话 在创建预览会话时,我们需要设置一个用于预览的Surface(例如TextureView的SurfaceTexture)并构建预览请求。 ```kotlin private fun createPreviewSession() { val textureView: TextureView = ... // 你的TextureView val surfaceTexture = textureView.surfaceTexture surfaceTexture.setDefaultBufferSize(previewSize.width, previewSize.height) val previewSurface = Surface(surfaceTexture) // 创建用于预览的请求 previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) previewRequestBuilder.addTarget(previewSurface) // 创建CaptureSession,这里我们使用预览Surface和用于保存照片的ImageReader的Surface cameraDevice.createCaptureSession( listOf(previewSurface, imageReader.surface), object : CameraCaptureSession.StateCallback() { override fun onConfigured(session: CameraCaptureSession) { captureSession = session // 设置自动对焦模式 previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE) // 设置会话以重复发送预览请求 captureSession.setRepeatingRequest(previewRequestBuilder.build(), null, null) } override fun onConfigureFailed(session: CameraCaptureSession) { // 处理失败 } }, null ) } ``` ### 4. 设置自动对焦 在上面的预览请求中,我们设置了`CONTROL_AF_MODE_CONTINUOUS_PICTURE`模式,该模式适用于连续自动对焦(适合拍照)。当需要手动触发对焦(例如点击屏幕对焦)时,我们可以触发一次自动对焦操作。 ```kotlin fun triggerFocus() { // 首先停止重复请求 captureSession.stopRepeating() // 创建一个新的请求,设置对焦模式为自动对焦并触发 previewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START) captureSession.capture(previewRequestBuilder.build(), object : CameraCaptureSession.CaptureCallback() { override fun onCaptureCompleted(session: CameraCaptureSession, request: CaptureRequest, result: TotalCaptureResult) { // 对焦完成后,重新开始预览(并恢复连续对焦模式) previewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_IDLE) captureSession.setRepeatingRequest(previewRequestBuilder.build(), null, null) } }, null) } ``` ### 5. 拍照 首先,我们需要创建一个ImageReader来接收拍照结果。 ```kotlin private lateinit var imageReader: ImageReader // 初始化ImageReader imageReader = ImageReader.newInstance(imageWidth, imageHeight, ImageFormat.JPEG, 1) imageReader.setOnImageAvailableListener({ reader -> val image = reader.acquireLatestImage() // 处理图像数据(例如保存为文件) saveImage(image) image.close() }, null) ``` 在用户触发拍照时,我们创建一个拍照请求: ```kotlin fun takePicture() { // 停止预览 captureSession.stopRepeating() // 创建拍照请求 val captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE).apply { addTarget(imageReader.surface) // 设置拍照参数,例如自动对焦、闪光灯等 set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE) // 设置JPEG方向 val rotation = windowManager.defaultDisplay.rotation val sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION) val jpegOrientation = (sensorOrientation + rotation * 90 + 360) % 360 set(CaptureRequest.JPEG_ORIENTATION, jpegOrientation) } // 捕获静态图像 captureSession.capture(captureBuilder.build(), object : CameraCaptureSession.CaptureCallback() { override fun onCaptureCompleted(session: CameraCaptureSession, request: CaptureRequest, result: TotalCaptureResult) { // 拍照完成后,重新开始预览 previewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_IDLE) captureSession.setRepeatingRequest(previewRequestBuilder.build(), null, null) } }, null) } ``` ### 6. 保存图像 在`ImageReader`的回调中,我们可以获取到图像数据并保存。 ```kotlin private fun saveImage(image: Image) { val buffer = image.planes[0].buffer val bytes = ByteArray(buffer.remaining()) buffer.get(bytes) // 保存bytes到文件(注意:需要在后台线程执行文件操作) // 例如:FileOutputStream(file).use { it.write(bytes) } } ``` ### 注意事项 - 上述代码仅为示例,实际开发中需要处理权限、生命周期(例如在onPause中关闭相机)、线程(使用后台线程执行耗时操作)等问题。 - 需要添加相机权限:`<uses-permission android:name="android.permission.CAMERA" />` ### 引用说明 本实现参考了Android Camera2 API的基本使用流程[^1][^4],并针对对焦和拍照功能进行了具体实现。 §§相关问题§§ 1. Camera2 API中如何实现手动对焦2. 在Camera2 API中如何处理图像数据(如YUV格式)? 3. Camera2 API与旧版Camera API的主要区别是什么?</think>### Android Camera2 API 对焦和拍照实现(Kotlin) 以下是使用 Camera2 API 实现自动对焦和拍照功能的完整 Kotlin 示例代码: ```kotlin class CameraActivity : AppCompatActivity() { // 核心组件 private lateinit var cameraManager: CameraManager private lateinit var cameraId: String private var cameraDevice: CameraDevice? = null private var captureSession: CameraCaptureSession? = null // UI 组件 private lateinit var textureView: TextureView private lateinit var captureButton: Button // 图像处理 private lateinit var imageReader: ImageReader override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_camera) textureView = findViewById(R.id.texture_view) captureButton = findViewById(R.id.capture_button) cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager // 初始化相机 setupCamera() // 拍照按钮点击事件 captureButton.setOnClickListener { captureStillImage() } } /** 1. 初始化相机设置 */ private fun setupCamera() { try { // 选择后置摄像头 cameraId = cameraManager.cameraIdList.first { val characteristics = cameraManager.getCameraCharacteristics(it) characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_BACK } // 检查相机权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), REQUEST_CAMERA_PERMISSION) return } // 打开相机 cameraManager.openCamera(cameraId, cameraStateCallback, null) // 初始化ImageReader用于拍照 val characteristics = cameraManager.getCameraCharacteristics(cameraId) val map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP) val largestSize = map!!.getOutputSizes(ImageFormat.JPEG).maxByOrNull { it.height * it.width }!! imageReader = ImageReader.newInstance(largestSize.width, largestSize.height, ImageFormat.JPEG, 2) imageReader.setOnImageAvailableListener(imageListener, null) } catch (e: CameraAccessException) { e.printStackTrace() } } /** 2. 相机设备回调 */ private val cameraStateCallback = object : CameraDevice.StateCallback() { override fun onOpened(device: CameraDevice) { cameraDevice = device createPreviewSession() } override fun onDisconnected(device: CameraDevice) { device.close() cameraDevice = null } override fun onError(device: CameraDevice, error: Int) { device.close() cameraDevice = null } } /** 3. 创建预览会话 */ private fun createPreviewSession() { val texture = textureView.surfaceTexture?.apply { setDefaultBufferSize(textureView.width, textureView.height) } val previewSurface = Surface(texture) val captureBuilder = cameraDevice?.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)?.apply { addTarget(previewSurface) // 设置自动对焦模式 set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE) } cameraDevice?.createCaptureSession( listOf(previewSurface, imageReader.surface), object : CameraCaptureSession.StateCallback() { override fun onConfigured(session: CameraCaptureSession) { captureSession = session captureBuilder?.let { it.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE) session.setRepeatingRequest(it.build(), null, null) } } override fun onConfigureFailed(session: CameraCaptureSession) { Toast.makeText(this@CameraActivity, "配置失败", Toast.LENGTH_SHORT).show() } }, null ) } /** 4. 触发拍照 */ private fun captureStillImage() { cameraDevice?.let { device -> val captureBuilder = device.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE).apply { addTarget(imageReader.surface) // 设置自动对焦并锁定 set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO) set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START) // 设置JPEG方向 val rotation = windowManager.defaultDisplay.rotation val sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION)!! val jpegOrientation = (sensorOrientation + rotation * 90 + 360) % 360 set(CaptureRequest.JPEG_ORIENTATION, jpegOrientation) } // 捕获静态图像 captureSession?.capture(captureBuilder.build(), captureCallback, null) } } /** 5. 拍照回调 */ private val captureCallback = object : CameraCaptureSession.CaptureCallback() { override fun onCaptureCompleted( session: CameraCaptureSession, request: CaptureRequest, result: TotalCaptureResult ) { super.onCaptureCompleted(session, request, result) Toast.makeText(this@CameraActivity, "照片已保存", Toast.LENGTH_SHORT).show() // 拍照后恢复预览 createPreviewSession() } } /** 6. 图像保存处理 */ private val imageListener = ImageReader.OnImageAvailableListener { reader -> val image = reader.acquireLatestImage() val buffer = image.planes[0].buffer val bytes = ByteArray(buffer.remaining()).apply { buffer.get(this) } // 保存图片到文件(需在后台线程执行) thread { val output = File(getExternalFilesDir(null), "${System.currentTimeMillis()}.jpg") FileOutputStream(output).use { it.write(bytes) } image.close() } } companion object { private const val REQUEST_CAMERA_PERMISSION = 100 } } ``` ### 关键实现说明: 1. **自动对焦实现**: - 预览模式使用 `CONTROL_AF_MODE_CONTINUOUS_PICTURE` 实现连续自动对焦[^1] - 拍照时切换为 `CONTROL_AF_MODE_AUTO` 并触发 `CONTROL_AF_TRIGGER_START` 锁定焦点[^3] 2. **拍照流程**: - 使用 `ImageReader` 接收 JPEG 格式图像数据 - 设置正确的 `JPEG_ORIENTATION` 保证图像方向正确[^4] - 通过 `OnImageAvailableListener` 处理图像数据并保存为文件 3. **生命周期管理**: - 在 `onPause()` 中关闭相机资源 - 正确处理相机权限请求 - 使用后台线程执行文件保存操作 ### 布局文件示例 (res/layout/activity_camera.xml): ```xml <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextureView android:id="@+id/texture_view" android:layout_width="match_parent" android:layout_height="match_parent"/> <Button android:id="@+id/capture_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|center_horizontal" android:text="拍照" android:layout_margin="16dp"/> </FrameLayout> ``` ### 所需权限: ```xml <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> ``` [^1]: Camera2 API 提供了更精细的相机参数控制,包括对焦模式设置[^1] [^3]: 通过 `CameraCharacteristics` 获取相机特性,使用 `CaptureRequest` 控制对焦行为[^3] [^4]: 正确处理图像方向是 Camera2 开发中的关键步骤[^4]
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

BlueGoDisplay

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

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

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

打赏作者

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

抵扣说明:

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

余额充值