图像结构相似性指数(SSIM)

图像结构相似性指数(SSIM)

介绍

SSIM(结构相似性指数)是一种用于衡量两个图像之间结构相似性的指标。它是一种全参考图像质量评价指标,用于衡量两个图像在亮度、对比度和结构方面的相似程度。

SSIM 被广泛应用于图像处理领域,尤其在图像压缩、图像恢复、图像质量评价等方面具有重要作用。与传统的 PSNR(峰值信噪比)相比,SSIM 考虑了人眼对图像感知的特性,更能反映人眼感知到的图像质量。

SSIM 的计算基于以下三个方面的信息:

  1. 亮度相似性(Luminance Similarity):衡量两个图像的亮度是否相似。通过计算两个图像的亮度信息的均值和方差来评估亮度相似性。

  2. 对比度相似性(Contrast Similarity):衡量两个图像的对比度是否相似。通过计算两个图像的像素值的标准差和协方差来评估对比度相似性。

  3. 结构相似性(Structure Similarity):衡量两个图像的结构是否相似。通过计算两个图像的像素值的协方差来评估结构相似性。

SSIM 的计算结果范围为 -1 到 1,值越接近 1 表示两个图像结构相似性越高,质量越好;值越接近 -1 表示结构相似性越低,质量越差。

SSIM 的优点是能够考虑到图像的结构信息,更贴近人眼的感知结果。然而,SSIM 也有一些局限性,例如它对亮度、对比度和结构的权重分配是固定的,不适用于所有类型的图像。

示例代码

SSIM 的计算公式如下:

SSIM(x, y) = [l(x, y) * c(x, y) * s(x, y)]^α

其中,x 和 y 是要比较的两个图像。

  • l(x, y) 表示亮度相似性,计算方式为:
    l(x, y) = (2 * μx * μy + c1) / (μx^2 + μy^2 + c1)

    其中,μx 和 μy 分别是 x 和 y 的像素值的均值,c1 是一个常数,用于防止分母为零。

  • c(x, y) 表示对比度相似性,计算方式为:
    c(x, y) = (2 * σxy + c2) / (σx^2 + σy^2 + c2)

    其中,σx 和 σy 分别是 x 和 y 的像素值的标准差,σxy 是 x 和 y 的像素值的协方差,c2 是一个常数,用于防止分母为零。

  • s(x, y) 表示结构相似性,计算方式为:
    s(x, y) = (σxy + c3) / (σx * σy + c3)

    其中,c3 是一个常数,用于防止分母为零。

  • α 是一个指数参数,一般取值为 1。

以下是使用 PyTorch 实现 SSIM 的示例代码:

import torch
import torch.nn.functional as F

def gaussian(window_size, sigma):
    gauss = torch.Tensor([exp(-(x - window_size//2) ** 2 / float(2*sigma ** 2)) for x in range(window_size)])
    return gauss / gauss.sum()


def create_window(window_size, channel):
    _1D_window = gaussian(window_size, 1.5).unsqueeze(1)
    _2D_window = _1D_window.mm(_1D_window.t()).float().unsqueeze(0).unsqueeze(0)
    window = Variable(_2D_window.expand(channel, 1, window_size, window_size).contiguous())
    return window

def ssim(x, y, window_size=11, size_average=True):
    c1 = 0.01 ** 2
    c2 = 0.03 ** 2
    
    window = create_window(window_size, 1)
    # window = torch.Tensor([1.0 / (window_size ** 2)] * window_size ** 2).view(1, 1, window_size, window_size).to(x.device)

    mu1 = F.conv2d(x, window, padding=window_size // 2, groups=x.shape[1])
    mu2 = F.conv2d(y, window, padding=window_size // 2, groups=y.shape[1])

    mu1_sq = mu1 ** 2
    mu2_sq = mu2 ** 2
    mu12 = mu1 * mu2

    sigma1_sq = F.conv2d(x * x, window, padding=window_size // 2, groups=x.shape[1]) - mu1_sq
    sigma2_sq = F.conv2d(y * y, window, padding=window_size // 2, groups=y.shape[1]) - mu2_sq
    sigma12 = F.conv2d(x * y, window, padding=window_size // 2, groups=x.shape[1]) - mu12

    ssim_map = ((2 * mu12 + c1) * (2 * sigma12 + c2)) / ((mu1_sq + mu2_sq + c1) * (sigma1_sq + sigma2_sq + c2))

    if size_average:
        return ssim_map.mean()
    else:
        return ssim_map.mean(1).mean(1).mean(1)  # 分别对每个通道求均值,然后再对所有通道求均值

# 示例使用
x = torch.randn(1, 3, 256, 256)
y = torch.randn(1, 3, 256, 256)

ssim_value = ssim(x, y)
print(ssim_value)

在上述示例中,我们定义了一个 ssim() 函数来计算 SSIM。该函数接受两个输入张量 xy,以及一个窗口大小 window_size 和一个布尔值 size_average,用于指定是否对输出结果进行平均。

在函数内部,我们首先定义了常数 c1c2,然后创建了一个窗口权重张量 window。接下来,我们使用 F.conv2d() 函数来计算输入张量的均值和方差。最后,我们根据 SSIM 的公式计算相似性,并返回结果。

猜你喜欢

转载自blog.csdn.net/qq_36892712/article/details/132568486