一、SSIM算法简介

      SSIM(structural similarity index),结构相似性,是一种衡量两幅图像相似度的指标。该指标首先由德州大学奥斯丁分校的图像和视频工程实验室(Laboratory for Image and Video Engineering)提出。SSIM使用的两张图像中,一张为未经压缩的无失真图像,另一张为失真后的图像。
      与PSNR一样,SSIM也经常用作图像质量的评价。

二、SSIM算法原理

      对SSIM算法,其输入是两张图片,即要求结构相似性的两张图片。其中一张是未经压缩的无失真图像(即ground truth),另一张就是需要与无失真图片对比的图片。物体表面的亮度信息与照度反射系数有关,且场景中的物体的结构与照度是独立的,反射系数与物体有关。我们可以通过分离照度对物体的影响来探索一张图像中的结构信息。这里,把与物体结构相关的亮度和对比度作为图像中结构信息的定义。因为一个场景中的亮度和对比度总是在变化的,所以我们可以通过分别对局部的处理来得到更精确的结果。

      算法处理的原理图如下图所示:

                   

python计算ssim代码 python ssim_python计算ssim代码

      由SSIM测量系统可得相似度的测量可由三种对比模块组成,分别为:亮度,对比度,结构。接下来我们将会对这三模块函数进行定义。

      首先,对于离散信号,我们以平均灰度来作为亮度测量的估计:

                                          

python计算ssim代码 python ssim_python计算ssim代码_02

             (1)       亮度对比函数l(x,y)是关于

python计算ssim代码 python ssim_python计算ssim代码_03

的函数。       然后,由测量系统知道要把平均灰度值从信号中去除,对于离散信号

python计算ssim代码 python ssim_python计算ssim代码_04

,可使用标准差来做对比度估量值。                                  

python计算ssim代码 python ssim_python实现SSIM_05

      (2)       对比度对比函数c(x,y)就是

python计算ssim代码 python ssim_ci_06

的函数。       接下来,信号被自己的标准差相除,结构对比函数就被定义成

python计算ssim代码 python ssim_ci_07


python计算ssim代码 python ssim_python计算ssim代码_08

的函数。

       最后,三个对比模块组合成一个完整的相似测量函数:

                             

python计算ssim代码 python ssim_结构相似性_09

       (3)

       

       S(x,y)应该满足以下三个条件:

       (1) 对称性:

python计算ssim代码 python ssim_结构相似性_10

;       (2) 有界性:

python计算ssim代码 python ssim_结构相似性_11


       (3) 最大值唯一性:当且仅当x=y时,S(x,y)=1 。

 

       现在,我们定义三个对比函数。

       亮度对比函数:

                            

python计算ssim代码 python ssim_ci_12

                      (4)       常数

python计算ssim代码 python ssim_SSIM_13

是为了避免

python计算ssim代码 python ssim_结构相似性_14

接近0时造成系统的不稳定。       特别的,我们选择

python计算ssim代码 python ssim_ci_15

,L为图像灰度级数,对于8-bit灰度图像,L=255,

python计算ssim代码 python ssim_SSIM_16

。公式(4)满足上述三个条件。

       对比度对比函数:

                           

python计算ssim代码 python ssim_python计算ssim代码_17

                        (5)       常数

python计算ssim代码 python ssim_python实现SSIM_18

,且

python计算ssim代码 python ssim_ci_19

。公式(5)依然满足上述三个条件。

       结构对比函数:

                           

python计算ssim代码 python ssim_python实现SSIM_20

                          (6)

       其中

                      

python计算ssim代码 python ssim_ci_21

                   (7)

      最后把三个函数组合起来,得到SSIM指数函数:

                      

python计算ssim代码 python ssim_结构相似性_22

             (8)      这里

python计算ssim代码 python ssim_python计算ssim代码_23

,用来调整三个模块间的重要性。      为了得到简化形式,设

python计算ssim代码 python ssim_结构相似性_24

,得到:                     

python计算ssim代码 python ssim_SSIM_25

            (9)

三、SSIM指数应用于图像质量评估

在图像质量评估之中,局部求SSIM指数的效果要好于全局。第一,图像的统计特征通常在空间中分布不均;第二,图像的失真情况在空间中也是变化的;第三,在正常视距内,人们只能将视线聚焦在图像的一个区域内,所以局部处理更符合人类视觉系统的特点;第四,局部质量检测能得到图片空间质量变化的映射矩阵,结果可服务到其他应用中。

     所以,在上述公式中,

python计算ssim代码 python ssim_python实现SSIM_26

都加入了一个8*8的方形窗,并且逐像素的遍历整幅图片。每一步计算,

python计算ssim代码 python ssim_python实现SSIM_26

和SSIM都是基于窗口内像素的,最终得到一个SSIM指数映射矩阵,由局部SSIM指数组成。然而,简单的加窗会使映射矩阵出现不良的“分块”效应。为解决这问题,我们使用11*11的对称高斯加权函数

python计算ssim代码 python ssim_ci_28

作为加权窗口,标准差为1.5,且                                   

python计算ssim代码 python ssim_python实现SSIM_29

              (10)

 


python计算ssim代码 python ssim_python实现SSIM_26

的估计值表示为:                                 

