资讯动态

区域差分信息熵:超分重建局部感知质量评价指标

发布时间:2026/10/5 8:55:11 来源:尧图企业网站定制
简介区域差分信息熵RDE评估指标源码包专注于超分辨率图像感知质量评价。相比传统像素级误差度量RDE通过分析图像局部区域的统计特性更加贴合人眼视觉机制适合图像处理研究者、算法工程师以及进行课程设计或毕设的学生使用。源码共64个文件压缩包约25.23MB包含2个Python脚本核心算法与演示代码、60张用于测试的PNG示例图、1张JPG流程示意图及1份Markdown说明文档。代码结构清晰关键部分配详细注释可直接运行demo.py对超分图像做质量评估也可借助README快速理解调用方式和算法逻辑。目前已有38人学习下载属小众但实用的参考资料。资源内含RDE完整计算流程、区域划分与差分信息熵统计实现、配套图片数据及Pipeline示意图既能辅助论文复现也能作为图像质量评价入门的实践素材。1. 区域差分信息熵一个为超分重建“局部感知质量”而生的评价指标做超分辨率图像重建的人常有这种体验PSNR 很高画面却发虚SSIM 还行皮肤和草地却透着一股塑料感。逐像素误差和结构相似度都回答不了同一个问题——重建出的局部细节是否真的像原图那样丰富且自然。区域差分信息熵RDIE正是为此设计的感知质量评价指标把图像划分成局部区域在每个区域内计算差分图像的灰度分布熵再汇总所有块的统计量来评价超分重建在细节尺度上的真实感。它适合超分算法选型、训练数据筛选、图像超分辨率重建对比以及 AI 对 CT 超分辨率重建这类高频细节敏感任务的评价。接下来的内容会从原理讲到 Python 源码实现再落到底层参数和坑点。2. 区域差分信息熵的原理为什么局部差分熵比全局直方图更贴近人眼2.1 信息熵描述的是灰度分布不是空间结构信息熵在图像处理里最常见的用法是统计灰度直方图后计算香农熵。设一张 8 位灰度图的灰度分布为 p0 到 p255其信息熵为H -Σ p(i) · log2(p(i))当所有灰度值出现概率相近时熵高接近 8 bit当图像只有两个灰度值且占比极端不平衡时熵很低。这个指标反映的是灰度取值的“混乱程度”而不是画面的空间复杂度。问题也很明显把一张纹理丰富的照片所有像素随机打乱直方图完全不变熵也完全不变但画面已经变成了噪声图。反过来把照片做高斯模糊直方图可能只是轻微变化熵几乎不动人眼却立刻感知到清晰度下降。这说明基于原始像素分布的熵对空间结构不敏感而人眼对图像质量的判断恰恰是高度空间化的——边缘是否锐利、纹理是否集中在正确位置这些信息都藏在像素的空间关系里不在灰度统计里。所以要在熵的框架里描述感知质量第一步就是换掉统计对象不去统计原始像素而是统计像素之间的差异。2.2 差分图像上的熵将对焦信息与模糊信息分开“差分”在图像处理里就是像素灰度变化率的度量。最简单的是水平一阶差分 d(x,y) I(x1,y) - I(x,y)更常用的是 Sobel、Prewitt 这类梯度算子。对图像求梯度后得到差分图再对差分图统计直方图并计算熵得到的就是差分熵。差分熵的意义在于模糊图像的边缘是缓变的相邻像素差值普遍偏小差分直方图集中在零附近熵低清晰图像的边缘是陡变的差分值分布更宽甚至会出现明显的双峰熵高。于是差分熵把图像质量评价从“灰度丰富度”转移到了“梯度丰富度”上与清晰度的关联更强。但全局差分熵仍然有一个盲区它把整张图的信息量压成一个值。自然图像并不是均匀分布的纹理——城市街景的下半部分是密集的窗户和招牌上半部分是天空人像中头发区域的梯度能量远高于皮肤区域。全局差分熵把这些区域的差异全部叠加平均等于把“局部重建质量是否真实”这个问题抹平了。2.3 区域划分的意义捕捉局部信息量分布的“不均匀”区域差分信息熵的做法是在差分熵前面加了一个“区域”约束把图像划分成不重叠或重叠的块对每个块分别计算差分熵再用这些块级熵值的均值、标准差或分位数来代表整体质量。这么做的原因是超分辨率重建的失败模式往往是局部性的。一个超分网络可能把树冠区域的纹理重建得异常锐利伪细节同时把墙面抹得像塑料一样光滑全局差分熵会把这两类失真平均掉得不出任何结论。而分块之后每个块的差分熵单独计算你可以直接看到哪些块熵异常高、哪些异常低还能通过熵分布图对比参考图和重建图之间的局部信息量偏移。用数学语言来归纳设图像 I 被划分为 k×k 个不重叠块 B_ij每个块先做差分变换得到差分图 D(B_ij)再统计差分值的概率分布并计算熵H_ij -Σ p_n(B_ij) · log2(p_n(B_ij))最终的区域差分信息熵可以是所有 H_ij 的均值也可以是标准差、分位数的组合。均值代表整体信息量水平标准差代表空间分布是否均匀两者结合起来才能描述“哪里好、哪里坏”这个感知层面的信息。到这里原理层面还剩最后一个关键问题为什么块级熵能反映“感知质量”答案在于分布对齐。真实的自然图像其局部差分熵分布是有特定形状的——纹理区高、平坦区低、边缘区居中。超分网络如果过度平滑平坦区的差分熵变化不大但纹理区的熵会显著下降如果过度锐化平坦区会出现伪纹理熵异常升高。RDIE 通过对比参考图和重建图的块级熵分布把这两种失败模式同时暴露出来这是 PSNR 和 SSIM 做不到的。3. 用 Python 实现区域差分信息熵核心代码与超分评估接入3.1 最小可用实现一个计算区域差分信息熵的函数依赖只用了 OpenCV 和 NumPy这两者在图像处理环境里基本是标配。核心流程是灰度化 → Sobel 梯度幅值 → 非重叠分块 → 每块计算差分熵 → 返回均值与全部块熵。import numpy as np import cv2 def block_entropy(grad_block, bins256): 计算单个梯度块的差分信息熵。 输入 grad_block 为单通道梯度幅值图 (block_h, block_w)。 bins 控制直方图分桶数8 位梯度图默认 256。 hist, _ np.histogram( grad_block, binsbins, range(0, 255), densityTrue ) # 去掉零概率项避免 log2(0) 产生 -inf hist hist[hist 0] return float(-np.sum(hist * np.log2(hist))) def rdie_score(image_gray, block_size32, bins256): 区域差分信息熵主函数。 输入为单通道 uint8 灰度图输出 (均值, 块熵数组)。 # Sobel 梯度幅值ksize3 是自然图像上的稳妥选择 grad_x cv2.Sobel(image_gray, cv2.CV_64F, 1, 0, ksize3) grad_y cv2.Sobel(image_gray, cv2.CV_64F, 0, 1, ksize3) grad_mag cv2.magnitude(grad_x, grad_y) grad_mag np.clip(grad_mag, 0, 255).astype(np.uint8) h, w grad_mag.shape block_entropies [] # 非重叠分块边缘不足 block_size 的块直接丢弃 for y in range(0, h, block_size): for x in range(0, w, block_size): block grad_mag[y:y block_size, x:x block_size] if block.shape[0] 8 or block.shape[1] 8: continue block_entropies.append(block_entropy(block, bins)) if not block_entropies: raise ValueError(图像尺寸小于 block_size请调小块尺寸) return float(np.mean(block_entropies)), np.array(block_entropies)这段代码里有几个细节需要注意。Sobel 算子求梯度时用了 CV_64F避免 uint8 溢出因为梯度可能是负值随后用 magnitude 合并 x 和 y 方向响应再 clip 到 0 到 255 并转回 uint8是为了让直方图能用固定 range 统计。bins 默认 256正好对应 8 位灰度范围如果保留浮点梯度而不压缩bins 必须按梯度的实际动态范围重新设置否则直方图会大量空洞算出来的熵偏低。block_size 默认取 32这是一个折中32×32 块内有 1024 个梯度像素参与直方图统计熵估计相对稳定16×16 块只有 256 个样本在 256 个 bin 上平均每个 bin 不到 1 个像素统计噪声明显。块越大越接近全局差分熵分区感知能力越弱。这个参数的进一步讨论放在第 4 章。3.2 接入超分评估流程与 PSNR 和 SSIM 一起输出报告单看 RDIE 值没有太大意义要把它放进超分模型对比的评估流程里才有实际价值。下面是一个批量评估单张参考图与重建图的函数同时输出 PSNR、SSIM、参考图 RDIE、重建图 RDIE 以及两者的差值。from skimage.metrics import structural_similarity def evaluate_sr_result(reference, reconstructed, block_size32): 超分结果综合评估。 reference/reconstructed 均为 BGR 彩色图 uint8且形状一致。 assert reference.shape reconstructed.shape, 参考图与重建图尺寸不一致 # PSNR直接调用 OpenCV 自带实现 psnr cv2.PSNR(reference, reconstructed) # SSIM在灰度图上的结构相似度fullTrue 可返回逐像素映射 ref_gray cv2.cvtColor(reference, cv2.COLOR_BGR2GRAY) rec_gray cv2.cvtColor(reconstructed, cv2.COLOR_BGR2GRAY) ssim structural_similarity(ref_gray, rec_gray, data_range255) # RDIE分别在参考图与重建图上计算并求差值 rdie_ref, _ rdie_score(ref_gray, block_sizeblock_size) rdie_rec, rec_block_ent rdie_score(rec_gray, block_sizeblock_size) rdie_diff rdie_rec - rdie_ref return { PSNR_dB: round(psnr, 3), SSIM: round(float(ssim), 5), RDIE_ref: round(rdie_ref, 4), RDIE_rec: round(rdie_rec, 4), RDIE_diff: round(rdie_diff, 4), }这段代码把 RDIE 放进了常规超分评测体系里。关键看 RDIE_diff 这个值它为正且偏大说明重建图的局部差分熵整体高于原图典型的伪纹理特征因为真实图像不会无中生有地增加边缘和纹理它为负说明重建图的局部差分信息量丢失往往对应过度平滑。RDIE_diff 接近零时还要结合 PSNR 和 SSIM 判断因为存在灰度整体偏移时差分熵可能变化不大但 PSNR 会被拉低。SSIM 这里用了 skimage 的实现原因是它支持 data_range 参数的显式传入避免 uint8 与 float 混合时出现归一化错误。如果你不想引入 skimage用 OpenCV 4.5 以上自带的 cv2.SSIM 也可以但要注意它内部假定输入为 uint8传入 float 图会得到错误结果。3.3 批量评估一个目录把 RDIE 变成一个工程工具单张评估跑通后下一步就是把整个测试集批量跑一遍输出排序结果和一份 JSON 报告。常见做法是遍历目录、逐对计算然后把结果汇总到 Pandas DataFrame 或直接写 CSV方便后续与主观评分做相关性分析。import os, json, glob def batch_evaluate(reference_dir, reconstructed_dir, output_pathrdie_report.json): 批量评估某个超分测试集。 目录结构要求两个目录下的文件名一一对应例如 hr/0001.png 与 sr/0001.png。 ref_paths sorted(glob.glob(os.path.join(reference_dir, *.png))) rec_paths sorted(glob.glob(os.path.join(reconstructed_dir, *.png))) assert len(ref_paths) len(rec_paths), 参考图与重建图数量不一致 results [] for ref_p, rec_p in zip(ref_paths, rec_paths): ref_img cv2.imread(ref_p) rec_img cv2.imread(rec_p) if ref_img is None or rec_img is None: print(f读取失败: {ref_p} 或 {rec_p}) continue name os.path.basename(ref_p) score evaluate_sr_result(ref_img, rec_img) score[name] name results.append(score) # 按 RDIE_diff 绝对值升序排列最接近原图信息分布的排前面 results.sort(keylambda x: abs(x[RDIE_diff])) with open(output_path, w, encodingutf-8) as f: json.dump(results, f, ensure_asciiFalse, indent2) print(f已完成 {len(results)} 张图的评估结果写入 {output_path}) return results批量脚本里最容易被忽略的是文件名对齐。超分测试集常见命名是 HR 图叫 0001.png重建图也叫 0001.png但也有带 epoch 后缀或模型名后缀的直接用 zip 对两个 glob 结果做一一对应会错位。我一般会按序号提取文件名中的数字部分做排序 key或者干脆要求两个目录使用完全一致的 basename。这个约束在脚本注释里写清楚能省掉后续大量对不上号的麻烦。到这一步RDIE 已经是一个可用的评估工具。但工具能用只是第一步参数设置不对结论可能完全相反。4. 参数这么调块尺寸、差分算子与聚合策略对评分结果的影响4.1 块尺寸16、32、64 在不同图像尺度下的行为差异块尺寸是 RDIE 最敏感的参数没有之一。它决定“区域”的粒度也决定每个块内用于统计熵的样本量。先看统计可靠性。块越小样本越少熵估计的方差越大。16×16 的块只有 256 个梯度像素在 256 个直方图桶上平均每个桶不到 1 个像素熵经常被低估而且块与块之间的波动可能不是图像内容差异而是采样噪声。32×32 的块有 1024 个样本统计稳定性明显改善。64×64 的块有 4096 个样本熵估计非常稳定但空间分辨率下降可能把 32×32 尺度上的纹理异常平均掉。再看内容敏感性。对自然图像超分评估我通常先从 32 起步同时跑一组 64 做稳定性验证。如果两组块尺寸下的模型排序一致说明结论稳健如果排序差异很大说明数据集的纹理尺度跨度太大单一尺寸无法代表感知质量这时需要用重叠分块或记录多尺度值。对医学影像超分尤其是 AI 对 CT 超分辨率重建推荐把块尺寸调小到 16 或 24。CT 图像中的关键结构——骨小梁、血管断面、肺纹理——都是高频局部信号尺寸通常在几十个像素以内64 的块会把它们和周围平滑组织混在一起RDIE 无法反映真实的细节重建质量。4.2 差分算子Sobel、一阶差分与拉普拉斯的取舍差分算子的选择决定了“差分”指什么。三种常见算子各有偏向评价效果差异明显算子响应特征对噪声敏感性适用场景Soble 梯度边缘有宽度响应平滑中等自然图像超分通用首选一阶邻域差分边缘响应极锐利极高只在无噪声数据上使用拉普拉斯算子二阶差分突出过冲极高检测振铃和伪边缘不适合整体评分Sobel 是默认选择因为它在边缘响应和噪声抑制之间取了一个平衡点对超分网络常见的轻微伪影不会过度放大。一阶差分响应锐利但会把传感器噪声也当成高频信息算出来的 RDIE 经常虚高。拉普拉斯算子对边缘过冲敏感适合用来观察超分重建是否引入了振铃但作为整体评价指标很容易被个别强边缘带偏。如果你不确定该用哪个算子做法是写一个参数化的 run把算子类型传进去在同样一批图上跑出三组分对比模型排序的 Spearman 相关系数。相关系数高说明结论不依赖算子选择低说明数据里存在某种和算子强相关的特殊纹理需要单独分析。4.3 聚合策略均值、标准差和低百分位数的结合使用rdie_score 返回的均值只是聚合策略的其中一种。均值把图像内容信息量拉平了一张纹理均匀分布的图和一张半边细节半边天空的图可能得到几乎相同的均值但人眼对这两种图的感知差异极大。所以实际使用时要搭配分布统计量。标准差反映块间信息量分布的不均匀程度。标准差大的模型往往只重建好了部分区域另一半被抹平或加了伪纹理标准差小的模型输出风格保守局部翻车概率低。在视频超分场景里这个取舍很关键偏科模型切镜头时会出现一帧好一帧坏观感下降明显在单张人像超分中局部细节丰富可能更讨喜。低百分位数比如 P10反映最平滑的那 10% 块的信息量能暴露过度平滑问题高百分位数比如 P90反映最纹理化的区域是否出现离谱的伪细节。把这些统计量全部输出RDIE 就从单一指标变成一组多维信号。在写评估脚本时我一般把 rdie_score 的返回值扩展成字典包含 mean、std、p10、p90而不是只返回均值。后续做模型过滤时每个统计量都有用途。第 6 章的护栏筛选展示了具体怎么用。5. 区域差分信息熵的避坑清单这些用法会把排序结果带偏5.1 彩色图直接转灰度计算色度伪影完全失明现象两张重建图一张颜色准确一张有明显偏色和色斑PSNR 和 SSIM 相差不大RDIE 也几乎一样但主观上偏色那张明显更难接受。原因RDIE 默认在灰度图上计算只响应亮度域的差分信息。超分模型如果出现色彩渗漏或色度伪影只要亮度结构没崩差分熵就不会有明显变化。解决把 RGB 三通道分别计算 RDIE取均值作为一个参考更敏感的做法是在 Lab 色彩空间对 a、b 通道单独计算差分熵因为 Lab 的 a、b 通道集中了大部分色度信息。色彩是超分感知质量的一部分完全不看色度会漏掉一类严重失真。5.2 黑边与 padding 块混入统计RDIE 被纯色块拉低现象同一张图裁掉四周 5% 的黑边后RDIE 涨了 0.3 甚至更多模型排序完全变化。原因很多超分网络的输出带 padding 边或者推理脚本在边界做了 reflection padding输出边缘存在黑色或重复纹理区域。这些区域梯度几乎为零算出的熵极低混入均值后显著拉低整体分数。更麻烦的是数据集中每张图的 padding 宽度不一致相当于给每张图加了不同的权重排序自然失真。解决进入 rdie_score 之前先做纯色边框裁剪。用阈值检测灰度接近 0 或接近 255 的连续边缘区域裁掉后再分块。下面是一个简单可靠的裁剪函数def crop_blank_borders(img_gray, threshold8, margin4): 裁剪灰度接近纯黑或纯白的边框。 threshold 控制判空阈值margin 防止误裁掉真实暗边。 mask (img_gray threshold) (img_gray 255 - threshold) ys, xs np.where(mask) if len(ys) 0: return img_gray y0 max(int(ys.min()) - margin, 0) y1 min(int(ys.max()) margin 1, img_gray.shape[0]) x0 max(int(xs.min()) - margin, 0) x1 min(int(xs.max()) margin 1, img_gray.shape[1]) return img_gray[y0:y1, x0:x1]这个函数的关键是 margin 参数。真实图像的暗角或黑色物体可能紧贴边界如果 margin 设成 0会把它们也裁掉设成 4 或 8则只去掉纯色边带。具体数值需要根据你的数据统计一下边界像素的灰度分布再定。5.3 与论文结果对比时块划分方式不一致导致数值对不上现象按论文里的方法复现 RDIE算出来的数值总是有偏差有时模型排序都变了。原因不同来源对“区域”的实现差异极大。有的是把图像缩放到固定尺寸再分块有的是非重叠分块有的用 50% 重叠的滑动窗口有的对每个块单独归一化梯度后再算熵有的对整张图归一化一次再分块。这些看似微小的差异会让熵值出现系统性偏移。解决在论文或项目文档里记录完整的参数集至少包含块尺寸、块重叠率、差分算子、归一化粒度、直方图 bin 数和灰度范围。我自己的习惯是把这些参数编码进输出文件名比如 rdie_b32_sobel_noolap_bins256.json这样三个月后回看还能清楚知道指标是怎么算出来的。5.4 把 RDIE 当唯一选型标准误把伪纹理当高分现象某个超分模型输出的纹理非常锐利但纹理形状是错的——皮肤纹理被重建成了类似草地的排列RDIE 反而给这个模型打了高分。原因RDIE 是信息量指标不是语义保真度指标。它奖励“更多更丰富的高频信息”但不关心这些高频信息在空间上是否构成真实的结构。它测的是感知相关信息量不是语义正确性。解决RDIE 必须与 SSIM 或 LPIPS 联合使用。RDIE 高而 SSIM 低的模型要警惕因为高 RDIE 可能来自伪纹理而不是真实细节SSIM 在这里扮演结构保真兜底的角色。更稳妥的做法是先按 RDIE_diff 绝对值过滤掉信息量偏移过大的模型再在剩余候选里按 SSIM 排序。5.5 输入图像含噪声差分熵把噪声当成了细节现象原始图像有轻度传感器噪声超分后的噪声被放大或抑制RDIE 随之突增或骤降但主观感受并不对应。原因差分熵无法区分噪声和真实纹理。它看到的只是梯度分布而噪声在梯度域的响应和真实纹理很接近尤其是细颗粒噪声几乎无法用一阶统计区分。解决在计算 RDIE 之前对参考图和重建图各做一次轻度中值滤波比如 3×3 或 5×5得到滤波前后的两个 RDIE。如果差值超过 0.2说明图中存在大量非纹理高频成分RDIE 的可靠性要打折扣。这个方法不改变 RDIE 本身而是给你一个量化“噪声污染程度”的参考值。6. 让 RDIE 真正可信用主观评分校准、护栏筛选与工程化落地6.1 用 Spearman 相关系数验证 RDIE 在你数据上的可信度RDIE 在公开基准上的表现不能直接迁移到你的业务数据上。一个稳妥的验证流程是挑 20 到 30 张代表性的测试图用三到四个超分模型分别生成×2、×3、×4 的重建图然后让三到五个熟悉图像质量的评估者做主观排序计算 RDIE 排序与主观排序的 Spearman 相关系数。经验参考值在 Urban100 这类密集纹理数据集上PSNR 与主观排名的相关系数通常在 0.5 左右SSIM 约 0.7RDIE 在 0.8 以上但在人像数据集上由于平滑区域占比大RDIE 的相关性会明显下降。如果相关系数低于 0.6优先检查块尺寸——多半是块太大把细纹理平均掉了。只有在你自己的数据上验证通过RDIE 才真正可用。6.2 在超分模型筛选中用 RDIE 差值做护栏在模型选型时我反对“RDIE 最高者胜出”的思路更推荐把它当作护栏拒绝 RDIE_diff 绝对值过大的模型再用 PSNR 或 SSIM 做二次排序。这样能有效拦截“局部编造纹理”和“整体过度平滑”两类典型失败模型。def rank_models_by_rdie(results, diff_threshold0.15, std_threshold2.0): 按 RDIE 护栏规则筛选超分模型。 diff_threshold重建图与参考图 RDIE 差值的最大绝对值。 std_threshold重建图块熵标准差的上限拦截偏科模型。 passed [] for r in results: if abs(r[RDIE_diff]) diff_threshold: continue if RDIE_std_rec in r and r[RDIE_std_rec] std_threshold: continue passed.append(r) return sorted(passed, keylambda x: abs(x[RDIE_diff])) # 用法示例results 为 evaluate_sr_result 的返回值列表 # ranked rank_models_by_rdie(results, diff_threshold0.15)diff_threshold 的取值依赖数据集的整体尺度。自然图像经过灰度归一化后RDIE 通常落在 6 到 8 之间差 0.1 已经是肉眼可辨的细节差异如果块尺寸改成 16阈值要适当放宽到 0.2。std_threshold 的作用是防止偏科模型它在视频超分场景下比 diff_threshold 更敏感因为偏科模型切镜头时的质量波动会被标准差放大。6.3 批量评估的工程细节并行、切块与参数记录当评估集规模达到几百张甚至上千张时计算效率开始成为问题。三个异步的注意点第一计算密度很低时没必要用多进程。rdie_score 主要耗时在 Sobel 和直方图统计几百张图加起来也不过几秒用 ProcessPoolExecutor 反而增加进程切换开销。真正值得优化的是 I/O 侧用 cv2.imread 的 IMREAD_UNCHANGED 标记避免不必要的颜色空间转换。第二超大图像的切块策略。对 4K 以上分辨率建议先裁掉边界再按重叠分块计算避免单张图产生几百个块后数组内存膨胀。重叠分块的步长一般取块尺寸的一半即 block_size32 时步长取 16这样既能平滑块间不连续又不会让计算量翻倍太多。第三参数记录要比数据本身更严谨。RDIE 的绝对值受块尺寸和算子影响极大不记录参数的结果在两周后基本失去可比性。我习惯把每次实验的参数写入 JSON 元数据和评测结果一起存档文件命名里带上块尺寸和算子标识。回头看我自己的经验最开始用 RDIE 时也走过弯路直接拿默认参数跑完整个测试集输出的排序和主观感受相去甚远一度以为这个指标没用。后来逐项排查才发现是黑边没处理加上块尺寸对数据集偏大。把这两个问题解决后RDIE 才真正成为团队超分模型选型中不可替代的参考指标。指标本身没有魔法参数调对、边界处理好、验证跑通它才能发挥出价值。希望这些经验能帮你少走几步弯路。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