项目地址:https://github.com/Alexkkir/pyiqa-sal/tree/main
这是一个纯python和pytorch编写的图像质量评估工具箱,提供了许多主流全参考(FR)和无参考(NR)指标的重新实现(如果有的话,结果会用官方matlab脚本校准)。借助GPU加速,我们的大多数实现都比Matlab快得多。同时也比torch实现的方法在调用上更加方便。
1、基本简介
1.1 安装库
安装代码
# Install with pip
pip install pyiqa
# Install latest github version
pip uninstall pyiqa # if have older version installed already
pip install git+https://github.com/chaofengc/IQA-PyTorch.git
# Install with git clone
git clone https://github.com/chaofengc/IQA-PyTorch.git
cd IQA-PyTorch
pip install -r requirements.txt
python setup.py develop
1.2 使用案例
基本使用案例
import pyiqa
import torch
# list all available metrics
print(pyiqa.list_models())
device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
# create metric with default setting
iqa_metric = pyiqa.create_metric('lpips', device=device)
# Note that gradient propagation is disabled by default. set as_loss=True to enable it as a loss function.
iqa_loss = pyiqa.create_metric('lpips', device=device, as_loss=True)
# create metric with custom setting
iqa_metric = pyiqa.create_metric('psnr', test_y_channel=True, color_space='ycbcr').to(device)
# check if lower better or higher better
print(iqa_metric.lower_better)
# example for iqa score inference
# Tensor inputs, img_tensor_x/y: (N, 3, H, W), RGB, 0 ~ 1
score_fr = iqa_metric(img_tensor_x, img_tensor_y)
score_nr = iqa_metric(img_tensor_x)
# img path as inputs.
score_fr = iqa_metric('./ResultsCalibra/dist_dir/I03.bmp', './ResultsCalibra/ref_dir/I03.bmp')
# For FID metric, use directory or precomputed statistics as inputs
# refer to clean-fid for more details: https://github.com/GaParmar/clean-fid
fid_metric = pyiqa.create_metric('fid')
score = fid_metric('./ResultsCalibra/dist_dir/', './ResultsCalibra/ref_dir')
score = fid_metric('./ResultsCalibra/dist_dir/', dataset_name="FFHQ", dataset_res=1024, dataset_split="trainval70k")
1.3 一次性评价多个指标
代码地址:https://github.com/wyf0912/SinSR/blob/main/evaluate.py
所依赖的 utils库地址为:https://github.com/wyf0912/SinSR/tree/main/utils
import pyiqa
import os
import argparse
from pathlib import Path
import torch
from utils import util_image
import tqdm
device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
def evaluate(in_path, ref_path, ntest):
metric_dict = {}
metric_dict["clipiqa"] = pyiqa.create_metric('clipiqa').to(device)
metric_dict["musiq"] = pyiqa.create_metric('musiq').to(device)
metric_paired_dict = {}
in_path = Path(in_path) if not isinstance(in_path, Path) else in_path
assert in_path.is_dir()
ref_path_list = None
if ref_path is not None:
ref_path = Path(ref_path) if not isinstance(ref_path, Path) else ref_path
ref_path_list = sorted([x for x in ref_path.glob("*.[jpJP][pnPN]*[gG]")])
if ntest is not None: ref_path_list = ref_path_list[:ntest]
metric_paired_dict["psnr"]=pyiqa.create_metric('psnr', test_y_channel=True, color_space='ycbcr').to(device)
metric_paired_dict["lpips"]=pyiqa.create_metric('lpips').to(device)
metric_paired_dict["ssim"]=pyiqa.create_metric('ssim', test_y_channel=True, color_space='ycbcr' ).to(device)
lr_path_list = sorted([x for x in in_path.glob("*.[jpJP][pnPN]*[gG]")])
if ntest is not None: lr_path_list = lr_path_list[:ntest]
print(f'Find {len(lr_path_list)} images in {in_path}')
result = {}
for i in tqdm.tqdm(range(len(lr_path_list))):
in_path = lr_path_list[i]
ref_path = ref_path_list[i] if ref_path_list is not None else None
im_in = util_image.imread(in_path, chn='rgb', dtype='float32') # h x w x c
im_in_tensor = util_image.img2tensor(im_in).cuda() # 1 x c x h x w
for key, metric in metric_dict.items():
with torch.cuda.amp.autocast():
result[key] = result.get(key, 0) + metric(im_in_tensor).item()
if ref_path is not None:
im_ref = util_image.imread(ref_path, chn='rgb', dtype='float32') # h x w x c
im_ref_tensor = util_image.img2tensor(im_ref).cuda()
for key, metric in metric_paired_dict.items():
result[key] = result.get(key, 0) + metric(im_in_tensor, im_ref_tensor).item()
for key, res in result.items():
print(f"{key}: {res/len(lr_path_list):.5f}")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('-i',"--in_path", type=str, required=True)
parser.add_argument("-r", "--ref_path", type=str, default=None)
parser.add_argument("--ntest", type=int, default=None)
args = parser.parse_args()
evaluate(args.in_path, args.ref_path, args.ntest)
1.4 使用脚本
# example for FR metric with dirs
python inference_iqa.py -m LPIPS[or lpips] -i ./ResultsCalibra/dist_dir[dist_img] -r ./ResultsCalibra/ref_dir[ref_img]
# example for NR metric with single image
python inference_iqa.py -m brisque -i ./ResultsCalibra/dist_dir/I03.bmp
2、评价方法
2.1 有参考评价方法
AHIQ ✅、PieAPP ✅、LPIPS ✅、DISTS ✅、WaDIQaM ✅、CKDN1 ✅、FSIM ✅、SSIM ✅、MS-SSIM ✅、CW-SSIM ✅、PSNR ✅、VIF ✅、GMSD ✅、NLPD ✅、VSI ✅、MAD ✅
2.2 无参考评价方法
FID ✖️、CLIPIQA(+) ✅、MANIQA ✅、MUSIQ ✅、DBCNN ✅、PaQ-2-PiQ ✅、HyperIQA ✅、NIMA ✅、WaDIQaM ✅、CNNIQA ✅、NRQM(Ma)2 ✖️、PI(Perceptual Index) ✖️、BRISQUE ✅、ILNIQE ✅、NIQE ✅
2.3 指标对应的论文
无参考评价方法比较多,建议使用2020年以后提出的指标
model | lower better ? | min | max | DATE | Link |
---|---|---|---|---|---|
clipiqa | False | 0 | 1 | 2022 | https://arxiv.org/abs/2207.12396 |
maniqa | False | 0 | 2022 | https://arxiv.org/abs/2204.08958 | |
hyperiqa | False | 0 | 1 | 2020 | |
cnniqa | False | 2014 | |||
tres | False | 2022 | https://github.com/isalirezag/TReS | ||
musiq | False | ~0 | ~100 | 2021 | https://arxiv.org/abs/2108.05997 |
musiq-ava | False | ~0 | ~10 | 2021 | https://arxiv.org/abs/2108.05997 |
musiq-koniq | False | ~0 | ~100 | 2021 | https://arxiv.org/abs/2108.05997 |
paq2piq | False | 2020 | |||
dbcnn | False | 2019 | https://arxiv.org/bas/1907.02665 | ||
brisque | True | 2012 | |||
pi | True | 2018 | https://arxiv.org/abs/1809.07517 | ||
nima | False | 2018 | https://arxiv.org/abs/1709.05424 | ||
nrqm | False | 2016 | https://arxiv.org/abs/1612.05890 | ||
ilniqe | True | 0 | 2015 | ||
niqe | True | 0 | 2012 |