python numpy版本SSIM复现与算法解释

1. 简介

SSIM是一种图像评估指标算法,在算法实现里面输入是两张图片,输出是两张图片的相似评估数值,输入两张一模一样的图片则输出是1。

2. 算法

x与y分别代表两张图片(两个矩阵)
SSIM可通过两条公式计算:

2.1 公式一

公式1

2.2 公式二

paddle的高斯核滤波版本使用了这个公式
公式2

2.3 公式一的子项计算

公式一的子项公式
下面为图像均值的计算公式:
R(rows)代表图片的行,C(columns)代表图片的列,X为图像第i行第j列的像素值。
均值
下面为单张图像的方差、标准差和两张图片的协方差计算公式:
方差、标准差、协方差

2.4 常量

bit为图像位数,假设图像为8位,L=255
常量

3. 复现代码

3.1 基于公式一的实现

以下代码基于paddle的GAN代码里面的SSIM算法进行修改,这个版本是基于公式二。

import numpy as np
# 该函数作用于单通道
def ssim_1(img1, img2, L):
    """Calculate SSIM (structural similarity) for one channel images.
    Args:
        img1 (ndarray): Images with range [0, 255].
        img2 (ndarray): Images with range [0, 255].
    Returns:
        float: ssim result.
    """
    K1 = 0.01
    K2 = 0.03
    C1 = (K1 * L)**2
    C2 = (K2 * L)**2
    C3 = C2/2

    img1 = img1.astype(np.float64)
    img2 = img2.astype(np.float64)
    # ux
    ux = img1.mean()
    # uy
    uy = img2.mean()
    # ux^2
    ux_sq = ux**2
    # uy^2
    uy_sq = uy**2
    # ux*uy
    uxuy = ux * uy
    # ox、oy方差计算
    ox_sq = img1.var()
    oy_sq = img2.var()
    ox = np.sqrt(ox_sq)
    oy = np.sqrt(oy_sq)
    oxoy = ox * oy
    oxy = np.mean((img1 - ux) * (img2 - uy))
    # 公式二计算
    L = (2 * uxuy + C1) / (ux_sq + uy_sq + C1)
    C = (2 * ox * oy + C2) / (ox_sq + oy_sq + C2)
    S = (oxy + C3) / (oxoy + C3)
    ssim = L * C * S
    # 验证结果输出
    # print('ssim:', ssim, ",L:", L, ",C:", C, ",S:", S)
    return ssim

3.2 基于公式二的实现(高斯滤波)

代码来自paddle使用高斯核卷积

def ssim_2(img1, img2):
    """Calculate SSIM (structural similarity) for one channel images.
    It is called by func:`calculate_ssim`.
    Args:
        img1 (ndarray): Images with range [0, 255] with order 'HWC'.
        img2 (ndarray): Images with range [0, 255] with order 'HWC'.
    Returns:
        float: ssim result.
    """

    C1 = (0.01 * 255)**2
    C2 = (0.03 * 255)**2

    img1 = img1.astype(np.float64)
    img2 = img2.astype(np.float64)
    kernel = cv2.getGaussianKernel(11, 1.5)
    window = np.outer(kernel, kernel.transpose())

    mu1 = cv2.filter2D(img1, -1, window)[5:-5, 5:-5]
    mu2 = cv2.filter2D(img2, -1, window)[5:-5, 5:-5]
    mu1_sq = mu1**2
    mu2_sq = mu2**2
    mu1_mu2 = mu1 * mu2
    sigma1_sq = cv2.filter2D(img1**2, -1, window)[5:-5, 5:-5] - mu1_sq
    sigma2_sq = cv2.filter2D(img2**2, -1, window)[5:-5, 5:-5] - mu2_sq
    sigma12 = cv2.filter2D(img1 * img2, -1, window)[5:-5, 5:-5] - mu1_mu2
	# 公式二计算
    ssim_map = ((2 * mu1_mu2 + C1) *
                (2 * sigma12 + C2)) / ((mu1_sq + mu2_sq + C1) *
                                       (sigma1_sq + sigma2_sq + C2))
    return ssim_map.mean()

3.3 skimage的structural_similarity函数

skimage从1.17版本开始将compare_ssim更名为structural_similarity。

from skimage.metrics import structural_similarity

4. SSIM-Loss

该函数可作为部分神经网络的loss function,如图像生成网络等,计算output与label的相似度,SSIM-Loss如下:
S S I M L o s s = 1 − S S I M ( o u t p u t , l a b e l ) SSIM_{Loss}=1-SSIM(output, label) SSIMLoss=1SSIM(output,label)

5. 测试

测试图使用肺部胸片与去肋骨后的胸片进行测试。
原图:
在这里插入图片描述

去肋骨后:在这里插入图片描述
代码与输出:

if __name__=="__main__":
    origin_path = './origin.png'
    pred_path = './pred.png'
    img_ori = image.open(origin_path)
    img_pred = image.open(pred_path)
    X = np.array(img_pred)
    Y = np.array(img_ori)
    # 两者最后都需要做一个abs!!!!!!!!
    # 非高斯滤波
    print(abs(ssim_1(X, Y, 255))) # output:0.0002043533434396722
    # 高斯滤波
    print(abs(ssim_2(X, Y))) # output: 1.8464489378357714e-05
以下是一个基于PaddlePaddle框架的神经网络训练代码的示例,包括损失函数和优化器的定义: ```python import paddle import paddle.nn as nn import paddle.optimizer as optim # 定义神经网络模型 class Net(nn.Layer): def __init__(self, input_size, hidden_size, output_size): super(Net, self).__init__() self.hidden = nn.Linear(input_size, hidden_size) self.out = nn.Linear(hidden_size, output_size) def forward(self, x): x = paddle.tanh(self.hidden(x)) x = self.out(x) return x # 定义损失函数和优化器 model = Net(10, 20, 3) criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(parameters=model.parameters(), learning_rate=0.01) # 进行训练 for epoch in range(100): for input_data, target_data in train_loader: # 前向传播 output_data = model(input_data) loss = criterion(output_data, target_data) # 反向传播 optimizer.clear_grad() loss.backward() optimizer.step() print('Epoch: {}, Loss: {}'.format(epoch, loss.numpy())) ``` 在这个示例中,我们定义了一个包含一个隐藏层和一个输出层的神经网络模型,并使用交叉熵损失函数和随机梯度下降优化器进行训练。我们使用PaddlePaddle提供的`nn`和`optim`模块来定义网络和优化器,并使用`parameters()`方法获取模型参数的迭代器。在训练过程中,我们首先进行前向传播计算网络输出和损失值,然后进行反向传播计算梯度并使用优化器更新模型参数。最后,我们输出每个epoch的损失值以监控模型的训练进度。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Alex-Leung

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

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

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

打赏作者

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

抵扣说明:

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

余额充值