关于图像误差分析常用指标-MSE,PSNR和SSIM

做图像处理的实验,常用到的定量比较的三个指标:均方误差(MSE), 峰值信噪比(PSNR), 结构相似性指数(SSIM).

本文将着重介绍这三个指标的定义和Python版本的代码实现。

均方误差 Mean Squared Error

功能:

衡量两张图像相似度的一个指标,均方误差越小,表示两张图像越相似。

特点:

对大误差敏感:由于是平方差,MSE对大误差特别敏感,因此如果图像中有较大的差异(比如大面积的噪声),MSE值会显著增大。

对视觉质量的感知差异不敏感:MSE主要从数学角度衡量图像差异,但它并不一定与人眼对图像质量的感知一致。例如,两个图像的MSE可能非常相近,但其中一个图像在视觉上可能明显更好。

公式:

图像处理中的均方误差公式可以如下计算:
M S E = 1 m × n ∑ i = 1 m ∑ j = 1 n ( I ( i , j ) − I ^ ( i , j ) ) 2 其 中 : I 是 图 像 , I ^ 是 其 处 理 版 本 m × n 是 图 像 的 尺 寸 , 即 图 像 中 的 像 素 数 。 I ( i , j ) 是 原 始 图 像 在 位 置 ( i , j ) 处 的 像 素 值 。 I ^ ( i , j ) 是 处 理 后 图 像 在 位 置 ( i , j ) 处 的 像 素 值 。 MSE = \frac{1}{m \times n} \sum_{i=1}^{m} \sum_{j=1}^{n} \left( I(i,j) - \hat{I}(i,j) \right)^2 \\\\ 其中: I是图像,\hat{I}是其处理版本\\ m \times n 是图像的尺寸,即图像中的像素数。 \\ I(i,j) 是原始图像在位置 (i,j)处的像素值。\\ \hat{I}(i,j)是处理后图像在位置 (i,j)处的像素值。 MSE=m×n1i=1mj=1n(I(i,j)I^(i,j))2II^m×nI(i,j)(i,j)I^(i,j)(i,j)

代码实现(Python):

本文提供的参考代码可以实现多通道的MSE计算,计算的数值已经经过归一化处理。

import cv2
import numpy as np

def resize_to_smaller(image1, image2):
    """
    将两幅图像调整为相同的较小尺寸。
    """
    h1, w1 = image1.shape[:2]
    h2, w2 = image2.shape[:2]
    target_height = min(h1, h2)
    target_width = min(w1, w2)
    resized_image1 = cv2.resize(image1, (target_width, target_height), interpolation=cv2.INTER_AREA)
    resized_image2 = cv2.resize(image2, (target_width, target_height), interpolation=cv2.INTER_AREA)
    return resized_image1, resized_image2

def calculate_mse_per_channel(image1, image2):
    """
    计算彩色图像每个通道的均方误差 (MSE)。
    """
    assert image1.shape == image2.shape, "两幅图像的尺寸必须相同"
    mse_values = []
    for channel in range(3):  # 对B、G、R通道分别计算
        channel1 = image1[:, :, channel] / 255.0
        channel2 = image2[:, :, channel] / 255.0
        mse = np.mean((channel1 - channel2) ** 2)
        mse_values.append(mse)
    return mse_values

def main(image_path1, image_path2):
    """
    主函数,读取图像、调整尺寸并计算每个通道的 MSE。
    """
    img1 = cv2.imread(image_path1)
    img2 = cv2.imread(image_path2)

    if img1 is None or img2 is None:
        print("无法加载图像,请检查文件路径!")
        return

    img1_resized, img2_resized = resize_to_smaller(img1, img2)

    # 计算每个通道的 MSE
    mse_values = calculate_mse_per_channel(img1_resized, img2_resized)

    # print(f"MSE (B通道): {mse_values[0]:.6f}")
    # print(f"MSE (G通道): {mse_values[1]:.6f}")
    # print(f"MSE (R通道): {mse_values[2]:.6f}")

    # 平均 MSE
    avg_mse = np.mean(mse_values)
    print(f"平均 MSE: {avg_mse:.6f}")

# 程序入口
image1 = ''
image2 = ''
main(image1, image2)

峰值信噪比 Peak Signal-to-Noise Ratio

功能

PSNR 表示图像的信号与噪声之间的比率。值越高,图像质量越好。

特点

越大越好:PSNR 值越高,表示图像质量越好。通常来说,PSNR 大于 30 dB 时,人眼几乎无法分辨原始图像和压缩后的图像之间的差异。

