3. 神经网络自动曝光控制
任务说明
本案例需要构建一个轻量级回归模型,输入为场景亮度特征(平均亮度、亮度标准差、暗部比例),输出为最佳曝光参数(曝光时间、模拟增益)。模型训练完成后,通过模拟曝光调整流程,验证模型预测的曝光参数能否将图像亮度拉至目标区间。
实现方案
使用PyTorch搭建三层全连接回归网络,生成模拟场景亮度数据作为训练集。曝光参数预测采用归一化输出,通过模拟曝光函数(线性增益模型)将预测参数作用于输入图像,计算调整后亮度与目标亮度的误差作为评估指标。
完整代码
import torch
import torch.nn as nn
import numpy as np
# ---------- 1. 数据生成 ----------
def generate_scene_data(num_samples=2000):
"""生成模拟场景亮度特征: [平均亮度, 亮度标准差, 暗部比例]"""
np.random.seed(42)
avg_lum = np.random.uniform(10, 200, num_samples) # 平均亮度 10~200
std_lum = np.random.uniform(5, 60, num_samples) # 亮度标准差
dark_ratio = np.random.uniform(0.05, 0.8, num_samples) # 暗部像素比例
# 模拟最佳曝光参数: 曝光时间(ms) 与 增益(线性)
# 目标亮度约为120, 曝光参数与当前亮度成反比关系
target_lum = 120.0
exp_time = np.clip(target_lum / avg_lum * 16.0, 1.0, 100.0) # 基准16ms
gain = np.clip(target_lum / (avg_lum * exp_time / 16.0), 1.0, 8.0)
features = np.stack([avg_lum, std_lum, dark_ratio], axis=1)
labels = np.stack([exp_time, gain], axis=1)
return features.astype(np.float32), labels.astype(np.float32)
# ---------- 2. 回归模型 ----------
class ExposureRegressor(nn.Module):
def __init__(self, input_dim=3, hidden_dim=64):
super().__init__()
self.net = nn.Sequential(
nn.Linear(input_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, 2) # 输出: [曝光时间, 增益]
)
def forward(self, x):
return self.net(x)
# ---------- 3. 模拟曝光调整 ----------
def simulate_exposure(image, exp_time_ms, gain):
"""模拟曝光调整: 线性亮度缩放"""
base_time = 16.0 # 基准曝光时间
scale = (exp_time_ms / base_time) * gain
adjusted = np.clip(image * scale, 0, 255)
return adjusted
def evaluate_exposure(image, exp_time_ms, gain, target_lum=120.0):
"""评估曝光效果: 返回调整后平均亮度与目标亮度误差"""
adjusted = simulate_exposure(image, exp_time_ms, gain)
actual_lum = np.mean(adjusted)
return abs(actual_lum - target_lum), adjusted
# ---------- 4. 训练流程 ----------
def train_model():
features, labels = generate_scene_data()
X = torch.tensor(features)
y = torch.tensor(labels)
model = ExposureRegressor()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
loss_fn = nn.MSELoss()
dataset = torch.utils.data.TensorDataset(X, y)
loader = torch.utils.data.DataLoader(dataset, batch_size=64, shuffle=True)
for epoch in range(100):
total_loss = 0
for batch_x, batch_y in loader:
optimizer.zero_grad()
pred = model(batch_x)
loss = loss_fn(pred, batch_y)
loss.backward()
optimizer.step()
total_loss += loss.item()
if (epoch+1) % 20 == 0:
print(f"Epoch {epoch+1}, Loss: {total_loss/len(loader):.4f}")
return model
# ---------- 5. 验证与模拟 ----------
def verify_exposure_control(model):
"""使用测试场景验证曝光控制效果"""
# 构造3个典型场景: 暗场景, 正常场景, 亮场景
test_scenes = [
np.full((64, 64), 30.0), # 暗场景: 平均亮度30
np.full((64, 64), 100.0), # 正常场景: 平均亮度100
np.full((64, 64), 180.0), # 亮场景: 平均亮度180
]
print("\n=== 曝光控制验证 ===")
for i, scene in enumerate(test_scenes):
avg = np.mean(scene)
std = np.std(scene)
dark_ratio = np.mean(scene < 50)
feat = torch.tensor([[avg, std, dark_ratio]])
with torch.no_grad():
pred = model(feat).numpy()[0]
exp_time, gain = pred
error, adjusted = evaluate_exposure(scene, exp_time, gain)
print(f"场景{i+1}: 原始亮度={avg:.1f}, "
f"预测曝光时间={exp_time:.2f}ms, 增益={gain:.2f}, "
f"调整后亮度={np.mean(adjusted):.1f}, 目标误差={error:.2f}")
if __name__ == "__main__":
model = train_model()
verify_exposure_control(model)
运行与验证
运行方式:直接执行 python exposure_control.py(需已安装 torch 与 numpy)。
验证方法:程序会输出训练损失下降过程,并在验证阶段打印三个典型场景的预测曝光参数与调整后亮度误差。
通过标准:训练损失收敛至0.01以下;三个测试场景调整后亮度与目标亮度120的误差均小于15(即调整后亮度在105~135范围内),说明模型能根据场景亮度预测合理曝光参数并完成模拟调整。