【画像評価指標とコード】PSNR、SSIM、FID、NMSEの説明とコード

評価指標と算出方法

ピーク信号対雑音比 (PSNR):

「ピーク信号対雑音比」とは中国語でピーク信号対雑音比を意味し、画質を測る指標の一つです。これは、再構成された画像と元の画像の間の類似性と歪みを測定するために使用されます。PSNR は画像の全体的な品質に関する情報のみを提供し、詳細や知覚の違いをキャプチャすることはできません。

式によれば、MSE が小さいほど品質が良く、PSNR が大きいほど品質が良いことがわかります。
ここに画像の説明を挿入します
ここに画像の説明を挿入します
平均二乗誤差から得られる MAX1 はピクセル内の最大値で、通常は 1 または 255 です。

def psnr(res,gt):
    mse = np.mean((res - gt) ** 2)
    if(mse == 0):
        return 100
    max_pixel = 1
    psnr = 20 * log10(max_pixel / sqrt(mse))
    return psnr

構造的類似性 (SSIM):

この方法は(構造的類似性)とも呼ばれ、2つの画像の類似性を測定するために使用される指標です。SSIM 法は、画像を複数の領域として表示し、これらの領域内の構造、明るさ、コントラストなどの統計を比較することによって評価されます。SSIM アルゴリズムは人間の画像知覚の特性を考慮しており、人間の目の視覚特性により一致しています。SSIM アルゴリズムは比較的複雑で、画像のローカル構造情報とグローバル構造情報を比較する必要があります。2 つの画像 x と y が与えられると、2 つの画像の構造的類似性の式は式 2-7 として表すことができます。

ここに画像の説明を挿入します

" SSIM " ( x , y ) = ( 2 μ x μ y + c 1 ) ( 2 σ xy + c 2 ) / ( μ x 2 + μ y 2 + c 1 ) ( σ x 2 + σ y 2 + c 2 ) "SSIM" (x,y)=(2μ_x μ_y+c_1 )(2σ_xy+c_2 )/(μ_x^2+μ_y^2+c_1 )(σ_x^2+σ_y^2+c_2 )SS I M ( x y )=( 2m _×メートルはい+c1) ( 2p _×y+c2) / (メートルバツ2+メートルy2+c1) ( pバツ2+py2+c2)

戻り値は次のとおりです: [0, 1] の範囲の SSIM スコア 1 に近づくほど、2 つの画像はより類似します。

from skimage.metrics import structural_similarity as ssim

def calculate_ssim(img1, img2):
    # 计算 SSIM
    ssim_score = ssim(img1, img2, multichannel=True)
    
    return ssim_score

# 示例用法
img1 = ...  # 第一幅图像数据,类型为numpy数组,范围为0-1
img2 = ...  # 第二幅图像数据,类型为numpy数组,范围为0-1

score = calculate_ssim(img1, img2)
print("SSIM score:", score)

# 或者使用下面代码也可以
#-*- codeing = utf-8 -*-
#@Time : 2023/4/27 0027 14:43
#@Author : Tom
#@File : SSIM.py
#@Software : PyCharm

import torch
import torch.nn.functional as F

