在挪动端倒退的过程中,相机设施对于推动挪动设施翻新起到了无足轻重的作用,而相机曝光则是可能拍摄出不凡品质照片的要害因素。在本文中,我将为大家详解挪动端开发者在解决相机曝光时所遇到的挑战。之后我会为大家介绍新的 CameraX 曝光弥补 (Exposure Compensation) API 如何帮忙开发者应答这些挑战,使疾速拍摄高品质照片变得更加简略。最初,我将为大家展现如何在您的利用中应用该 API。
背景
在摄影中,曝光是决定最终相机所出现图像的最重要因素之一,因而大多数摄影师都竭力将曝光调至最佳。主动曝光 (AE) 模式在大多数常见拍摄场景下的成果都不错,比方主动疾速拍照。然而在某些特定条件下,AE 模式会为了照片的整体品质而做出一些斗争,而这些斗争有时并不是您想要的。其中一个例子就是逆光,例如,在室内朝向窗户或者其它光源的地位拍摄,或者在室外拍摄,拍摄对象的前方刚好是太阳。在这些拍摄场景中,AE 模式会因为亮堂的背景 (照片中高亮的区域) 而对照片进行适当曝光,然而处于光明前景中的主体就会变得过于暗淡或者成为掠影成果。图 1 展现的是在雷同条件 (室内逆光) 下应用不同曝光进行拍摄的三张照片。
AE 对于照片的整体品质管制得很好,然而更高的曝光的确可能捕捉到 Android 公仔的更多画面细节。
传统操作中,摄影师通过调整如下三个参数来达到称心的曝光:
- 光圈: 镜片的关上水平,它管制相机的进光量
- 快门速度: 照片曝光的持续时间
- ISO (国际标准化组织): 相机感光元件对捕捉光线的敏感水平
每个参数对于图像都有非凡的作用: 光圈能够调整景深成果,快门速度能够虚化静止的过程或者定格静止的霎时,而更高的 ISO 会减少图像噪点。其中用到相当精准的数学计算,然而这些参数设置的不同组合能够取得雷同的整体曝光成果,以及在这个过程中取得高水准的完满曝光数值。为了辅助弥补曝光,CameraX 实现了曝光弥补 API。
实现曝光弥补 API
曝光弥补 API 依据生成的主动曝光值,通过曝光弥补指数调整曝光弥补度。曝光弥补指数能够为正值 (用于进步照片亮度) 或者负值 (升高照片亮度)。它将整体曝光范畴映射到弥补指数的取值区间,并将曝光总量映射到 EV 步长。相机设施外部会依据曝光指数扭转曝光,缩小管制其它参数的操作并且达到同一成果。
以图 1 为例,相机的默认配置无奈为咱们心愿对焦的主体提供足够的亮度,所以咱们能够应用正值指数的曝光弥补配置来取得两倍或者四倍的曝光,从而突出主体。通过扭转曝光弥补指数,相机外部会管制快门速度、光圈和 ISO 以取得适合的曝光。
要取得弥补指数,CameraX 实现了以下内容:
- CameraControl::setExposureCompensationIndex,用于设置新的曝光弥补指数。
-
ExposureState 用于曝光弥补性能和以后配置,包含:
- 反对调整弥补
- 所反对的弥补范畴
- 所反对的弥补步长
- 以后弥补指数值
咱们来看看在 CameraX 利用中如何应用 API 来创立曝光适合的照片。
应用曝光弥补 API
要在利用中应用曝光弥补 API,您须要实现如下工作:
- 查问曝光弥补范畴
- 设置新的曝光弥补指数
- 当 CameraX 确认后持续后续操作
查问曝光弥补指数的范畴
曝光弥补值的范畴依赖 相机设施的配置和硬件级别;利用能够通过 ExposureState 接口查问所反对的取值范畴。
val camera = cameraProvider.bindToLifecycle(…)
val range = camera.cameraInfo.exposureState.exposureCompensationRange
设置新的曝光弥补指数
如果照片显得较暗,在相机本来的修改曝光根底上设置一个正值的曝光弥补指数来进步亮度;同理,如果照片显得过亮,则设置一个负值。这能够通过 setExposureCompensationIndex() 来实现:
interface CameraControl {fun setExposureCompensationIndex(value: Int): ListenableFuture<Int!>
}
默认状况下,曝光弥补指数的值从 “0” 开始,新的指数值必须在相机设施所反对的范畴内变动。否则 CameraX 会抛出 IllegalArgument
谬误。请留神如果相机设施不反对曝光弥补调节,CameraX 所返回反对的取值范畴是 [0,0]。
举个例子,下述代码中当用户点击了 UI 中的按钮会进步曝光弥补指数直到曝光指数达到所反对的最大值为止:
var exposureIndex = 0
val camera = cameraProvider.bindToLifecycle(
lifecycleOwner,
getCameraSelector(),
preview,
imageCapture,
)
evButton.setOnClickListener {
val range = camera.cameraInfo.exposureState.exposureCompensationRange
if (range.contains(exposureIndex + 1)) {camera.cameraControl.setExposureCompensationIndex(++exposureIndex)
val ev = camera.cameraInfo.exposureState.exposureCompensationStep.toFloat() * exposureIndex
Log.i("CameraXLog", "EV: $ev")
}
}
setExposureCompensationIndex()
是 async
函数,每个相机只能响应一个未解决的申请。如果利用在之前的调用未被响应之前再次调用 setExposureCompensationIndex()
,新的调用申请就会代替之前的申请,而之前的申请会被勾销并抛出 OperationCanceledException
。通常,新的指数值会被迅速启用,输入流的曝光会随着 绑定用例 变动。如果利用须要晓得特定申请的精确执行工夫和后果,能够在函数返回的 ListenableFuture<Int>) 之上注册监听器。
关联弥补指数和曝光值 (EV)
曝光值 (EV) 是一个用于示意曝光弥补的光照度差别的度量单位。+1 EV 示意两倍光照,+2 EV 是四倍光照,依此类推。利用能够将雷同的 曝光 值利用到各种相机,甚至不同的设施,来取得类似的曝光,然而利用不应该针对雷同的指标成果间接应用雷同的 指数 值,因为每个指数值是相机的专属值。
弥补 API 中,曝光值是通过如下公式进行计算的:
曝光值 (EV) = exposure_compensation_index * compensation_step
上述公式中提到的 compensation_step 是曝光值可被批改的最小单位。请留神 compensation_step 也依赖相机设施。利用能够通过 ExposureState
查问相机的 compensation_step,并且能够依照上面所示计算曝光值:
val camera = cameraProvider.bindToLifecycle(…)
val exposureValue = camera.cameraInfo.exposureState.exposureCompensationStep.toFloat() * exposureIndex
例如: exposure_compensation_index 等于 6,compensation_step 等于 ⅓,那么曝光弥补计算为 +2 EV,也就是 两倍 的默认曝光值。
compensation_step 的 step_size 取值通常为 ⅓ 或者 ½,较少状况下,有些设施可能会反对 1 或者甚至 ¼。所能反对的最大曝光值个别是 2 EV 或者 3 EV。
CameraX 曝光弥补 API 的可用性
曝光弥补 API 是在 android.camera:camera-core:1.0.0-beta09
中首次以试验形式公布。
该 API 在版本 android.camera:camera-core:1.1.0-alpha06
中实现了试验阶段,成为正式版本 CameraX API 的一部分。
要取得最新的公布版本,请查阅 官网 CameraX 版本阐明。
总结
在 GitHub 上能够找到 CameraX 曝光弥补的示例代码。联合 CameraX API 的其它局部,曝光弥补 API 能够帮忙开发者实现富裕创意的 Android 相机利用,并在挪动利用的陆地中怀才不遇。如果您有趣味理解更多对于 CameraX 的内容,请参阅 官网文档,如果心愿可能继续取得 CameraX 的最新进展,能够退出 CameraX 讨论组。欢送大家提出宝贵意见,能够在 CameraX 讨论组 中和咱们交换,或者创立 CameraX issues 提交您遇到的问题。
相干浏览
- setExposureCompensationIndex API)
- ExposureState API
- CameraX 版本阐明
- Codelab: 上手应用 CameraX
- GitHub 示例
欢迎您 点击这里 向咱们提交反馈,或分享您喜爱的内容、发现的问题。您的反馈对咱们十分重要,感谢您的反对!