LoginSignup
4

More than 3 years have passed since last update.

超解像用のPSNRをPythonで算出する

Last updated at Posted at 2018-06-28

単一画像超解像の評価方法

単一画像超解像の評価にはSSIMやPSNRなどの指標が挙げられますが,今回は特にPSNRを焦点に当てます.
多くの論文はおそらく
https://github.com/jbhuang0604/SelfExSR
の sr_quant_eval.m の実装を参考にしていると思います.

この中でやっていることは
超解像画像と正解画像をRGBからYCbCrに変換して輝度値Yだけを取り出す.
周囲 $cr$ ピクセルを除外した上で超解像画像と正解画像の $\mathrm{MSE}$ を算出する.
その上で以下の式を用いて $\mathrm{PSNR}$ を求める.

$$ \mathrm{PSNR} = 10\times log_{10}{\frac{255^2}{\mathrm{MSE}}} $$

式自体は非常に単純であるので上のリンクはMATLABで書いていますが別に他の言語でも実装は簡単そうです.

特に最近は機械学習の影響でPythonで実装しようとする方も多いと思います.
その際,OpenCVを使うと思わぬ穴にはまります.

MATLABとOpenCVではRGB→YCbCrの計算式が異なる

上に書いた通りです.MATLABとOpenCVではRGB→YCbCrの計算式が異なります.
なるべく寄せたコードがこちらです.

import numpy as np
import math

def psnr(img1, img2):
    mse = np.mean((img1 - img2) ** 2)
    if mse == 0:
        return 100
    PIXEL_MAX = 255.0
    return 10 * math.log10(PIXEL_MAX * PIXEL_MAX / mse)


def extract_y(image: np.ndarray) -> np.ndarray:
    if image.ndim == 2:
        return image
    image = image.astype(np.float64)
    return ((image[:, :, 2] * 65.481 / 255.
             + image[:, :, 1] * 128.553 / 255.
             + image[:, :, 0] * 24.966 / 255.) + 16)

def evaluate(img1: np.ndarray, img2: np.ndarray, upscaling=4):
    # BGR -> YCrCb
    # 画像はcv2.imreadで読まれている前提 [0, 255]
    y1 = extract_y(img1)
    y2 = extract_y(img2)

    # 周囲のcropping
    # assert y1.shape == y2.shape
    h, w = y1.shape
    cr = upscaling
    cropped_y1 = y1[cr:h - cr, cr:w - cr]
    cropped_y2 = y2[cr:h - cr, cr:w - cr]

    # psnr
    psnr_val = psnr(cropped_y1, cropped_y2)
    return psnr_val

まだ微妙にMATLABとずれるので厳しい

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4