2. AE基础
任务目标
本案例实现一个基于直方图统计的场景亮度分类器:输入一张图像的灰度直方图(或直接输入图像),根据暗区比例、亮区比例及动态范围特征,将场景分类为低照度、正常或高动态(HDR)三类,并输出分类结果及关键统计量。
实现方案
分类逻辑基于以下直方图特征:
- 暗区比例:灰度值 < 64 的像素占比(8bit图像)
- 亮区比例:灰度值 > 192 的像素占比
- 动态范围:直方图有效灰度跨度(从第1百分位到第99百分位的宽度)
判定规则:
- 若暗区比例 > 0.5 → 低照度
- 若亮区比例 > 0.5 → 正常(高调场景),但若同时动态范围极大则归为HDR
- 若动态范围 > 180 且暗区与亮区比例均 > 0.15 → 高动态(HDR)
- 其余情况 → 正常
完整代码
import numpy as np
def classify_scene(hist, bins=256):
"""
基于直方图统计的场景亮度分类器
参数:
hist: 归一化直方图数组(长度为bins,元素为概率密度,和为1)
bins: 灰度级数(默认256,灰度范围0~255)
返回:
dict: 包含分类结果和关键统计量
"""
if len(hist) != bins:
raise ValueError(f"直方图长度必须为{bins}")
if abs(np.sum(hist) - 1.0) > 1e-3:
raise ValueError("直方图必须归一化(和为1)")
# 灰度级坐标
gray_levels = np.arange(bins)
# 1. 暗区/亮区比例(以8bit为例:暗区<64,亮区>192)
dark_thresh = int(64 * bins / 256)
bright_thresh = int(192 * bins / 256)
dark_ratio = np.sum(hist[:dark_thresh])
bright_ratio = np.sum(hist[bright_thresh:])
# 2. 动态范围:第1百分位到第99百分位的灰度跨度
cdf = np.cumsum(hist)
p1 = gray_levels[np.searchsorted(cdf, 0.01)]
p99 = gray_levels[np.searchsorted(cdf, 0.99)]
dynamic_range = p99 - p1
# 3. 分类决策
if dark_ratio > 0.5:
scene_type = "低照度"
elif bright_ratio > 0.5 and dynamic_range < 180:
scene_type = "正常"
elif dynamic_range > 180 and dark_ratio > 0.15 and bright_ratio > 0.15:
scene_type = "高动态(HDR)"
else:
scene_type = "正常"
return {
"scene_type": scene_type,
"dark_ratio": round(float(dark_ratio), 4),
"bright_ratio": round(float(bright_ratio), 4),
"dynamic_range": int(dynamic_range),
"p1_gray": int(p1),
"p99_gray": int(p99)
}
def classify_image_gray(gray_img):
"""直接输入灰度图(0~255 uint8)进行分类"""
hist, _ = np.histogram(gray_img, bins=256, range=(0, 256), density=True)
return classify_scene(hist)
# ===== 最小验证示例 =====
if __name__ == "__main__":
# 构造三种典型场景的模拟直方图(归一化)
# 低照度:大部分像素集中在暗区
hist_low = np.zeros(256)
hist_low[:60] = 1.0 / 60
# 正常:像素均匀分布在中灰区域
hist_normal = np.zeros(256)
hist_normal[80:180] = 1.0 / 100
# 高动态:暗区和亮区各占较大比例
hist_hdr = np.zeros(256)
hist_hdr[:50] = 0.3 / 50
hist_hdr[200:] = 0.3 / 56
hist_hdr[80:120] = 0.4 / 40
for name, h in [("低照度模拟", hist_low),
("正常模拟", hist_normal),
("HDR模拟", hist_hdr)]:
result = classify_scene(h)
print(f"{name}: {result}")
运行与验证
运行方式:直接执行脚本(需安装NumPy):
python ae_histogram_classifier.py
预期输出:(由代码逻辑直接推出)
低照度模拟: {'scene_type': '低照度', 'dark_ratio': 1.0, 'bright_ratio': 0.0, 'dynamic_range': 59, 'p1_gray': 0, 'p99_gray': 59}
正常模拟: {'scene_type': '正常', 'dark_ratio': 0.0, 'bright_ratio': 0.0, 'dynamic_range': 99, 'p1_gray': 81, 'p99_gray': 180}
HDR模拟: {'scene_type': '高动态(HDR)', 'dark_ratio': 0.3, 'bright_ratio': 0.3, 'dynamic_range': 206, 'p1_gray': 0, 'p99_gray': 255}
验证方法:运行后观察输出是否与上述一致。若需验证真实图像,将图像转为灰度图后调用classify_image_gray(),观察分类结果是否符合主观判断。
关键说明
- 直方图输入必须已归一化(概率密度和为1),代码内部会做校验。
- 阈值(64/192)和比例阈值(0.5/0.15)为经验值,实际ISP集成时需根据传感器特性标定。
- 动态范围采用1%~99%百分位跨度,可避免单像素噪声导致的误判。