3. 直方图特征分析
直方图不只是个“图”。它背后藏着一堆数字特征,能告诉你图像的亮度分布、对比度强弱、纹理复杂程度。说白了,这些统计量就是图像的“体检报告”。
我个人习惯,拿到一张图先算这六个指标。它们能帮我快速判断:这张图是不是过曝了?是不是雾蒙蒙的?有没有细节可以挖?
3.1 均值(Mean)—— 图像的整体亮度
均值就是所有像素灰度的平均值。公式很简单:
μ = (1 / N) * Σ_{i=0}^{L-1} i * p(i)
其中 p(i) 是灰度 i 出现的概率,N 是总像素数,L 是灰度级数(通常是 256)。
- 均值偏小(< 80):图像偏暗,细节可能藏在暗部。
- 均值适中(80~170):亮度正常,视觉舒适。
- 均值偏大(> 170):图像偏亮,高光区域可能过曝。
我的经验: 均值只能反映“整体亮度”,不能说明对比度。一张灰蒙蒙的图和一张高对比的图,均值可能一模一样。所以别只看均值。
3.2 方差(Variance)—— 对比度的度量
方差衡量像素值偏离均值的程度。对比度越高,方差越大。
σ² = Σ_{i=0}^{L-1} (i - μ)² * p(i)
标准差 σ 是方差的平方根,单位与灰度一致,更直观。
| 方差范围 | 对比度描述 | 典型场景 |
|---|---|---|
| < 1000 | 低对比度,图像模糊 | 雾天、水下、老照片 |
| 1000 ~ 4000 | 中等对比度,正常 | 日常拍摄、监控画面 |
| > 4000 | 高对比度,层次分明 | 强光下、艺术摄影 |
注意: 方差过大不一定好。我曾经处理过一张工业检测图,方差很高,但暗部完全死黑、亮部完全过曝——细节全丢了。高方差不等于高质量。
3.3 偏度(Skewness)—— 亮度分布的对称性
偏度告诉你直方图是“左偏”还是“右偏”。
Skewness = (1 / σ³) * Σ_{i=0}^{L-1} (i - μ)³ * p(i)
- 偏度 > 0(右偏):直方图左侧有长尾,图像偏暗,暗部细节丰富。
- 偏度 < 0(左偏):直方图右侧有长尾,图像偏亮,高光区域多。
- 偏度 ≈ 0:直方图对称,亮度分布均匀。
为什么会这样?你想想看,如果大部分像素集中在暗部,少数像素在亮部,直方图就会向右拖出一条尾巴——这就是正偏度。
实用技巧: 偏度值 > 1 时,图像大概率存在曝光问题。这时候直方图均衡化往往效果不错。
3.4 峰度(Kurtosis)—— 分布的“尖峭”程度
峰度衡量直方图是“尖峰”还是“扁平”。
Kurtosis = (1 / σ⁴) * Σ_{i=0}^{L-1} (i - μ)⁴ * p(i) - 3
这里减 3 是为了让正态分布的峰度为 0,方便比较。
- 峰度 > 0(尖峰):像素集中在少数灰度级,图像纹理单一,比如纯色背景。
- 峰度 < 0(平峰):像素分布分散,纹理丰富,细节多。
- 峰度 ≈ 0:接近正态分布,自然图像常见。
我记得有一次做医学图像分析,CT 图像的峰度特别高——因为大部分像素集中在骨骼和空气两个灰度区间。这时候做增强,得小心别把噪声也放大了。
3.5 能量(Energy)—— 灰度分布的集中度
能量是各灰度概率的平方和。它反映直方图的“纯净度”。
Energy = Σ_{i=0}^{L-1} [p(i)]²
- 能量高(接近 1):少数灰度级占主导,图像简单,比如二值图。
- 能量低(接近 0):灰度分布均匀,图像复杂,纹理丰富。
避坑指南: 我曾经把能量和熵搞混过。记住:能量看“集中度”,熵看“混乱度”。两者是互补关系,不是一回事。
3.6 熵(Entropy)—— 图像的信息量
熵来自信息论,衡量直方图的不确定性。熵越大,图像包含的信息越丰富。
Entropy = - Σ_{i=0}^{L-1} p(i) * log₂[p(i)]
对于 8 位图像,熵的最大值是 8(所有灰度等概率出现)。
| 熵值范围 | 信息量描述 | 典型图像 |
|---|---|---|
| < 4 | 信息量低,图像简单 | 纯色背景、简单图形 |
| 4 ~ 7 | 信息量中等,正常 | 自然风景、人像 |
| > 7 | 信息量高,纹理复杂 | 遥感图像、密集纹理 |
嗯,这里要注意:熵高不一定好。噪声图像的熵也很高,但那是“无效信息”。所以熵要结合其他指标一起看。
3.7 六个特征的关系图谱
下面这张图帮你理清这六个指标的逻辑关系:
3.8 实战:用 Python 计算这些特征
光说不练假把式。下面这段代码,我经常在项目里直接复用:
import cv2
import numpy as np
def histogram_features(image):
# 计算直方图
hist = cv2.calcHist([image], [0], None, [256], [0, 256])
hist = hist.flatten()
prob = hist / hist.sum() # 归一化为概率
gray_levels = np.arange(256)
# 均值
mean = np.sum(gray_levels * prob)
# 方差
variance = np.sum((gray_levels - mean) ** 2 * prob)
# 偏度
skewness = np.sum((gray_levels - mean) ** 3 * prob) / (variance ** 1.5)
# 峰度
kurtosis = np.sum((gray_levels - mean) ** 4 * prob) / (variance ** 2) - 3
# 能量
energy = np.sum(prob ** 2)
# 熵
entropy = -np.sum(prob * np.log2(prob + 1e-10))
return {
'mean': mean,
'variance': variance,
'skewness': skewness,
'kurtosis': kurtosis,
'energy': energy,
'entropy': entropy
}
# 使用示例
img = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE)
features = histogram_features(img)
for key, value in features.items():
print(f"{key}: {value:.4f}")
核心要点: 这六个特征不是孤立的。均值 + 方差看亮度和对比度,偏度 + 峰度看分布形态,能量 + 熵看信息量。组合使用,才能全面评估图像质量。
嗯,以上就是直方图统计特征的完整分析。下次拿到一张图,先跑一遍这六个指标,你就能快速判断它“健不健康”了。