对视觉质量有一定反映:与 MSE 相比,PSNR 直接通过对数转换来反映图像质量,且以分贝为单位,更符合人类对信号强度的感知。

MSE的关系:PSNR 和 MSE 是反相关的,MSE 越小,PSNR 越大,意味着图像质量越好。实际上,PSNR 是通过均方误差来推导的,目的是提供一个更容易理解的度量,尤其是在图像压缩中,PSNR 值越高,通常代表图像的失真较小。

单位:PSNR 的单位是分贝(dB)。PSNR 值通常在 20 dB 到 40 dB 之间,超过 40 dB 时,图像质量通常非常接近原始图像。

公式

P S N R = 10 ⋅ log ⁡ 10 ( I max 2 M S E ) 其 中 : I m a x 是 图 像 中 可 能 的 最 大 像 素 值 , 对 于 8 位 图 像 , 通 常 I m a x = 255. M S E 即 上 文 介 绍 的 均 方 误 差 PSNR = 10 \cdot \log_{10} ( \frac{I_{\text{max}}^2}{MSE}) \\\\ 其中: I_{max}是图像中可能的最大像素值,对于8位图像,通常I_{max}=255. \\ MSE即上文介绍的均方误差 PSNR=10log10(MSEImax2):Imax8Imax=255.MSE

代码实现(Python)

三通道,归一化处理的PSNR值

import cv2
import numpy as np

def calculate_psnr_from_mse(avg_mse, max_pixel=1.0):
    """
    根据平均 MSE 计算 PSNR。
    max_pixel: float
        图像的最大像素值(归一化图像为 1.0,原始图像为 255)。
    """
    if avg_mse == 0:
        return float('inf')  # 如果平均 MSE 为 0,PSNR 为无穷大
    return 10 * np.log10((max_pixel ** 2) / avg_mse)

def process_rgb_psnr(image1, image2):
    """
    计算 RGB 图像的平均 MSE,并根据平均 MSE 计算 PSNR。
    """
    assert image1.shape == image2.shape, "两幅图像的尺寸必须相同"
    
    # 归一化到 [0, 1]
    image1_normalized = image1 / 255.0
    image2_normalized = image2 / 255.0

    # 计算 RGB 各通道的 MSE
    mse_b = np.mean((image1_normalized[:, :, 0] - image2_normalized[:, :, 0]) ** 2)
    mse_g = np.mean((image1_normalized[:, :, 1] - image2_normalized[:, :, 1]) ** 2)
    mse_r = np.mean((image1_normalized[:, :, 2] - image2_normalized[:, :, 2]) ** 2)

    # 计算平均 MSE
    avg_mse = (mse_b + mse_g + mse_r) / 3

    # 计算 PSNR
    psnr = calculate_psnr_from_mse(avg_mse)
    
    return {"Average MSE": avg_mse, "PSNR": psnr}

def main(image_path1, image_path2):
    """
    主函数,读取图像并计算平均 MSE 和 PSNR。
    """
    # 读取图像
    img1 = cv2.imread(image_path1)
    img2 = cv2.imread(image_path2)

    if img1 is None or img2 is None:
        print("无法加载图像,请检查文件路径!")
        return

    # 调整图像大小为相同
    h1, w1 = img1.shape[:2]
    h2, w2 = img2.shape[:2]
    target_height = min(h1, h2)
    target_width = min(w1, w2)
    img1_resized = cv2.resize(img1, (target_width, target_height), interpolation=cv2.INTER_AREA)
    img2_resized = cv2.resize(img2, (target_width, target_height), interpolation=cv2.INTER_AREA)

    # 计算平均 MSE 和 PSNR
    results = process_rgb_psnr(img1_resized, img2_resized)
    print(f"PSNR: {results['PSNR']:.3f} dB")

# 程序入口
image1 = ''
image2 = ''
main(image1, image2)

结构相似性指数 Structural Similarity Index

功能

SSIM 不仅关注像素值之间的差异,还考虑了图像的结构信息(例如纹理、亮度和对比度),因此更加符合人类视觉感知。值越大,表明图像越相同。

特点

更符合人眼视觉感知:SSIM 考虑了图像的亮度、对比度和结构信息,模拟了人眼对图像的感知,因此它的评估结果更符合人类的主观感知。

不受单纯像素差异影响:不同于 MSE 和 PSNR,SSIM 更注重结构信息,因此对于相同的均方误差,SSIM 能提供更精确的质量评估。

局部结构信息:SSIM 是局部计算的,通常通过在图像中滑动一个小窗口(例如 8x8 或 11x11 的窗口),逐块计算图像的结构相似性。

