def calculate_psnr(img1, img2, crop_border, input_order='HWC', test_y_channel=False): """Calculate PSNR (Peak Signal-to-Noise Ratio). Ref: https://en.wikipedia.org/wiki/Peak_signal-to-noise_ratio Args: img1 (ndarray/tensor): Images with range [0, 255]/[0, 1]. img2 (ndarray/tensor): Images with range [0, 255]/[0, 1]. crop_border (int): Cropped pixels in each edge of an image. These pixels are not involved in the PSNR calculation. input_order (str): Whether the input order is 'HWC' or 'CHW'. Default: 'HWC'. test_y_channel (bool): Test on Y channel of YCbCr. Default: False. Returns: float: psnr result. """ assert img1.shape == img2.shape, ( f'Image shapes are differnet: {img1.shape}, {img2.shape}.') if input_order not in ['HWC', 'CHW']: raise ValueError( f'Wrong input_order {input_order}. Supported input_orders are ' '"HWC" and "CHW"') if type(img1) == torch.Tensor: if len(img1.shape) == 4: img1 = img1.squeeze(0) img1 = img1.detach().cpu().numpy().transpose(1, 2, 0) if type(img2) == torch.Tensor: if len(img2.shape) == 4: img2 = img2.squeeze(0) img2 = img2.detach().cpu().numpy().transpose(1, 2, 0) img1 = reorder_image(img1, input_order=input_order) img2 = reorder_image(img2, input_order=input_order) img1 = img1.astype(np.float64) img2 = img2.astype(np.float64) if crop_border != 0: img1 = img1[crop_border:-crop_border, crop_border:-crop_border, ...] img2 = img2[crop_border:-crop_border, crop_border:-crop_border, ...] if test_y_channel: img1 = to_y_channel(img1) img2 = to_y_channel(img2) mse = np.mean((img1 - img2)**2) if mse == 0: return float('inf') max_value = 1. if img1.max() <= 1 else 255. return 20. * np.log10(max_value / np.sqrt(mse))
def calculate_ssim(img, img2, crop_border, input_order='HWC', test_y_channel=False, **kwargs): """Calculate SSIM (structural similarity). Ref: Image quality assessment: From error visibility to structural similarity The results are the same as that of the official released MATLAB code in https://ece.uwaterloo.ca/~z70wang/research/ssim/. For three-channel images, SSIM is calculated for each channel and then averaged. Args: img (ndarray): Images with range [0, 255]. img2 (ndarray): Images with range [0, 255]. crop_border (int): Cropped pixels in each edge of an image. These pixels are not involved in the calculation. input_order (str): Whether the input order is 'HWC' or 'CHW'. Default: 'HWC'. test_y_channel (bool): Test on Y channel of YCbCr. Default: False. Returns: float: SSIM result. """ assert img.shape == img2.shape, ( f'Image shapes are different: {img.shape}, {img2.shape}.') if input_order not in ['HWC', 'CHW']: raise ValueError( f'Wrong input_order {input_order}. Supported input_orders are "HWC" and "CHW"' ) img = reorder_image(img, input_order=input_order) img2 = reorder_image(img2, input_order=input_order) if crop_border != 0: img = img[crop_border:-crop_border, crop_border:-crop_border, ...] img2 = img2[crop_border:-crop_border, crop_border:-crop_border, ...] if test_y_channel: img = to_y_channel(img) img2 = to_y_channel(img2) img = img.astype(np.float64) img2 = img2.astype(np.float64) ssims = [] for i in range(img.shape[2]): ssims.append(_ssim(img[..., i], img2[..., i])) return np.array(ssims).mean()
def calculate_psnr(img, img2, crop_border, input_order='HWC', test_y_channel=False, **kwargs): """Calculate PSNR (Peak Signal-to-Noise Ratio). Ref: https://en.wikipedia.org/wiki/Peak_signal-to-noise_ratio Args: img (ndarray): Images with range [0, 255]. img2 (ndarray): Images with range [0, 255]. crop_border (int): Cropped pixels in each edge of an image. These pixels are not involved in the PSNR calculation. input_order (str): Whether the input order is 'HWC' or 'CHW'. Default: 'HWC'. test_y_channel (bool): Test on Y channel of YCbCr. Default: False. Returns: float: psnr result. """ assert img.shape == img2.shape, ( f'Image shapes are different: {img.shape}, {img2.shape}.') if input_order not in ['HWC', 'CHW']: raise ValueError( f'Wrong input_order {input_order}. Supported input_orders are "HWC" and "CHW"' ) img = reorder_image(img, input_order=input_order) img2 = reorder_image(img2, input_order=input_order) img = img.astype(np.float64) img2 = img2.astype(np.float64) if crop_border != 0: img = img[crop_border:-crop_border, crop_border:-crop_border, ...] img2 = img2[crop_border:-crop_border, crop_border:-crop_border, ...] if test_y_channel: img = to_y_channel(img) img2 = to_y_channel(img2) mse = np.mean((img - img2)**2) if mse == 0: return float('inf') return 20. * np.log10(255. / np.sqrt(mse))
def calculate_niqe(img, crop_border, input_order='HWC', convert_to='y', **kwargs): """Calculate NIQE (Natural Image Quality Evaluator) metric. Ref: Making a "Completely Blind" Image Quality Analyzer. This implementation could produce almost the same results as the official MATLAB codes: http://live.ece.utexas.edu/research/quality/niqe_release.zip > MATLAB R2021a result for tests/data/baboon.png: 5.72957338 (5.7296) > Our re-implementation result for tests/data/baboon.png: 5.7295763 (5.7296) We use the official params estimated from the pristine dataset. We use the recommended block size (96, 96) without overlaps. Args: img (ndarray): Input image whose quality needs to be computed. The input image must be in range [0, 255] with float/int type. The input_order of image can be 'HW' or 'HWC' or 'CHW'. (BGR order) If the input order is 'HWC' or 'CHW', it will be converted to gray or Y (of YCbCr) image according to the ``convert_to`` argument. crop_border (int): Cropped pixels in each edge of an image. These pixels are not involved in the metric calculation. input_order (str): Whether the input order is 'HW', 'HWC' or 'CHW'. Default: 'HWC'. convert_to (str): Whether converted to 'y' (of MATLAB YCbCr) or 'gray'. Default: 'y'. Returns: float: NIQE result. """ ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) # we use the official params estimated from the pristine dataset. niqe_pris_params = np.load(os.path.join(ROOT_DIR, 'niqe_pris_params.npz')) mu_pris_param = niqe_pris_params['mu_pris_param'] cov_pris_param = niqe_pris_params['cov_pris_param'] gaussian_window = niqe_pris_params['gaussian_window'] img = img.astype(np.float32) if input_order != 'HW': img = reorder_image(img, input_order=input_order) if convert_to == 'y': img = to_y_channel(img) elif convert_to == 'gray': img = cv2.cvtColor(img / 255., cv2.COLOR_BGR2GRAY) * 255. img = np.squeeze(img) if crop_border != 0: img = img[crop_border:-crop_border, crop_border:-crop_border] # round is necessary for being consistent with MATLAB's result img = img.round() niqe_result = niqe(img, mu_pris_param, cov_pris_param, gaussian_window) return niqe_result
def calculate_ssim(img1, img2, crop_border, input_order='HWC', test_y_channel=False): """Calculate SSIM (structural similarity). Ref: Image quality assessment: From error visibility to structural similarity The results are the same as that of the official released MATLAB code in https://ece.uwaterloo.ca/~z70wang/research/ssim/. For three-channel images, SSIM is calculated for each channel and then averaged. Args: img1 (ndarray): Images with range [0, 255]. img2 (ndarray): Images with range [0, 255]. crop_border (int): Cropped pixels in each edge of an image. These pixels are not involved in the SSIM calculation. input_order (str): Whether the input order is 'HWC' or 'CHW'. Default: 'HWC'. test_y_channel (bool): Test on Y channel of YCbCr. Default: False. Returns: float: ssim result. """ assert img1.shape == img2.shape, ( f'Image shapes are differnet: {img1.shape}, {img2.shape}.') if input_order not in ['HWC', 'CHW']: raise ValueError( f'Wrong input_order {input_order}. Supported input_orders are ' '"HWC" and "CHW"') if type(img1) == torch.Tensor: if len(img1.shape) == 4: img1 = img1.squeeze(0) img1 = img1.detach().cpu().numpy().transpose(1, 2, 0) if type(img2) == torch.Tensor: if len(img2.shape) == 4: img2 = img2.squeeze(0) img2 = img2.detach().cpu().numpy().transpose(1, 2, 0) img1 = reorder_image(img1, input_order=input_order) img2 = reorder_image(img2, input_order=input_order) img1 = img1.astype(np.float64) img2 = img2.astype(np.float64) if crop_border != 0: img1 = img1[crop_border:-crop_border, crop_border:-crop_border, ...] img2 = img2[crop_border:-crop_border, crop_border:-crop_border, ...] if test_y_channel: img1 = to_y_channel(img1) img2 = to_y_channel(img2) return _ssim_cly(img1[..., 0], img2[..., 0]) ssims = [] # ssims_before = [] # skimage_before = skimage.metrics.structural_similarity(img1, img2, data_range=255., multichannel=True) # print('.._skimage', # skimage.metrics.structural_similarity(img1, img2, data_range=255., multichannel=True)) max_value = 1 if img1.max() <= 1 else 255 with torch.no_grad(): final_ssim = _ssim_3d(img1, img2, max_value) ssims.append(final_ssim) # for i in range(img1.shape[2]): # ssims_before.append(_ssim(img1, img2)) # print('..ssim mean , new {:.4f} and before {:.4f} .... skimage before {:.4f}'.format(np.array(ssims).mean(), np.array(ssims_before).mean(), skimage_before)) # ssims.append(skimage.metrics.structural_similarity(img1[..., i], img2[..., i], multichannel=False)) return np.array(ssims).mean()