python计算ssim代码 python ssim_SSIM_31

              (11)                         

python计算ssim代码 python ssim_python实现SSIM_32

         (12)                          

python计算ssim代码 python ssim_结构相似性_33

     (13)

       应用这种加窗方法,映射矩阵就可展现出局部各向同性的性质。

       在这里,经过一些实验总结,我们把K1设为0.01,K2设为0.03,然后用平均SSIM指数作为整幅图像的估计质量评价:

                 

python计算ssim代码 python ssim_python计算ssim代码_34

   (14)其中X,Y为图像,

python计算ssim代码 python ssim_python计算ssim代码_35

为局部SSIM指数在映射中的位置,MN为局部窗口的数量。

三、python代码实现

代码是从项目里面直接贴过来的,只改了其中一些部分,代码的目录格式如下所示:

├─python-ssim
│  │  python-ssim.py
│  │  README.md
│  │  使用.txt
│  └─data
│          1.jpg
│          2.jpg
│          3.jpg
│          4.jpg
│          5.png
│          6.png
 

python-ssim.py文件

import numpy
import scipy.ndimage
from scipy.ndimage import imread
from numpy.ma.core import exp
from scipy.constants.constants import pi

img_mat_1=imread('./data/5.png', flatten=True)
img_mat_2=imread('./data/6.png', flatten=True)


'''
The function to compute SSIM
@param param: img_mat_1 1st 2D matrix
@param param: img_mat_2 2nd 2D matrix
'''
def compute_ssim(img_mat_1, img_mat_2):
    #Variables for Gaussian kernel definition
    gaussian_kernel_sigma=1.5
    gaussian_kernel_width=11
    gaussian_kernel=numpy.zeros((gaussian_kernel_width,gaussian_kernel_width))
    
    #Fill Gaussian kernel
    for i in range(gaussian_kernel_width):
        for j in range(gaussian_kernel_width):
            gaussian_kernel[i,j]=\
            (1/(2*pi*(gaussian_kernel_sigma**2)))*\
            exp(-(((i-5)**2)+((j-5)**2))/(2*(gaussian_kernel_sigma**2)))

    #Convert image matrices to double precision (like in the Matlab version)
    img_mat_1=img_mat_1.astype(numpy.float)
    img_mat_2=img_mat_2.astype(numpy.float)
    
    #Squares of input matrices
    img_mat_1_sq=img_mat_1**2
    img_mat_2_sq=img_mat_2**2
    img_mat_12=img_mat_1*img_mat_2
    
    #Means obtained by Gaussian filtering of inputs
    img_mat_mu_1=scipy.ndimage.filters.convolve(img_mat_1,gaussian_kernel)
    img_mat_mu_2=scipy.ndimage.filters.convolve(img_mat_2,gaussian_kernel)
        
    #Squares of means
    img_mat_mu_1_sq=img_mat_mu_1**2
    img_mat_mu_2_sq=img_mat_mu_2**2
    img_mat_mu_12=img_mat_mu_1*img_mat_mu_2
    
    #Variances obtained by Gaussian filtering of inputs' squares
    img_mat_sigma_1_sq=scipy.ndimage.filters.convolve(img_mat_1_sq,gaussian_kernel)
    img_mat_sigma_2_sq=scipy.ndimage.filters.convolve(img_mat_2_sq,gaussian_kernel)
    
    #Covariance
    img_mat_sigma_12=scipy.ndimage.filters.convolve(img_mat_12,gaussian_kernel)
    
    #Centered squares of variances
    img_mat_sigma_1_sq=img_mat_sigma_1_sq-img_mat_mu_1_sq
    img_mat_sigma_2_sq=img_mat_sigma_2_sq-img_mat_mu_2_sq
    img_mat_sigma_12=img_mat_sigma_12-img_mat_mu_12;
    
    #c1/c2 constants
    #First use: manual fitting
    c_1=6.5025
    c_2=58.5225
    
    #Second use: change k1,k2 & c1,c2 depend on L (width of color map)
    l=255
    k_1=0.01
    c_1=(k_1*l)**2
    k_2=0.03
    c_2=(k_2*l)**2
    
    #Numerator of SSIM
    num_ssim=(2*img_mat_mu_12+c_1)*(2*img_mat_sigma_12+c_2)
    #Denominator of SSIM
    den_ssim=(img_mat_mu_1_sq+img_mat_mu_2_sq+c_1)*\
    (img_mat_sigma_1_sq+img_mat_sigma_2_sq+c_2)
    #SSIM
    ssim_map=num_ssim/den_ssim
    index=numpy.average(ssim_map)

    print(index)

    return index

    
compute_ssim(img_mat_1, img_mat_2)

三、结果示例

示例1

python计算ssim代码 python ssim_python计算ssim代码_36

python计算ssim代码 python ssim_ci_37

示例2

python计算ssim代码 python ssim_SSIM_38

python计算ssim代码 python ssim_python计算ssim代码_39

 

python计算ssim代码 python ssim_SSIM_40

示例3

python计算ssim代码 python ssim_结构相似性_41

python计算ssim代码 python ssim_SSIM_42

python计算ssim代码 python ssim_python实现SSIM_43


参考:指数应用于图像质量评估

https://baike.baidu.com/item/SSIM/2091025?fr=aladdin