第4章 · 亮度与曝光
图像亮度定义 · 直方图分析 · 曝光过度与不足的识别
1. 图像亮度定义
在数字图像中,亮度(Luminance)通常指像素的灰度强度,范围从 0(纯黑)到 255(纯白)。对于彩色图像,亮度可通过加权转换得到:
亮度公式(ITU-R BT.601):
Y = 0.299 · R + 0.587 · G + 0.114 · B
Y = 0.299 · R + 0.587 · G + 0.114 · B
亮度是曝光控制的核心指标。摄像头实时调整时,通常将平均亮度映射到目标区间(如 100~150)。
2. 直方图分析
直方图展示图像中每个灰度级出现的频率。横轴为灰度值 (0~255),纵轴为像素计数。通过直方图可快速判断曝光状态:
| 直方图形态 | 曝光状态 | 典型场景 |
|---|---|---|
| 数据集中在左侧 (0~60) | 曝光不足 | 暗光、逆光、低照度 |
| 数据集中在右侧 (200~255) | 曝光过度 | 强光、过曝、高反光 |
| 分布均匀,覆盖全范围 | ✅ 正常曝光 | 良好光照 |
| 中间凸起,两侧极少 | 低对比度 / 灰雾 | 雾天、均匀光照 |
3. 曝光过度与不足的识别
基于直方图统计,定义两个关键指标:
- 过曝比率:像素值 > 230 的像素占比 > 15% 视为过曝。
- 欠曝比率:像素值 < 25 的像素占比 > 20% 视为欠曝。
以下 Python 代码使用 OpenCV 计算直方图并判断曝光状态:
import cv2
import numpy as np
def analyze_exposure(image):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
hist = cv2.calcHist([gray], [0], None, [256], [0, 256])
total = gray.size
under = np.sum(hist[:25]) / total
over = np.sum(hist[230:]) / total
status = "正常"
if under > 0.20:
status = "曝光不足"
elif over > 0.15:
status = "曝光过度"
return status, under, over
# 示例调用
img = cv2.imread('frame.jpg')
status, u, o = analyze_exposure(img)
print(f"曝光状态: {status} (欠曝 {u:.1%}, 过曝 {o:.1%})")
4. 实战:直方图可视化与曝光告警
在实时视频流中,每帧计算直方图并绘制亮度分布,同时标注曝光状态:
def draw_exposure_overlay(frame):
status, under, over = analyze_exposure(frame)
color = (0, 255, 0) if status == "正常" else (0, 0, 255)
cv2.putText(frame, f"Exposure: {status}", (20, 40),
cv2.FONT_HERSHEY_SIMPLEX, 1, color, 2)
# 绘制简易直方图 (略)
return frame
💡 提示: 曝光不足时优先增加曝光时间或增益;曝光过度时降低曝光时间或光圈。结合直方图动态调整,可实现无级自适应。