拓冰建站拓冰建站
首页 / 资讯中心 / 正文

图像质量评价三指标:平均梯度、信息熵、标准差原理与Python实现

简介面向图像处理学习者和科研人员的图像质量评价工具包围绕平均梯度、信息熵、标准差、清晰度等核心指标提供可直接运行的算法脚本可用于图像融合、压缩、去噪等处理效果的快速评估。压缩包共十二个文件含十一个脚本与一份说明文档脚本覆盖梯度计算、香农熵、标准差、均值、清晰度及综合评价等典型环节整体仅五KB轻量易读说明文档对模块用途做了简要交代。目前已有七百七十八人学习下载。通过阅读这些脚本能够理解各指标的计算逻辑和适用场景掌握融合图像质量对比与评价标准选用的实践方法脚本结构简洁便于初学者巩固理论也方便研究者直接复用或二次开发搭建自己的评价基线。这一套资料将理论指标与实际计算衔接起来可有效支撑课程实验、论文验证或工程测试中的质量评估需求。1. 图像质量评价.zip 的敲门砖为什么大家都先算梯度、熵和标准差拿到一个名为「图像质量评价」的工具包最常见的三个函数名准是 average_gradient、information_entropy 和 standard_deviation。做融合对比、超分重建评测时这三项指标总在结果表第一行分别对应人眼最在意的事边缘清不清晰、灰度层次丰不丰富、画面有没有对比度。三者放一起就能把「这张图行不行」翻译成三个可比较的数值。但多数人只把脚本当黑盒差分方向怎么取、熵的 log 底数用几、标准差除 N 还是 N-1换一个脚本结论就对不上。这篇笔记把定义、Python 实现和融合评价里的用法逐个拆开用最小可复现脚本把每一步讲清楚。读完后你不仅能把 zip 里的脚本改造成自己的工具还能回答「为什么我的融合图熵值最高但看着最差」这类让人卡壳的问题。适合被审稿人追问指标计算方式的人也适合需要给融合算法写验收脚本的工程师。2. 平均梯度、信息熵、标准差的数学定义与判读逻辑2.1 平均梯度一阶差分逼近清晰度平均梯度Average Gradient度量的是图像边缘的锐利程度。它的思路很朴素清晰图像相邻像素变化大模糊图像相邻像素变化小用一阶差分把这种变化量化出来。对 M×N 的灰度图 I先求水平差分 ΔIx(i,j) I(i, j1) - I(i, j) 和垂直差分 ΔIy(i,j) I(i1, j) - I(i, j)再对每个像素求梯度幅值最后取平均AG 1/((M-1)(N-1)) · Σ √( (ΔIx² ΔIy²) / 2 )因为差分会让输出尺寸在两个方向上各缩一个像素所以分母用 (M-1)(N-1)。根号里的 1/2 是最容易被忽略的细节它让水平、垂直和对角方向的边缘响应一致保证指标与边缘方向无关。有些开源实现写的是 √(ΔIx² ΔIy²)那会让数值整体放大 1.414 倍排序一般不变但和论文里的绝对值对比时必须先确认变体。import numpy as np gx, gy np.array(2.0), np.array(3.0) print(np.sqrt(gx**2 gy**2)) # 不除 2 的版本3.606 print(np.sqrt((gx**2 gy**2) / 2)) # 各向同性版本2.550同一个 (2, 3) 的梯度两个公式能差出 1 以上。按我的习惯实现一律用带 1/2 的版本并把公式写进代码注释省得三个月后自己都核对不上。另外要留意差分算子的选择用 np.diff 是裸差分对单像素细节最敏感Sobel 自带 3×3 平滑核对噪声更稳但会低估超分结果里的细纹理。论文对照时优先裸差分和定义式严格对应。2.2 图像信息熵灰度分布的不确定性度量图像信息熵借用香农信息论把图像看成灰度随机变量的一个样本灰度分布越均匀不确定性越大熵越高。对 8 位灰度图H -Σ p_k · log₂(p_k)k 从 0 到 255p_k 是灰度级 k 的出现频率。log 以 2 为底时单位是 bit均匀分布时熵达到最大值 8 bit整张图只有一种灰度时熵为 0。实现上用直方图统计频率再套公式即可唯一要处理的是 p_k 0 的桶不能参与 log 运算。熵的解读比梯度更依赖场景。细节丰富的自然图像熵通常在 7 bit 左右但这不意味着 7.5 就一定比 7.0 好——白噪声图像的熵可以非常接近 8因为每个灰度级都均匀出现。所以熵高只说明灰度层次多至于它是「丰富的细节」还是「一堆噪声」要靠梯度、标准差和肉眼一起判断。2.3 图像标准差对比度与动态范围标准差衡量像素值相对均值 μ 的离散程度σ √( 1/(MN) · Σ (I(i,j) - μ)² )它直观对应画面的「反差」标准差大亮暗拉得开视觉上更透亮标准差小图像发灰、发闷。numpy 的 np.std 默认除 N总体标准差有的脚本用除 N-1 的样本标准差对常见尺寸的图像两者差异在 0.05% 以内可以忽略真正影响可比性的是灰度范围——0-255 和 0-1 两种尺度算出的 σ 相差 255 倍。另外注意标准差对整体亮度偏移不敏感同一张图整体加 50 的灰度偏移σ 不变。若想排除亮度影响只看对比度可以用变异系数 CV σ/μ这在红外和可见光融合里常用来比较不同模态图像的反差水平。2.4 三指标联动判读先看“形状”再看“数值”单看任何一个指标都会误判三个放一起能筛掉大部分假阳性图像状态平均梯度信息熵标准差典型原因过曝/欠曝偏低明显偏低偏低灰度被压到极值附近层次丢失高斯模糊明显偏低略偏低略偏低高频细节被滤掉直方图被抹平叠加噪声异常偏高接近 8中等偏高噪声本身贡献梯度熵被推高正常细节丰富高7 左右高边缘清晰、层次完整、反差适中判读经验是梯度异常高但画面看着不干净先怀疑噪声熵接近 8 且梯度也高先看直方图有没有均匀「拖尾」标准差高但均值偏移严重先检查预处理是不是做了不该做的归一化。把三个数字和直方图放一起看比单独报一个指标靠谱得多。3. 用 Python 实现图像质量评价一次算完平均梯度/信息熵/标准差3.1 最小可复现脚本从 PIL 到三项指标把前面定义落成代码我会写成三个独立函数加一个入口方便单独 import 到其他项目import numpy as np from PIL import Image def average_gradient(img: np.ndarray) - float: 平均梯度输入二维灰度数组值越大边缘越锐利。 img img.astype(np.float64) gx np.diff(img, axis1) # 水平差分形状 (H, W-1) gy np.diff(img, axis0) # 垂直差分形状 (H-1, W) gx gx[:-1, :] # 裁剪公共区域 (H-1, W-1) gy gy[:, :-1] return float(np.mean(np.sqrt((gx ** 2 gy ** 2) / 2.0))) def information_entropy(img: np.ndarray) - float: 信息熵8 位灰度图均匀分布时为 8 bit。 img np.asarray(img, dtypenp.uint8) hist np.bincount(img.ravel(), minlength256) p hist / hist.sum() # 归一化为概率 p p[p 0] # 剔除零概率避免 log2(0) return float(-np.sum(p * np.log2(p))) def standard_deviation(img: np.ndarray) - float: 标准差反映对比度ddof 默认 0总体标准差。 return float(np.std(img.astype(np.float64))) def evaluate_quality(image_path: str) - dict: 读取图像并返回四项基础统计量。 arr np.array(Image.open(image_path).convert(L)) return { average_gradient: round(average_gradient(arr), 4), information_entropy: round(information_entropy(arr), 4), std_deviation: round(standard_deviation(arr), 4), mean: round(float(arr.mean()), 4), } if __name__ __main__: import sys for p in sys.argv[1:]: print(p, evaluate_quality(p))逐段说明。average_gradient 里 np.diff 沿 axis 的结果各少一个像素所以先算完再统一裁剪到 (H-1, W-1)保证 gx 和 gy 逐元素对应如果先裁剪再差分边界像素会丢更多数值偏小。information_entropy 里 np.bincount 要求输入为非负整数uint8 正好满足minlength256 保证灰度级 255 也有对应桶位。std 直接用它默认的总体标准差大图上 ddof 取 0 还是 1 的差异可以忽略。命令行用法python eval_metrics.py image1.png image2.png脚本会把每个文件的四项指标打出来。这是最小闭环做批量评价时只要在外面套一层目录遍历。3.2 关键参数细节差分选择、熵底数与灰度位数换不同实现时最容易翻车的是三个参数参数常见取值影响建议梯度算子一阶差分 / Sobel / PrewittSobel 带平滑核对噪声更稳但会低估高频细纹理论文对照优先一阶差分与公式严格对应熵底数log2 / ln数值相差 ln(2)≈0.693 倍统一用 log2单位 bit 最直观灰度位数8bit / 归一化 [0,1]熵和标准差的数值完全不同8 位图直接按 0-255 统计不归一化Sobel 的问题在超分辨率评测里特别明显它自带 3×3 平滑核会把单像素细线这类高频细节抹掉算出的梯度偏低。如果你的结果要和某篇论文的 AG 值逐位对齐先确认对方代码里有没有 filter2D 或 convolve没有就是裸差分。信息熵还有个隐藏前提直方图分箱必须是 0-255 共 256 个桶。有的脚本对归一化后的 [0,1] 数据直接 np.histogram默认分箱数对不上熵值就不可比。提示如果输入是 PNG 但实际存的是调色板索引直接 ravel 统计的是索引值而不是真实灰度先 convert(L) 再算。3.3 彩色图像与 16 位图像转灰度还是逐通道彩色图像常见两种策略。第一种是整体转灰度PIL 的 convert(L) 用 ITU-R BT.601 系数 L 0.299R 0.587G 0.114B优点是快、和大多数论文口径一致缺点是抹掉色差信息两张饱和度不同但亮度分布相同的图指标完全相同。第二种是逐通道计算再平均保留色彩对指标的影响def evaluate_color(image_path: str) - dict: arr np.array(Image.open(image_path)) if arr.ndim 2: return evaluate_quality(image_path) arr arr[:, :, :3] # RGBA 图去掉 alpha 通道 names [average_gradient, information_entropy, std_deviation] acc {k: [] for k in names} for c in range(arr.shape[2]): ch arr[:, :, c] acc[average_gradient].append(average_gradient(ch)) acc[information_entropy].append(information_entropy(ch)) acc[std_deviation].append(standard_deviation(ch)) return {k: round(float(np.mean(v)), 4) for k, v in acc.items()}对每个通道算完指标后取平均等价于把三通道看成三个独立样本。这样处理的好处是色偏严重的融合图会被熵值反映出来——某一通道分布被压扁时该通道熵明显低于其余通道平均后就能看见差异。注意 RGBA 图的 alpha 通道是透明掩膜不是色彩信息必须先切片去掉否则标准差会失真。16 位图像的坑更隐蔽uint16 范围是 0-65535直接套 256 桶的 bincount 会把高位信息全挤进第一个桶。做法是先做线性映射到 0-255 再算或者把熵的分箱数改成 4096/65536 并重新归一化联合分布。我一般只对 8 位图报绝对熵值16 位图只报相对大小不做跨数据集比较。4. 融合评价实战用三项指标比较融合算法的输出质量4.1 无参考评价的对照逻辑孤立指标没有意义图像融合场景里评价分两类。有真值比如仿真时把一张清晰图人为模糊成多张源图可以用 PSNR、SSIM 这类全参考指标但大多数真实融合任务没有真值只能做无参考评价平均梯度、信息熵、标准差就是最常用的一组。无参考不等于无对照。失败案例大多是「算了个融合图的熵7.2很好」——这没有意义。融合的目标是把源图的有效信息尽可能搬到结果里所以融合图的每个指标都要和源图放在同一张表里比看的是差值而不是绝对值。判读逻辑有三条。第一融合图的平均梯度应达到或超过源图中较清晰的那张第二信息熵不应低于任一源图明显降低说明灰度层次被压没第三标准差应保持在中上水平异常低说明动态范围被压缩异常高往往是振铃伪影在撑数值。4.2 多聚焦融合图的判读实验脚本多聚焦是最典型的场景源图 A 左清晰右模糊源图 B 右清晰左模糊融合算法把两者合成一张全清晰图。写个循环把一组图全算一遍import os def evaluate_folder(folder: str) - list: rows [] for name in sorted(os.listdir(folder)): if name.lower().endswith((.png, .jpg, .bmp, .tif)): m evaluate_quality(os.path.join(folder, name)) m[filename] name rows.append(m) return rows rows evaluate_folder(./fusion_results) for r in rows: print(f{r[filename]:20} AG{r[average_gradient]:.3f} fH{r[information_entropy]:.3f} std{r[std_deviation]:.3f})跑出来的表按文件名对齐源图 A、源图 B、融合图 F 各一行。判读时先看 AG 列F 的 AG 应该接近 max(AG_A, AG_B)如果比两者都低说明融合在「做平均」而不是「做选择」边缘被中和掉了。再看熵列F 的熵不低于任一源图才算合格但接近 8 且 AG 也比源图高出一截时要怀疑算法引入了伪纹理。场景AG 表现熵表现结论倾向融合图清晰选中目标区域与较清晰源图相当或略高不低于两源图融合有效融合图边缘糊明显低于两源图略低于源图像素平均为主需换策略融合图有振铃异常高偏高伪影贡献梯度需人工复核需要提醒的是这些指标无法区分「真实细节」和「伪影细节」任何自动判读都必须配一张局部放大图。我通常会在脚本里顺手裁三个 100×100 的区域存成对比图指标表和视图一起交出去。注意计算前所有图像必须经过完全相同的预处理包括位深、归一化和格式转换。融合算法输出的 16 位结果直接和 8 位源图比熵数值没有意义。4.3 补充互信息指标衡量融合结果对源图的信息保留三项基础指标之外融合评价里出场率最高的补充指标是互信息Mutual Information, MI衡量融合图 F 与各源图 S 之间的信息重合度。常用形式是 MI_f MI(F, S1) MI(F, S2)值越大说明从源图继承的信息越多。def mutual_information(a: np.ndarray, b: np.ndarray) - float: 计算两幅 8 位灰度图的互信息单位 bit。 a np.asarray(a, dtypenp.uint8).ravel() b np.asarray(b, dtypenp.uint8).ravel() joint, _, _ np.histogram2d(a, b, bins256, range[[0, 255], [0, 255]]) joint / joint.sum() pa joint.sum(axis1, keepdimsTrue) pb joint.sum(axis0, keepdimsTrue) with np.errstate(divideignore, invalidignore): term np.log2(joint / (pa * pb)) term[~np.isfinite(term)] 0.0 return float(np.sum(joint * term))np.histogram2d 生成 256×256 的联合直方图除以总和得到联合概率边缘概率 pa、pb 分别由联合分布按行列求和得到。log2(joint / (pa * pb)) 里 joint 为 0 的位置会产生 NaN用 errstate 配合 isfinite 清零后参与求和。MI 的下界是 0表示两图完全独立同图自信息是 8 bit所以融合评价里 MI 总和一般落在 2-6 bit 区间。审稿较严的场合还会要求 QABF基于边缘保持度的融合指标它需要方向梯度算子和边缘强度归一化实现比 MI 复杂得多但和 AG 互补——AG 看绝对值QABF 看边缘信息保留比例。论文里有空间引工程验收里我一般只算 MI 做交叉验证。5. 批量图像质量评价的工程细节CSV 汇总、数值验证与判读误区5.1 目录批量计算并输出 CSV实验要跑十几个算法、每个算法几十张图时print 到控制台就没法看了。我习惯把 evaluate_folder 的结果直接写成 CSVExcel 或 pandas 都能继续处理import csv def export_csv(rows: list, out_path: str) - None: with open(out_path, w, newline, encodingutf-8-sig) as fp: writer csv.DictWriter(fp, fieldnameslist(rows[0].keys())) writer.writeheader() writer.writerows(rows) rows evaluate_folder(./fusion_results) export_csv(rows, metrics_summary.csv)DictWriter 用第一个字典的键当表头后续每个字典一行。编码用 utf-8-sig 是为了让 Excel 直接打开时不乱码。导出后我会在 CSV 里加两列派生指标ΔAG AG_fused - max(AG_src1, AG_src2)ΔH H_fused - max(H_src1, H_src2)验收标准就变成两条硬规则ΔAG 0 且 ΔH 不低于 -0.3 bit。这两条能挡掉八成不合格的融合结果。5.2 用合成图验证实现是否正确指标实现有没有写错拿真实图是看不出来的因为没人知道「正确值」是多少。每次写完先用两张合成图自检# 合成图 1256x256 斜坡图灰度随列递增 ramp np.tile(np.arange(256, dtypenp.float64), (256, 1)) print(average_gradient(ramp)) # 期望 0.7071 1/sqrt(2) print(information_entropy(ramp)) # 期望 8.0均匀分布 print(standard_deviation(ramp)) # 期望约 73.9 # 合成图 2全零图 zero np.zeros((256, 256)) print(average_gradient(zero)) # 期望 0.0 print(information_entropy(zero)) # 期望 0.0 print(standard_deviation(zero)) # 期望 0.0斜坡图每列递增 1水平差分恒为 1、垂直差分恒为 0所以 AG √(1/2) ≈ 0.7071灰度在 256 级上均匀分布熵精确等于 8.0离散均匀分布的标准差理论值约 73.9。如果这三个值和理论对不上说明差分裁剪或分箱统计有 bug。这个验证十秒跑完比拿真实图瞎猜可靠得多。5.3 判读中的三个高频误区第一个误区是跨脚本比绝对值。不同实现的分箱、差分、归一化不一致AG 差 30% 很常见所以验收必须固定一套脚本跑完全部对比绝不允许 A 算法用论文里的数、B 算法自己跑一遍。第二个误区是把高熵当高质量噪声图熵接近 8判读时先看直方图看它是不是均匀「白」出来的。第三个误区是只看融合图自带指标、不看源图基线AG 7.0 看着不错但如果源图清晰区本来就有 7.5这个融合结果反而是减分的。我的验收流程固定为同一脚本算全部图 → CSV 输出 → 加 ΔAG 和 ΔH 两列 → 抽查三处局部放大图指标与视图互为印证后才算过。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门