• 图像质量评估——PSNR:峰值信噪比和SSIM:结构相似性(纯手撸代码)


    一、PSNR

    1.1 原理

    PSNR 是一种衡量图像质量的指标,它是通过比较原始图像和失真图像之间的差异来计算的。具体来说,PSNR 是通过比较两幅图像的每个像素值来计算的。

    在这里插入图片描述

    PSNR 主要比较的是两幅图像的每个像素值的差异,这种差异被称为 “噪声”。如果两幅图像完全相同,那么噪声就为零,PSNR 就为无穷大。如果两幅图像有很大的差异,那么噪声就会很大,PSNR 就会相应地减小。因此,PSNR 越大,表示图像质量越好。

    1.2 代码

    import numpy as np
    import cv2
    
    def reorder_image(img, input_order='HWC', output_order='HWC'):
        ''' reorder_image '''
        if input_order not in ['HWC', 'CHW']:
            raise ValueError(f'Wrong input_order {input_order}. Supported input_orders are ' "'HWC' and 'CHW'")
        if output_order not in ['HWC', 'CHW']:
            raise ValueError(f'Wrong output_order {output_order}. Supported output_orders are ' "'HWC' and 'CHW'")
        if len(img.shape) == 2:
            img, input_order = img[..., None], 'CHW'
        if input_order == 'CHW' and output_order == 'HWC':
            img = img.transpose(1, 2, 0)
        elif input_order == 'HWC' and output_order == 'CHW':
            img = img.transpose(2, 0, 1)
        return img
    
    def _convert_input_type_range(img):
        ''' convert input to [0, 1] '''
        img_type = img.dtype
        img = img.astype(np.float32)
        if img_type == np.float32:
            pass
        elif img_type == np.uint8:
            img /= 255.
        else:
            raise TypeError(f'The img type should be np.float32 or np.uint8, but got {img_type}')
        return img
        
    def _convert_output_type_range(img, dst_type):
        ''' convert output to dst_type '''
        if dst_type not in (np.uint8, np.float32):
            raise TypeError(f'The dst_type should be np.float32 or np.uint8, but got {dst_type}')
        if dst_type == np.uint8:
            img = img.round()
        else:
            img /= 255.
        return img.astype(dst_type)
    
    def bgr2ycbcr(img, y_only=False):
        ''' bgr space to ycbcr space '''
        img_type = img.dtype
        img = _convert_input_type_range(img)
        if y_only:
            out_img = np.dot(img, [24.966, 128.553, 65.481]) + 16.0
        else:
            out_img = np.matmul(
                img, [[24.966, 112.0, -18.214], [128.553, -74.203, -93.786], [65.481, -37.797, 112.0]]) + [16, 128, 128]
        out_img = _convert_output_type_range(out_img, img_type)
        return out_img
    
    def calculate_psnr(img, img2, crop_border, input_order='HWC', test_y_channel=False, **_kwargs):
        ''' calculate_psnr '''
        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"')
        if not isinstance(crop_border, (list, tuple)):
            crop_border = (crop_border, crop_border)
        img = reorder_image(img, input_order=input_order).astype(np.float64)
        img2 = reorder_image(img2, input_order=input_order).astype(np.float64)
        if crop_border[0] != 0:
            img = img[crop_border[0]:-crop_border[0], ...]
            img2 = img2[crop_border[0]:-crop_border[0], ...]
        if crop_border[1] != 0:
            img = img[:, crop_border[1]:-crop_border[1], ...]
            img2 = img2[:, crop_border[1]:-crop_border[1], ...]
        if test_y_channel:
            img = bgr2ycbcr(img.astype(np.float32) / 255., y_only=True) * 255
            img2 = bgr2ycbcr(img2.astype(np.float32) / 255., y_only=True) * 255
        mse = np.mean((img - img2)**2)                 # MSE均方误差
        if mse == 0:
            return float('inf')
        PSNR_result = 20. * np.log10(255. / np.sqrt(mse))
        return PSNR_result
    
    if __name__ == '__main__':
    	img1 = cv2.imread("datasets/Set5/GTmod12/hh74.png")  # 读入图片1
        img2 = cv2.imread("visualization/Set5/hh74_ETDS_M4C32_x4.png")  # 读入图片2
        PSNR_result = calculate_psnr(img1, img2, 4)
    
        print("PSNR_result = ",PSNR_result)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    1.3 运行测试结果

    在这里插入图片描述

    二、SSIM

    2.1 原理

    SSIM(结构相似性)是一种衡量两幅图像相似度的指标。

    在这里插入图片描述

    SSIM 主要比较的是两幅图像的亮度、对比度和结构。这三个因素都是人类视觉系统在评价图像质量时的重要因素。因此,SSIM 能够更好地反映人类视觉系统对图像质量的感知。

    2.2 代码

    
    import numpy as np
    import cv2
    
    def reorder_image(img, input_order='HWC', output_order='HWC'):
        ''' reorder_image '''
        if input_order not in ['HWC', 'CHW']:
            raise ValueError(f'Wrong input_order {input_order}. Supported input_orders are ' "'HWC' and 'CHW'")
        if output_order not in ['HWC', 'CHW']:
            raise ValueError(f'Wrong output_order {output_order}. Supported output_orders are ' "'HWC' and 'CHW'")
        if len(img.shape) == 2:
            img, input_order = img[..., None], 'CHW'
        if input_order == 'CHW' and output_order == 'HWC':
            img = img.transpose(1, 2, 0)
        elif input_order == 'HWC' and output_order == 'CHW':
            img = img.transpose(2, 0, 1)
        return img
    
    def _convert_input_type_range(img):
        ''' convert input to [0, 1] '''
        img_type = img.dtype
        img = img.astype(np.float32)
        if img_type == np.float32:
            pass
        elif img_type == np.uint8:
            img /= 255.
        else:
            raise TypeError(f'The img type should be np.float32 or np.uint8, but got {img_type}')
        return img
    
    def _convert_output_type_range(img, dst_type):
        ''' convert output to dst_type '''
        if dst_type not in (np.uint8, np.float32):
            raise TypeError(f'The dst_type should be np.float32 or np.uint8, but got {dst_type}')
        if dst_type == np.uint8:
            img = img.round()
        else:
            img /= 255.
        return img.astype(dst_type)
    
    def bgr2ycbcr(img, y_only=False):
        ''' bgr space to ycbcr space '''
        img_type = img.dtype
        img = _convert_input_type_range(img)
        if y_only:
            out_img = np.dot(img, [24.966, 128.553, 65.481]) + 16.0
        else:
            out_img = np.matmul(
                img, [[24.966, 112.0, -18.214], [128.553, -74.203, -93.786], [65.481, -37.797, 112.0]]) + [16, 128, 128]
        out_img = _convert_output_type_range(out_img, img_type)
        return out_img
    
    def _ssim(img, img2):
        ''' ssim '''
        c1, c2 = (0.01 * 255)**2, (0.03 * 255)**2
        img = img.astype(np.float64)
        img2 = img2.astype(np.float64)
        kernel = cv2.getGaussianKernel(11, 1.5)
        window = np.outer(kernel, kernel.transpose())
        mu1 = cv2.filter2D(img, -1, window)[5:-5, 5:-5]
        mu2 = cv2.filter2D(img2, -1, window)[5:-5, 5:-5]
        mu1_sq, mu2_sq = mu1**2, mu2**2
        mu1_mu2 = mu1 * mu2
        sigma1_sq = cv2.filter2D(img**2, -1, window)[5:-5, 5:-5] - mu1_sq
        sigma2_sq = cv2.filter2D(img2**2, -1, window)[5:-5, 5:-5] - mu2_sq
        sigma12 = cv2.filter2D(img * img2, -1, window)[5:-5, 5:-5] - mu1_mu2
        ssim_map = ((2 * mu1_mu2 + c1) * (2 * sigma12 + c2)) / ((mu1_sq + mu2_sq + c1) * (sigma1_sq + sigma2_sq + c2))
        return ssim_map.mean()
    
    
    def calculate_ssim(img, img2, crop_border, input_order='HWC', test_y_channel=False, **_kwargs):
        ''' calculate_ssim '''
        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"')
        if not isinstance(crop_border, (list, tuple)):
            crop_border = (crop_border, crop_border)
        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] != 0:
            img = img[crop_border[0]:-crop_border[0], ...]
            img2 = img2[crop_border[0]:-crop_border[0], ...]
        if crop_border[1] != 0:
            img = img[:, crop_border[1]:-crop_border[1], ...]
            img2 = img2[:, crop_border[1]:-crop_border[1], ...]
        if test_y_channel:
            img = bgr2ycbcr(img.astype(np.float32) / 255., y_only=True)[..., None] * 255
            img2 = bgr2ycbcr(img2.astype(np.float32) / 255., y_only=True)[..., None] * 255
        ssims = []
        for i in range(img.shape[2]):
            ssims.append(_ssim(img[..., i], img2[..., i]))
        ssims_result = np.array(ssims).mean()
        return ssims_result
    
    if __name__ == '__main__':
        img1 = cv2.imread("datasets/Set5/GTmod12/hh74.png")  # 读入图片1
        img2 = cv2.imread("visualization/Set5/hh74_ETDS_M4C32_x4.png")  # 读入图片2
        ssims_result = calculate_ssim(img1, img2, 4)
    
        print("PSNR_result = ", ssims_result)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102

    2.3 运行测试结果

    在这里插入图片描述

    三、总结

    以上就是图像质量评估——PSNR:峰值信噪比和SSIM:结构相似性的原理及详细代码,希望能帮到你,总结不易,撸码不易,三连多多支持,谢谢!

  • 相关阅读:
    Spring Cloud Gateway集成Nacos和Swagger聚合Api文档
    element ui this.$msgbox 自定义组件
    MIT课程分布式系统学习07——Fault Tolerance raft2
    iso27001信息安全体系认证咨询
    [附源码]Python计算机毕业设计SSM健身房预约平台(程序+LW)
    Mockito -- 如何Mock Util类中的static 方法?
    Hive基础知识概念
    react 生命周期
    JavaScript面向对象(2)—继承的实现
    [山东科技大学OJ]2045 Problem F: 稳定的排序
  • 原文地址:https://blog.csdn.net/qq_40280673/article/details/134280721