Spaces:
Running
Running
| # Copyright (c) 2020 Huawei Technologies Co., Ltd. | |
| # Licensed under CC BY-NC-SA 4.0 (Attribution-NonCommercial-ShareAlike 4.0 International) (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode | |
| # | |
| # The code is released for academic research use only. For commercial use, please contact Huawei Technologies Co., Ltd. | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| import glob | |
| import os | |
| import time | |
| from collections import OrderedDict | |
| import numpy as np | |
| import torch | |
| import cv2 | |
| import argparse | |
| from natsort import natsort | |
| from skimage.metrics import structural_similarity as ssim | |
| from skimage.metrics import peak_signal_noise_ratio as psnr | |
| import lpips | |
| class Measure(): | |
| def __init__(self, net='alex', use_gpu=False): | |
| self.device = 'cuda' if use_gpu else 'cpu' | |
| self.model = lpips.LPIPS(net=net) | |
| self.model.to(self.device) | |
| def measure(self, imgA, imgB): | |
| return [float(f(imgA, imgB)) for f in [self.psnr, self.ssim, self.lpips]] | |
| def lpips(self, imgA, imgB, model=None): | |
| tA = t(imgA).to(self.device) | |
| tB = t(imgB).to(self.device) | |
| dist01 = self.model.forward(tA, tB).item() | |
| return dist01 | |
| def ssim(self, imgA, imgB): | |
| # multichannel: If True, treat the last dimension of the array as channels. Similarity calculations are done independently for each channel then averaged. | |
| score, diff = ssim(imgA, imgB, full=True, multichannel=True, channel_axis=-1) | |
| return score | |
| def psnr(self, imgA, imgB): | |
| psnr_val = psnr(imgA, imgB) | |
| return psnr_val | |
| def t(img): | |
| def to_4d(img): | |
| assert len(img.shape) == 3 | |
| assert img.dtype == np.uint8 | |
| img_new = np.expand_dims(img, axis=0) | |
| assert len(img_new.shape) == 4 | |
| return img_new | |
| def to_CHW(img): | |
| return np.transpose(img, [2, 0, 1]) | |
| def to_tensor(img): | |
| return torch.Tensor(img) | |
| return to_tensor(to_4d(to_CHW(img))) / 127.5 - 1 | |
| def fiFindByWildcard(wildcard): | |
| return natsort.natsorted(glob.glob(wildcard, recursive=True)) | |
| def imread(path): | |
| return cv2.imread(path)[:, :, [2, 1, 0]] | |
| def format_result(psnr, ssim, lpips): | |
| return f'{psnr:0.2f}, {ssim:0.3f}, {lpips:0.3f}' | |
| def measure_dirs(dirA, dirB, use_gpu, verbose=False): | |
| if verbose: | |
| vprint = lambda x: print(x) | |
| else: | |
| vprint = lambda x: None | |
| t_init = time.time() | |
| paths_A = fiFindByWildcard(os.path.join(dirA, f'*.{type}')) | |
| paths_B = fiFindByWildcard(os.path.join(dirB, f'*.{type}')) | |
| vprint("Comparing: ") | |
| vprint(dirA) | |
| vprint(dirB) | |
| measure = Measure(use_gpu=use_gpu) | |
| results = [] | |
| for pathA, pathB in zip(paths_A, paths_B): | |
| result = OrderedDict() | |
| t = time.time() | |
| result['psnr'], result['ssim'], result['lpips'] = measure.measure(imread(pathA), imread(pathB)) | |
| d = time.time() - t | |
| vprint(f"{pathA.split('/')[-1]}, {pathB.split('/')[-1]}, {format_result(**result)}, {d:0.1f}") | |
| results.append(result) | |
| psnr = np.mean([result['psnr'] for result in results]) | |
| ssim = np.mean([result['ssim'] for result in results]) | |
| lpips = np.mean([result['lpips'] for result in results]) | |
| vprint(f"Final Result: {format_result(psnr, ssim, lpips)}, {time.time() - t_init:0.1f}s") | |
| if __name__ == "__main__": | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument('-dirA', default='', type=str) | |
| parser.add_argument('-dirB', default='', type=str) | |
| parser.add_argument('-type', default='png') | |
| parser.add_argument('--use_gpu', action='store_true', default=False) | |
| args = parser.parse_args() | |
| dirA = args.dirA | |
| dirB = args.dirB | |
| type = args.type | |
| use_gpu = args.use_gpu | |
| if len(dirA) > 0 and len(dirB) > 0: | |
| measure_dirs(dirA, dirB, use_gpu=use_gpu, verbose=True) | |