def ssim(img1, img2, window_size=11, size_average=True, full=False):
    # 常量,用于计算均值和方差
    C1 = (0.01 * 255) ** 2
    C2 = (0.03 * 255) ** 2

    # 平均池化滤波器
    window = torch.ones(3, 1, window_size, window_size).float().cuda()
    mu1 = F.conv2d(img1, window, padding=window_size//2, groups=3)
    mu2 = F.conv2d(img2, window, padding=window_size//2, groups=3)

    # 平均值和方差
    mu1_sq, mu2_sq, mu1_mu2 = mu1 ** 2, mu2 ** 2, mu1 * mu2
    sigma1_sq = F.conv2d(img1 ** 2, window, padding=window_size//2, groups=3) - mu1_sq
    sigma2_sq = F.conv2d(img2 ** 2, window, padding=window_size//2, groups=3) - mu2_sq
    sigma12 = F.conv2d(img1 * img2, window, padding=window_size//2, groups=3) - mu1_mu2

    # SSIM 的计算公式
    ssim_map = ((2 * mu1_mu2 + C1) * (2 * sigma12 + C2)) / ((mu1_sq + mu2_sq + C1) * (sigma1_sq + sigma2_sq + C2))
    if size_average:
        ssim_value = torch.mean(ssim_map)
    else:
        ssim_value = torch.mean(ssim_map, dim=(1, 2, 3))

    # 如果设置了 full=True,返回 SSIM 的值和 SSIM 图像的各通道值
    if full:
        return ssim_value, ssim_map
    else:
        return ssim_value


img1 = torch.ones(1, 3, 256, 256).cuda()
img2 = torch.ones(1, 3, 256, 256).cuda()

ssim_value = ssim(img1, img2, window_size=11)
print(ssim_value)

正規化された平均二乗誤差 (NMSE):

正規化された平均二乗誤差

NMSE の値は常に 0 から 1 (両端の値を含む) の間であり、値が小さいほどモデルのパフォーマンスが向上します。

def nmse(res,gt):
    Norm = np.linalg.norm((gt * gt),ord=2) # 计算 'gt' 的平方的2-范数(也就是欧几里得长度),存储在变量 'Norm' 中。这一步是为了避免在分母中出现零,从而导致除零错误
    if np.all(Norm == 0): # 如果 'Norm' 等于零(也就是说,如果 'gt' 是全零向量),那么函数直接返回0。这是因为对于全零向量,任何误差都会得到无穷大的NMSE。
        return 0 
    else:
        nmse = np.linalg.norm(((res - gt) * (res - gt)),ord=2) / Norm # 算 'res' 和 'gt' 的差的平方的2-范数,然后除以 'Norm'。这就是NMSE的定义:误差的平方和除以目标值的平方和。
    return nmse

フレッチャー距離 (FID)

Fréchet Inception Distance (FID) は、生成モデルによって生成された画像と実際の画像との差を測定するために使用される指標であり、Inception v3 [32] モデルの特徴空間におけるそれらの分布距離を比較することによって計算されます。FIDで使用する特徴ベクトルは、Inception v3モデルの最後から2番目の全結合層が出力する高次元ベクトルであり、画像の視覚的な特徴情報を捉えることができます。FID 値は、生成モデルによって生成された画像と実際の画像の類似性を測定するために使用でき、FID 値が小さいほど、特徴空間における 2 つの画像の分布が近く、類似性が高くなります。2 つの画像が同一である場合、それらの FID 値は 0 になります。

ここに画像の説明を挿入します

FID = ∣ ∣ μ r − μ g ∣ ∣ 2 + T r ( Σ r + Σ g − 2 〖 ( Σ r Σ g ) 〗 ( 1 / 2 ) ) FID=∣∣μ_r-μ_g∣∣^2+Tr (Σ_r+Σ_g-2〖(Σ_r Σ_g)〗^(1/2))FID _ _=∣∣メートルrメートルg2+ T r ( Sr+Sg2 ( SrSg( 1/2))
式中、 は実画像の特徴平均、 は生成画像の特徴平均、 は実画像の共分散行列、 は生成画像の共分散行列、 はトレースです。

import torch
import torchvision
import torchvision.transforms as transforms
from pytorch_fid import fid_score

# 准备真实数据分布和生成模型的图像数据
real_images_folder = '/path/to/real/images/folder'
generated_images_folder = '/path/to/generated/images/folder'

# 加载预训练的Inception-v3模型
inception_model = torchvision.models.inception_v3(pretrained=True)

# 定义图像变换
transform = transforms.Compose([
    transforms.Resize(299),
    transforms.CenterCrop(299),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])
])

# 计算FID距离值
fid_value = fid_score.calculate_fid_given_paths([real_images_folder, generated_images_folder],
                                                 inception_model,
                                                 transform=transform)
print('FID value:', fid_value)


pytorch_fid のバージョンが異なると使用方法が異なるため、注意が必要です。
対応する写真を計算できるように、2 つのフォルダー内の写真の数は同じである必要があり、サイズはできるだけ同じである必要があり、名前は対応していることが望ましいです。

最後に使用した

    PSNR = []
    NMSE = []
    SSIM = []

    for i, (img, gt) in enumerate(data_loader):
        batch_size = img.size()[0]
        img = img.to(device, dtype=torch.float)
        gt = gt.to(device, dtype=torch.float)

        with torch.no_grad():
            pred = model(img)

        for j in range(batch_size):
            a = pred[j]
            # save_image([pred[j]], images_save + str(i * batch_size + j + 1) + '.png', normalize=False)
            print(images_save + str(i * batch_size + j + 1) + '.png')

        pred, gt = pred.cpu().detach().numpy().squeeze(), gt.cpu().detach().numpy().squeeze()

        for j in range(batch_size):
            PSNR.append(psnr(pred[j], gt[j]))
            NMSE.append(nmse(pred[j], gt[j]))
            SSIM.append(ssim(pred[j], gt[j]))

    PSNR = np.asarray(PSNR)
    NMSE = np.asarray(NMSE)
    SSIM = np.asarray(SSIM)

    PSNR = PSNR.reshape(-1, slice_num)
    NMSE = NMSE.reshape(-1, slice_num)
    SSIM = SSIM.reshape(-1, slice_num)

    PSNR = np.mean(PSNR, axis=1)
    NMSE = np.mean(NMSE, axis=1)
    SSIM = np.mean(SSIM, axis=1) 

    print("PSNR mean:", np.mean(PSNR), "PSNR std:", np.std(PSNR))
    print("NMSE mean:", np.mean(NMSE), "NMSE std:", np.std(NMSE))
    print("SSIM mean:", np.mean(SSIM), "SSIM std:", np.std(SSIM))

各スライスを平均することにより、より詳細な評価が得られ、異なるスライス間の差異を観察できます。データ全体を直接平均すると、スライスレベルの情報を取得できない場合があります。したがって、スライスを取得し、各スライスのメトリックの平均を個別に計算するのが一般的です。

おすすめ

転載: blog.csdn.net/aaatomaaa/article/details/133234723