综合评价:通过整幅图像的局部SSIM值来得到整体的相似性评估。

单位:SSIM值的范围通常在0到1之间,

公式

S S I M ( x , y ) = ( 2 μ x μ y + C 1 ) ( 2 σ x y + C 2 ) ( μ x 2 + μ y 2 + C 1 ) ( σ x 2 + σ y 2 + C 2 ) 其 中 : x 和 y 是 两 张 图 像 ( 原 始 图 像 和 重 建 图 像 ) 的 局 部 图 像 块 ( 一 般 是 滑 动 窗 口 的 区 域 ) 。 μ x 和 μ y 是 图 像 x 和 y 块 的 平 均 值 ( 亮 度 信 息 ) 。 σ x 2 和 σ y 2 是 图 像 块 x 和 y 的 方 差 ( 对 比 度 信 息 ) 。 σ x y 是 图 像 x 和 y 块 之 间 的 协 方 差 ( 结 构 信 息 ) 。 C 1 和 C 2 是 常 数 , 用 于 避 免 分 母 为 零 的 情 况 , 通 常 选 择 C 1 = ( K 1 L ) 2 和 C 2 = ( K 2 L ) 2 , 其 中 L 是 像 素 值 的 动 态 范 围 , K 1 和 K 2 是 常 数 。 SSIM(x, y) = \frac{(2 \mu_x \mu_y + C_1)(2 \sigma_{xy} + C_2)}{(\mu_x^2 + \mu_y^2 + C_1)(\sigma_x^2 + \sigma_y^2 + C_2)} \\ 其中: x 和 y 是两张图像(原始图像和重建图像)的局部图像块(一般是滑动窗口的区域)。\\ \mu_x 和 \mu_y 是图像 x和 y 块的平均值(亮度信息)。\\ \sigma_x^2 和\sigma_y^2 是图像块 x 和 y 的方差(对比度信息)。\\ \sigma_{xy} 是图像 x 和 y 块之间的协方差(结构信息)。\\ C_1 和 C_2 是常数,用于避免分母为零的情况,通常选择 C_1 = (K_1 L)^2 和 C_2 = (K_2 L)^2 ,\\ 其中 L 是像素值的动态范围, K_1 和 K_2 是常数。 SSIM(x,y)=(μx2+μy2+C1)(σx2+σy2+C2)(2μxμy+C1)(2σxy+C2)xyμxμyxyσx2σy2xyσxyxyC1C2C1=(K1L)2C2=(K2L)2LK1K2

代码实现(Python)

借助scikit-image库实现,逐通道计算,求平均

from skimage.metrics import structural_similarity as ssim
import cv2

def calculate_ssim(image1, image2):
    """
    计算两幅图像的 SSIM(结构相似性指数),逐通道计算 RGB 的 SSIM。
    综合 SSIM 值(平均 SSIM)。
    """
    # 确保输入的图像尺寸相同
    assert image1.shape == image2.shape, "两幅图像的尺寸必须相同"
    
    # 分离 RGB 通道
    r1, g1, b1 = cv2.split(image1)
    r2, g2, b2 = cv2.split(image2)
    
    # 计算每个通道的 SSIM
    ssim_r = ssim(r1, r2)
    ssim_g = ssim(g1, g2)
    ssim_b = ssim(b1, b2)
    
    # 计算总体 SSIM(三个通道的平均值)
    overall_ssim = (ssim_r + ssim_g + ssim_b) / 3
    return overall_ssim

def main(image_path1, image_path2):
    """
    主函数,读取图像并计算 SSIM。
    """
    # 读取图像(RGB 图像)
    img1 = cv2.imread(image_path1, cv2.IMREAD_COLOR)
    img2 = cv2.imread(image_path2, cv2.IMREAD_COLOR)

    if img1 is None or img2 is None:
        print("无法加载图像,请检查文件路径!")
        return

    # 调整图像大小为相同
    h1, w1 = img1.shape[:2]
    h2, w2 = img2.shape[:2]
    target_height = min(h1, h2)
    target_width = min(w1, w2)
    img1_resized = cv2.resize(img1, (target_width, target_height), interpolation=cv2.INTER_AREA)
    img2_resized = cv2.resize(img2, (target_width, target_height), interpolation=cv2.INTER_AREA)

    # 计算 SSIM
    ssim_value = calculate_ssim(img1_resized, img2_resized)
    print(f"SSIM: {ssim_value:.6f}")

# 程序入口
image1 = ''
image2 = ''
main(image1, image2)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ayu阿予

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值