相机曝光
曝光(Exposure)= 传感器接收的光量
影响曝光的因素主要有三项:
-
曝光时间(Exposure Time / Shutter) — 像素采集光的时间,越长越亮。
-
增益(Gain / ISO) — 电路放大信号,越高越亮,但噪点越大。
-
光圈(Aperture) — UVC USB 摄像头一般 没有可变光圈,所以不考虑
| 名称 | 英文 | 控制对象 | 物理含义 | 影响效果 | 对应 Camera2 | 对应 V4L2(UVC) |
|---|---|---|---|---|---|---|
| 曝光时间 | Exposure Time / Shutter | 时间 | 图像传感器曝光光的时长 | 亮度变化大、动态模糊 | ANDROID_SENSOR_EXPOSURE_TIME(单位 ns) |
V4L2_CID_EXPOSURE_ABSOLUTE(单位 100µs) |
| 曝光增益 | ISO / Gain | 电子放大 | 把传感器采集的信号放大 | 亮度增加但噪点变多 | ANDROID_SENSOR_SENSITIVITY |
V4L2_CID_GAIN 或 V4L2_CID_ISO_SENSITIVITY |
| 曝光补偿 | EV Compensation | 自动曝光算法 | 让 AE(自动曝光)往亮/暗偏移 | AE 自动调节曝光时间和增益 | ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION |
一般没有(UVC 几乎不支持) |
自动曝光 VS 手动曝光
| 对比项 | 自动曝光(AE) | 手动曝光(Manual Exposure) |
|---|---|---|
| 曝光控制方式 | 由摄像头 ISP 或 UVC 固件根据画面亮度动态调节曝光时间 + 增益 | 程序员直接设置曝光时间(shutter)和增益(gain/ISO) |
| 亮度稳定性 | 低,亮度随着场景变化波动 | 极高,亮度稳定不变 |
| 响应光线变化 | 快速 or 慢(UVC 常常慢) | 不响应外界光线变化,完全固定 |
| 适用场景 | 视频聊天、拍照、直播、一般预览 | OCR(快递面单)、条码、工业视觉、机器人 |
| UVC 支持情况 | 100% 支持(所有相机必须支持 AE) | 有些 UVC 摄像头不支持 manual,尤其是廉价方案 |
| Android Camera2 支持情况 | CONTROL_AE_MODE_ON 即可 |
需要 CONTROL_AE_MODE_OFF + 设置 SENSOR_EXPOSURE_TIME 和 SENSOR_SENSITIVITY |
| 调节参数 | AE bias、AE compensation | shutter、gain、frame duration |
| 对画面噪点影响 | 动态变化,光线弱时噪点暴增 | 你自行控制 gain,噪点可控 |
| 抗闪烁能力(50/60Hz) | AE 可能出现明暗跳动(尤其在 LED 灯下) | 可固定曝光到频率整数倍,彻底避免闪烁 |
| 白平衡(AWB)依赖 | AE 调节会影响 AWB 曲线 | 独立于曝光,画面更稳定 |
| 亮度跳变现象 | 常见(快/暗场景切换时特别明显) | 完全无,亮度不会突然变化 |
| 曝光过程平滑性 | ISP 硬件决定,有时出现“呼吸效应” | 无呼吸效应,因为曝光不变 |
| 帧率影响 | AE 可能降低帧率(为提高亮度自动拉长曝光) | 可强制锁定 FPS,不被曝光干扰 |
| 逆光场景表现 | 背光严重时整体变暗或人物过曝 | 固定曝光但可能欠曝,需要补光 |
| 算法适配难度(AI 识别) | 难,模型输入亮度变化大 | 极低,模型输入稳定一致 |
| 开发复杂度 | 简单 | 中等,需要调曝光参数 |
| 调试成本 | 低 | 需要用示波仪/光功率计或反复拍照调参 |
| 对机器视觉的价值 | ❌ 不推荐,容易导致识别不稳定 | ✔ 强烈推荐,识别成功率大幅提升 |
| 在你 UVC 崩溃场景中 | AE 高频调节可能导致驱动压力变大 | 手动更稳定,一般不会触发频繁 ioctl |
| 在光线非常弱时 | AE 会自动把 gain 调得很高(噪点爆炸) | 你可以限制 gain 上限,牺牲亮度换质量 |
| 是否可冻结曝光 | AE 模式不能冻结(即使 lock 也会部分变化) | 完全冻结 |
| 是否需要 ISP 支持 | 需要 | 不需要 |
| 适合的相机参数文件(PID/VID) | 普通摄像头即可 | 推荐有手动曝光控件的 UVC 摄像头 |
| 是否影响自动对焦(AF) | AE 变化会让 AF 算法误判 | 手动曝光更适合固定焦距摄像头 |
RK3568 dumpsys camera
rk3568_r:/ $ dumpsys media.camera | grep -A 1 ae
android.control.aeAvailableAntibandingModes (10012): byte[1]
[3 ] # 支持的抗频闪模式只有一种:3 = AUTO(自动抗频闪)
--
android.control.aeAvailableModes (10013): byte[1]
[1 ] # 仅支持 AE_MODE_ON(自动曝光),不支持手动曝光(AE=OFF)
--
android.control.aeCompensationRange (10015): int32[2]
[0 0 ] # 曝光补偿范围固定为 0~0,表示不支持曝光补偿(EV 调节无效)
android.control.aeCompensationStep (10016): rational[1]
[(0 / 1) ] # 曝光补偿步进为 0,进一步说明 EV 功能完全不可用
--
android.control.aeLockAvailable (10024): byte[1]
[FALSE ] # 不支持 AE 锁定(无法锁住自动曝光,亮度会一直自动变化)
--
android.control.aeAvailableTargetFpsRanges (10014): int32[12]
[1 2 1 3 ] # FPS 范围异常(正常应为 15–30、30–30 等),说明相机未正确上报帧率能力
RK3568 上 Camera HAL 对外接 UVC 相机只开放了自动曝光(AE_MODE_ON),没有开放手动曝光和 AE 锁定功能,而不是摄像头本身完全不支持手动曝光
Camera HAL
rk3568_android_11/hardware/interfaces/camera$ adb shell dumpsys media.camera | grep "== Camera"
== Camera Provider HAL legacy/0 (v2.5, remote) static info: 0 devices: ==
== Camera Provider HAL external/0 (v2.5, remote) static info: 1 devices: ==
== Camera HAL device device@3.4/external/100 (v3.4) static information: ==
== Camera HAL device device@3.4/external/100 (v3.4) dumpState: ==
lxg@lxg:~/code/project/rk3568_android_11/hardware/interfaces/camera$ tree -L 2
.
├── common
│ ├── 1.0
│ └── README.md
├── device
│ ├── 1.0
│ ├── 3.2
│ ├── 3.3
│ ├── 3.4
│ ├── 3.5
│ ├── 3.6
│ └── README.md
├── metadata
│ ├── 3.2
│ ├── 3.3
│ ├── 3.4
│ │ ├── Android.bp
│ │ ├── default
│ │ │ ├── Android.bp
│ │ │ ├── Android.go
│ │ │ ├── CameraDevice.cpp
│ │ │ ├── CameraDeviceSession.cpp
│ │ │ ├── convert.cpp
│ │ │ ├── ExternalCameraDevice.cpp
│ │ │ ├── ExternalCameraDeviceSession.cpp
│ │ │ ├── ExternalCameraGralloc4.cpp
│ │ │ ├── ExternalCameraGralloc.cpp
│ │ │ ├── ExternalCameraMemManager.cpp
│ │ │ ├── ExternalCameraUtils.cpp
│ │ │ ├── ExternalFakeCameraDevice.cpp
│ │ │ ├── ExternalFakeCameraDeviceSession.cpp
│ │ │ ├── include
│ │ │ │ ├── convert.h
│ │ │ │ ├── device_v3_4_impl
│ │ │ │ ├── ext_device_v3_4_impl
│ │ │ │ └── vpu_inc
│ │ │ ├── OWNERS
│ │ │ ├── RgaCropScale.cpp
│ │ │ └── rkvpu_dec_api.cpp
│ │ ├── ICameraDeviceCallback.hal
│ │ ├── ICameraDeviceSession.hal
│ │ └── types.hal
│ ├── 3.5
│ └── README.md
├── provider
│ ├── 2.4
│ ├── 2.5
│ │ ├── Android.bp
│ │ ├── default
│ │ │ ├── Android.bp
│ │ │ ├── android.hardware.camera.provider@2.5-external-service.rc
│ │ │ ├── android.hardware.camera.provider@2.5-service_64.rc
│ │ │ ├── android.hardware.camera.provider@2.5-service-lazy_64.rc
│ │ │ ├── android.hardware.camera.provider@2.5-service-lazy.rc
│ │ │ ├── android.hardware.camera.provider@2.5-service.rc
│ │ │ ├── CameraProvider_2_5.h
│ │ │ ├── ExternalCameraProviderImpl_2_5.cpp
│ │ │ ├── ExternalCameraProviderImpl_2_5.h
│ │ │ ├── external-service.cpp
│ │ │ ├── LegacyCameraProviderImpl_2_5.cpp
│ │ │ ├── LegacyCameraProviderImpl_2_5.h
│ │ │ ├── OWNERS
│ │ │ └── service.cpp
│ │ ├── ICameraProvider.hal
│ │ └── types.hal
│ ├── 2.6
│ └── README.md
└── README.md
| HAL 类型 | 版本 | 源码目录 |
|---|---|---|
| Camera Provider HAL | 2.5 | hardware/interfaces/camera/provider/2.5/default/ExternalCameraProviderImpl_2_5.cpp |
| Camera Device HAL | 3.4 | hardware/interfaces/camera/metadata/3.4/default/ExternalCameraDevice.cpp (USB/外部摄像头实现) |
源码中曝光配置
| 函数 | 作用 |
|---|---|
initDefaultCharsKeys |
默认值/模式,比如 AE、AWB 默认开启 |
initCameraControlsCharsKeys |
静态特性,硬件支持什么,比如 ISO/曝光范围 |
initOutputCharsKeys |
输出能力,如分辨率、帧率、format |
initAvailableCapabilities |
Camera API 可用能力列表,告知上层支持哪些模式(RAW/JPEG/Video) |
status_t ExternalCameraDevice::initCameraCharacteristics() {
if (mCameraCharacteristics.isEmpty()) {
// init camera characteristics
unique_fd fd(::open(mDevicePath.c_str(), O_RDWR));
if (fd.get() < 0) {
ALOGE("%s: v4l2 device open %s failed", __FUNCTION__, mDevicePath.c_str());
return DEAD_OBJECT;
}
status_t ret;
ret = initDefaultCharsKeys(&mCameraCharacteristics);
if (ret != OK) {
ALOGE("%s: init default characteristics key failed: errorno %d", __FUNCTION__, ret);
mCameraCharacteristics.clear();
return ret;
}
ret = initCameraControlsCharsKeys(fd.get(), &mCameraCharacteristics);
if (ret != OK) {
ALOGE("%s: init camera control characteristics key failed: errorno %d", __FUNCTION__, ret);
mCameraCharacteristics.clear();
return ret;
}
ret = initOutputCharsKeys(fd.get(), &mCameraCharacteristics);
if (ret != OK) {
ALOGE("%s: init output characteristics key failed: errorno %d", __FUNCTION__, ret);
mCameraCharacteristics.clear();
return ret;
}
ret = initAvailableCapabilities(&mCameraCharacteristics);
if (ret != OK) {
ALOGE("%s: init available capabilities key failed: errorno %d", __FUNCTION__, ret);
mCameraCharacteristics.clear();
return ret;
}
}
return OK;
}
status_t ExternalCameraDevice::initDefaultCharsKeys(
::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
const uint8_t hardware_level = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL;
UPDATE(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, &hardware_level, 1);
// android.control
const uint8_t antibandingMode =
ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;
UPDATE(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
&antibandingMode, 1);
const int32_t controlMaxRegions[] = {/*AE*/ 0, /*AWB*/ 0, /*AF*/ 0};
UPDATE(ANDROID_CONTROL_MAX_REGIONS, controlMaxRegions,
ARRAY_SIZE(controlMaxRegions));
const uint8_t aeAvailableMode = ANDROID_CONTROL_AE_MODE_ON;
UPDATE(ANDROID_CONTROL_AE_AVAILABLE_MODES, &aeAvailableMode, 1);
}
status_t ExternalCameraDevice::initCameraControlsCharsKeys(int,
::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
// android.control
// No AE compensation support for now.
// TODO: V4L2_CID_EXPOSURE_BIAS
const int32_t controlAeCompensationRange[] = {0, 0};
UPDATE(ANDROID_CONTROL_AE_COMPENSATION_RANGE, controlAeCompensationRange,
ARRAY_SIZE(controlAeCompensationRange));
const camera_metadata_rational_t controlAeCompensationStep[] = 0;
UPDATE(ANDROID_CONTROL_AE_COMPENSATION_STEP, controlAeCompensationStep,
ARRAY_SIZE(controlAeCompensationStep));
}
| 函数 | 作用 | 影响曝光的地方 |
|---|---|---|
initDefaultCharsKeys |
初始化默认相机特性、模式 | 设置 ANDROID_CONTROL_AE_AVAILABLE_MODES = ON,表示自动曝光默认开启。它只告诉上层“AE模式可用”,但不包含范围信息。 |
initCameraControlsCharsKeys |
初始化硬件控制能力(静态信息) | 设置 ANDROID_CONTROL_AE_COMPENSATION_RANGE = {0,0} 和 AE_COMPENSATION_STEP = {0,1},告诉上层没有手动曝光能力。 |
曝光设置流程图
[Camera App / Camera2 API]
|
| setExposureCompensation / setAeMode
v
[Camera Framework (CameraService / CameraDevice)]
|
| 读取 CameraMetadata
| AE mode: ON
| AE compensation range: 0~0 (不支持手动曝光)
v
[ExternalCameraDevice HAL]
|
| initDefaultCharsKeys() -> 设置 AE mode ON
| initCameraControlsCharsKeys() -> AE compensation range {0,0}
| 接收到 setExposureCompensation 时:
| 如果 range={0,0} -> 忽略,无法修改
v
[V4L2 Driver / /dev/videoX]
|
| V4L2_CID_EXPOSURE_ABSOLUTE 或 V4L2_CID_EXPOSURE_AUTO
| 如果 HAL 没映射 -> 硬件曝光无法修改
v
[Camera Sensor Hardware]
判断摄像头是否支持手动曝光
| 控制名 | 类型 | 值 | 说明 |
|---|---|---|---|
exposure_auto |
menu | min=0 max=3 default=3 value=3 | 自动曝光模式,常见值: 0=关闭,1=自动,2=快门优先,3=光圈优先(或者厂商定义) |
exposure_absolute |
int | min=50 max=10000 step=1 default=166 value=166 flags=inactive | 曝光时间(单位通常为 100µs 或 µs,具体看驱动),目前 inactive,说明当前 exposure_auto 没关闭 |
exposure_auto_priority |
bool | default=0 value=0 | AE 优先级控制 |
1|rk3568_r:/ # v4l2-ctl --all -d /dev/video0
Driver Info:
Driver name : uvcvideo
Card type : USB Camera:
Bus info : usb-fd880000.usb-1
Driver version : 4.19.255
Capabilities : 0x84a00001
Video Capture
Metadata Capture
Streaming
Extended Pix Format
Device Capabilities
Device Caps : 0x04200001
Video Capture
Streaming
Extended Pix Format
Media Driver Info:
Driver name : uvcvideo
Model : USB Camera:
Serial : 200901010001
Bus info : usb-fd880000.usb-1
Media version : 4.19.255
Hardware revision: 0x00000007 (7)
Driver version : 4.19.255
Interface Info:
ID : 0x03000002
Type : V4L Video
Entity Info:
ID : 0x00000001 (1)
Name : USB Camera:
Function : V4L2 I/O
Pad 0x01000007 : Sink
Link 0x02000010: from remote pad 0x100000a of entity 'Extension 4': Data, Enabled, Immutable
Priority: 2
Video input : 0 (Camera 1: ok)
Format Video Capture:
Width/Height : 1920/1080
Pixel Format : 'MJPG'
Field : None
Bytes per Line : 0
Size Image : 4147200
Colorspace : sRGB
Transfer Function : Default (maps to sRGB)
YCbCr/HSV Encoding: Default (maps to ITU-R 601)
Quantization : Default (maps to Full Range)
Flags :
Crop Capability Video Capture:
Bounds : Left 0, Top 0, Width 1920, Height 1080
Default : Left 0, Top 0, Width 1920, Height 1080
Pixel Aspect: 1/1
Selection: crop_default, Left 0, Top 0, Width 1920, Height 1080, Flags:
Selection: crop_bounds, Left 0, Top 0, Width 1920, Height 1080, Flags:
Streaming Parameters Video Capture:
Capabilities : timeperframe
Frames per second: 30.000 (30/1)
Read buffers : 0
brightness 0x00980900 (int) : min=-64 max=64 step=1 default=0 value=0
contrast 0x00980901 (int) : min=0 max=100 step=1 default=50 value=50
saturation 0x00980902 (int) : min=0 max=100 step=1 default=64 value=64
hue 0x00980903 (int) : min=-180 max=180 step=1 default=0 value=0
white_balance_temperature_auto 0x0098090c (bool) : default=1 value=1
gamma 0x00980910 (int) : min=100 max=500 step=1 default=300 value=320
power_line_frequency 0x00980918 (menu) : min=0 max=2 default=1 value=1
white_balance_temperature 0x0098091a (int) : min=2800 max=6500 step=10 default=4600 value=4600 flags=inactive
sharpness 0x0098091b (int) : min=0 max=100 step=1 default=55 value=50
backlight_compensation 0x0098091c (int) : min=0 max=2 step=1 default=0 value=0
exposure_auto 0x009a0901 (menu) : min=0 max=3 default=3 value=3
exposure_absolute 0x009a0902 (int) : min=50 max=10000 step=1 default=166 value=166 flags=inactive
exposure_auto_priority 0x009a0903 (bool) : default=0 value=0
pan_absolute 0x009a0908 (int) : min=-57600 max=57600 step=3600 default=0 value=0
tilt_absolute 0x009a0909 (int) : min=-43200 max=43200 step=3600 default=0 value=0
zoom_absolute 0x009a090d (int) : min=0 max=3 step=1 default=0 value=0
可以看出当前摄像头是支持手动曝光的, 但是不支持曝光增益和曝光补偿
| 控制类别 | 是否支持 | 说明 |
|---|---|---|
| 曝光时间(Shutter) | ✔ 支持 | exposure_absolute 可调(前提:auto=1) |
| 曝光增益(ISO / Gain) | ❌ 不支持 | 控件列表中无相关控制 |
| 曝光补偿(EV) | ❌ 不支持 | 无 V4L2_CID_EXPOSURE_COMPENSATION |
手动关闭自动曝光时间
rk3568_r:/ # v4l2-ctl -d /dev/video0 -c exposure_auto=1
rk3568_r:/ # v4l2-ctl --all -d /dev/video0
exposure_auto 0x009a0901 (menu) : min=0 max=3 default=3 value=1
exposure_absolute 0x009a0902 (int) : min=50 max=10000 step=1 default=166 value=995 //可以看到变化了
exposure_auto_priority 0x009a0903 (bool) : default=0 value=0
最终修改方案
commit f90a45717a69ca6f8d694449e631623690cb748e (HEAD -> main_k5_wif)
Author: lxg <xiaogang.li>
Date: Wed Dec 10 13:42:49 2025 +0800
支持手动设置曝光
hardware/interfaces/camera/device/3.4/default/ExternalCameraDevice.cpp | 54 +++++++++++++++++++++++++++++++++++++++---
hardware/interfaces/camera/device/3.4/default/ExternalCameraDeviceSession.cpp | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
hardware/interfaces/camera/device/3.4/default/ExternalFakeCameraDevice.cpp | 56 +++++++++++++++++++++++++++++++++++++++++---
hardware/interfaces/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h | 4 ++++
hardware/interfaces/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession_3.4.h | 4 ++++
hardware/interfaces/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h | 2 ++
6 files changed, 215 insertions(+), 6 deletions(-)