损失函数-SSIM(structure similarity)结构相似性

SSIM是一种衡量两幅图片相似度的指标。
出处来自于2004年的一篇TIP,
标题为:Image Quality Assessment: From Error Visibility to Structural Similarity
地址为:https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=1284395

理论

详细推导见:https://blog.csdn.net/weixin_41923961/article/details/84795832
损失函数-SSIM(structure similarity)结构相似性_第1张图片

损失函数-SSIM(structure similarity)结构相似性_第2张图片

应用方法:

实际应用中,SSIM(x,y)通过作以(x,y)为中心的窗口,获得局部(x,y)点的局部均值,求取Ux矩阵,Uy矩阵;

sigmax平方通过 “方差等于平方的期望减去期望的平方,平方的均值减去均值的平方”求得

sigmaxy 通过“协方差,乘积的均值减去均值的乘积”求得

 

tensorflow代码

#%%

import tensorflow as tf
import numpy as np
import torch
 
#%%
#模仿matlab的fspecial函数,创建滤波算子(计算SSIM用)
def _tf_fspecial_gauss(size, sigma, channels=1):
    """Function to mimic the 'fspecial' gaussian MATLAB function
    """
    x_data, y_data = np.mgrid[-size//2 + 1:size//2 + 1, -size//2 + 1:size//2 + 1]

    x_data = np.expand_dims(x_data, axis=-1)
    x_data = np.expand_dims(x_data, axis=-1)

    y_data = np.expand_dims(y_data, axis=-1)
    y_data = np.expand_dims(y_data, axis=-1)

    x = tf.constant(x_data, dtype=tf.float32)
    y = tf.constant(y_data, dtype=tf.float32)

    g = tf.exp(-((x**2 + y**2)/(2.0*sigma**2)))

    window = g / tf.reduce_sum(g)
    return tf.tile(window, (1,1,channels,channels))


#计算ssim
def tf_ssim(img1, img2, cs_map=False, mean_metric=True, filter_size=11, filter_sigma=1.5):
    
    _, height, width, ch = img1.get_shape().as_list()
    size = min(filter_size, height, width)
    sigma = size * filter_sigma / filter_size if filter_size else 0

    window = _tf_fspecial_gauss(size, sigma, ch) # window shape [size, size]
    K1 = 0.01
    K2 = 0.03
    L = 1  # depth of image (255 in case the image has a differnt scale)
    C1 = (K1*L)**2
    C2 = (K2*L)**2

    #求取滑块内均值Ux Uy,均方值Ux_sq
    padded_img1 = tf.pad(img1, [[0, 0], [size//2, size//2], [size//2, size//2], [0, 0]], mode="CONSTANT")       #img1 上下左右补零
    padded_img2 = tf.pad(img2, [[0, 0], [size//2, size//2], [size//2, size//2], [0, 0]], mode="CONSTANT")       #img2 上下左右补零
    mu1 = tf.nn.conv2d(padded_img1, window, strides=[1,1,1,1], padding='VALID') #利用滑动窗口,求取窗口内图像的的加权平均
    mu2 = tf.nn.conv2d(padded_img2, window, strides=[1,1,1,1], padding='VALID')
    mu1_sq = mu1*mu1    #img(x,y) Ux*Ux 均方
    mu2_sq = mu2*mu2    #img(x,y) Uy*Uy
    mu1_mu2 = mu1*mu2   #img(x,y) Ux*Uy

    #求取方差,方差等于平方的期望减去期望的平方,平方的均值减去均值的平方
    paddedimg11 = padded_img1*padded_img1
    paddedimg22 = padded_img2*padded_img2
    paddedimg12 = padded_img1*padded_img2

    sigma1_sq = tf.nn.conv2d(paddedimg11, window, strides=[1,1,1,1],padding='VALID') - mu1_sq   #sigma1方差
    sigma2_sq = tf.nn.conv2d(paddedimg22, window, strides=[1,1,1,1],padding='VALID') - mu2_sq   #sigma2方差
    sigma12 = tf.nn.conv2d(paddedimg12, window, strides=[1,1,1,1],padding='VALID') - mu1_mu2    #sigma12协方差,乘积的均值减去均值的乘积

    ssim_value = tf.clip_by_value(((2*mu1_mu2 + C1)*(2*sigma12 + C2))/((mu1_sq + mu2_sq + C1)*(sigma1_sq + sigma2_sq + C2)), 0, 1)
    if cs_map:          #只考虑contrast对比度,structure结构,不考虑light亮度
        cs_map_value = tf.clip_by_value((2*sigma12 + C2)/(sigma1_sq + sigma2_sq + C2), 0, 1)    #对比度结构map
        value = (ssim_value, cs_map_value)
    else:
        value = ssim_value
    if mean_metric:             #求取矩阵的均值,否则返回ssim矩阵
        value = tf.reduce_mean(value)
    return value


img1 = np.arange(10000,dtype=np.float32).reshape([1,100,100,1])
img2 = np.arange(10000,dtype=np.float32).reshape([1,100,100,1])-2

with tf.Session() as sess:
    value = tf_ssim(tf.constant(img1),tf.constant(img2))
    print(sess.run(value))

输出结果:

0.9999688

 

你可能感兴趣的:(图像处理,算法)