需求
YUV 夜景这类 HDR 效果的 SDK,需要不同 EV (Exposure Value)的输入。
踩坑
之前经验不够,获取不同 EV 是通过设置 iso 和 曝光时间来做的。ev0 的 iso 和曝光时间直接从预览拿到,然后在此基础上计算出 ev+ 和 ev- 的 iso 和曝光时间。计算方式是将 iso 和曝光时间乘以(或除以) 2。代码如下:
|
|
这种方式的缺点:
- App 上拿到的 ev0 的 iso 可能不是最终拍照时使用的 iso,经过平台代码处理后,可能还会乘以 sensor gain 值。这会导致我们计算出来的所有 ev 值都不准确。
- 不知道手机支持的 ev 范围。
- 直接设置 iso 和曝光时间来获取不同 ev 的输入也不是推荐的做法。
- 代码很难看。
更优雅的方式
更好的方式是直接使用设置 ev 的方式来获取不同 ev 的输入,而且可以通过相关接口来得知当前手机 APP 层支持的 ev 范围。(这个范围不是死的,客户可以扩展。)
当前 ROM 支持的 ev 范围
手机支持的 ev 范围可以通过下面这两个接口计算出:
CameraCharacteristics#CONTROL_AE_COMPENSATION_RANGE
CameraCharacteristics#CONTROL_AE_COMPENSATION_STEP
上面两个接口的含义可以直接看下官方文档的解释,解释的很清楚。简单来说手机支持的 ev 范围就是 CONTROL_AE_COMPENSATION_RANGE 给出的范围乘以 CONTROL_AE_COMPENSATION_STEP。
比如 RANGE 是 [-18, 18],STEP 是 1/6,那当前支持的 ev 范围是 [-3, 3]。
PS:如果最暗帧(比如上面例子中的 ev-3)还是不满足算法要求,比如高光细节不够等,就可以请客户协助扩展 RANGE,也就是扩展支持的 ev。
设置 ev
设置 ev 是通过设置 CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION 的值,需要注意的是,我们设置的不是手机支持的 ev 值,而是上面 CONTROL_AE_COMPENSATION_RANGE 给出的范围里面的值。还是上面的例子,如果我们要拍 ev+1,那么我们设置的值就应该是 1/(1/6) = 6,以此类推 ev+2 就是设置 12,所以当你发现 ev+1 不够亮而 ev+2 又太亮时,其实还可以把 ev 设置为 6 ~ 12 间的任意值,都是支持的。
来看下代码:
|
|
利用 calculateAECompensation
函数我们将平时我们说的 ev+1,ev0,ev-1 转换成对应需要设置的值:
|
|
隔帧取
在我们设置了 ev 之后,并不是立马就会生效的,它有一个收敛过程,所以我们需要隔帧取。
比如我们需要 3 张 ev+1,3 张 ev0,3 张 ev-2, 3 张 ev-4 共 12 张。我们不能只下发 12 个 request(这样的话我们拿到的输入图 ev 可能不对),而是需要下发 16 个 request。具体做法是每个 ev 档位我们都多拍一张,图片来的时候,又丢弃掉每个 ev 档位的第一张。在这个例子也就是下发 4 张 ev+1,4 张 ev0,4 张 ev-2, 4 张 ev-4 共 16 张。然后当图片到来时,丢弃掉第 1 张 ev+1,第 1 张 ev0,第 1 张 ev-1,第 1 张 ev-2。
|
|
高通 camx 和非 camx 架构的设置 ev 值的差异
另外在 camx 和非 camx 架构上设置 ev 时也有一个差异。
细心的同学可能已经发现了,上面的代码中有一个 if 判断:
|
|
这个是非 camx 架构设置 ev 的方式,即我们只设置每组 ev 第一张的 ev 值。还是上面的例子,我们在第一张 ev+1 的 request 中设置它的 ev 为 +1,后续三张 ev+1 不需要再设置 ev 值。接着我们在第一张 ev0 的 request 中设置它的 ev 为 0,后续三张 ev0 不需要再设置 ev 值。以此类推。原因是在非 camx 框架上,每一次设置 ev 值都会有收敛过程,所以我们只需要设置每组 ev 第一张的 ev 值。如果每张都设置它的 ev 值,拍出来的图会发现同一组 ev 亮度会不一样。
在 camx 新架构的平台上,设置 ev 是直接就生效的,所以需要设置每一张的 ev 值,不再需要判断是否是每组 ev 的第一张:
|
|
注意:经过项目上验证,camx 和非 camx 架构都需要上一节提到过的隔帧取。
全文完
感谢阅读