赞
踩
在比较两幅图像误差或者相似度时,常用的衡量方法有MAE和MSE,
https://blog.csdn.net/u011875342/article/details/78036380
但是上述这两种损失不足以表达人的视觉系统对图像的直观感受,有时候两张图片只是亮度不同,但是他们之间的MSE loss相差很大,而一副很模糊与另一幅很清晰的图,他们的MSE loss可能反而很小。
而SSIM(Structural Similarity)结构相似度更能反映人类视觉系统对两幅图相似性的判断。
具体理论和公式计算可见以下链接:
https://mp.weixin.qq.com/s/hGum0fXrKUHCoaInVVS3rQ
目前可以从anaconda自带的库skimage库中找到该函数,具体调用方法如下:
另外,也可以调用其他图像相似度评价函数,如MSE,PSNR。
from skimage.measure import compare_ssim
from skimage.measure import compare_mse
from skimage measure import compare_psnr
这三个函数只默认支持 两张图片进行对比,无法进行批量比较。X,Y必须都为数组。
另外,如果是X Y 都是彩色图三色,即为多通道的,则需要设置mutichannel=True;
import keras
from skimage.measure import compare_ssim
from skimage.measure import compare_mse
img1=keras.preprocessing.image.load_img(img_path1_1) #先通过keras读取图片,
img1_array=keras.preprocessing.image.img_to_array(img1)/255 #将图片转换为数组
img2=keras.preprocessing.image.load_img(img_path2_2)
img2_array=keras.preprocessing.image.img_to_array(img2)/255
ssim=compare_ssim(img1_array,img2_array,multichannel=True)
mse=compare_mse(img1_array,img2_array)
print('ssim value:' ,ssim)
print('mse value:',mse)
ssim value: 0.5348699316504579
mse value: 0.030186621034944017
一般情况下,ssim在-1~1之间,数值越大代表相似度越高。
肉眼上两张图片相似度较高,但是ssim值却不到0.6.说明 ssim可以很容易捕捉到两幅图像之间的差异。因此可以考虑使用ssim作为图像回归中的损失函数;
两张图片如下
详细介绍可以参考次链接:https://www.jianshu.com/p/ca343a441e6d
import tensorflow as tf import numpy as np #a为数组 a=np.random.randint(0,10,(2,3)) print('type of a:',type(a)) print() #将a转化成Tensor tensor_a=tf.convert_to_tensor(a) print('type of tensor_a:',type(tensor_a)) print() #将tensor转化成数组 with tf.Session(): array_a=tensor_a.eval() print('type of array_a:',type(array_a)) print()
输出结果如下:
type of a: <class ‘numpy.ndarray’>
type of tensor_a: <class ‘tensorflow.python.framework.ops.Tensor’>
type of array_a: <class ‘numpy.ndarray’>
需要说明的是:ssim为衡量图片相似度的,数值在-1~1之间,数值越大,越相似。而训练神经网络的为了使得损失函数越来越小,因此这里选取 1-ssim作为损失。
目前keras中不支持ssim作为损失函数,但是tensorflow中有ssim函数
可以参看tensorflow文档:
https://www.w3cschool.cn/tensorflow_python/tensorflow_python-c5xz2rsh.html 说明
https://www.w3cschool.cn/tensorflow_python/tensorflow_python-ats62pzl.html 源码
如果想在keras中使用ssim为损失函数,可以自己根据自己要求单独写,损失函数写法可以参考我的另一篇博客,链接如下:
https://blog.csdn.net/weixin_43718675/article/details/89041352
我尝试了两种写法,一种是使用skimage库,一种是使用tensorflow
先查看keras中损失函数的输入数据type和维度:
https://keras.io/zh/losses/
https://github.com/keras-team/keras/blob/master/keras/losses.py
如:
def mean_squared_error(y_true, y_pred):
return K.mean(K.square(y_pred - y_true), axis=-1)
这里面默认的输入和输出都是 Tensor
因此自定义损失函数时候,需要保证输入输出都是张量
4.1 使用skimag库
def my_ssim_loss(y_true,y_pred): from keras import backend as K import tensorflow as tf print(type(y_pred)) print('y_shape:',y_true.shape) with tf.Session(): y_pred=y_pred.eval() y_true=y_true.eval() # y_true=np.array(y_true) # y_pred=np.array(y_pred) print(type(y_pred)) print('y_shape:',y_true.shape) shape=y_true.shape if len(shape)==5: batch=shape[0] set_length=shape[1] total_loss=np.zeros((batch,set_length,400,400)) for i in range(batch): for j in range(set_length): ssim_loss=1-compare_ssim(np.array(y_true[i,j]),np.array(y_pred[i,j]),multichannel=True) total_loss[i,j,:,:] +=ssim_loss # loss.append(ssim_loss) # loss=np.array(loss).reshape(batch,set_lenth) total_loss=tf.convert_to_tensor(total_loss) print(type(total_loss)) print('total_loss_shape:',total_loss.shape) return total_loss
由于使用了ConvLSTM2D, 因此输入y为5D的,使用MSE为loss时候,损失为4D的,为了与mse_loss保持一致,这里使用扩充,具体过程见以上代码。虽然在类型和维度上保持了一致,可是在调用时,还是出错了。
原因不太清楚。
4.2 使用tf.image.ssim
def tf_ssim_loss(y_true,y_pred): import keras.backend as k # total_loss=1-tf.image.ssim_multiscale(y_true,y_pred,max_val=1) total_loss=1-tf.image.ssim(y_true,y_pred,max_val=1) with tf.Session(): total_loss=1-total_loss.eval() batch=total_loss.shape[0] set_length=total_loss.shape[1] loss=np.zeros((batch,set_length,400,400)) for i in range(batch): for j in range(set_length): loss[i,j]=total_loss[i,j] loss=tf.convert_to_tensor(loss) return loss
同样为了保持维度,还是出错。
后来,我不人为进行维度设置,而是使用tf默认的输出loss维度,结果倒还正确了
可能上述出错的原因在于:传入的y_true等张量虽然是5D的,但是其每个维度的大小是占位符placeholder,无法实体化,即无法进行类似batch=total_loss.shape[0]这样的获取维度具体信息的操作。
def tf_ssim_loss(y_true,y_pred):
total_loss=1-tf.image.ssim(y_true,y_pred,max_val=1)
return total_loss
model.compile(optimizer=opt,loss=tf_ssim_loss,metrics=['accuracy'])
这里的total_loss的维度为2D,即[batch, set_length ]而上述使用MSE时候,loss维度为4D,即[batch, set_length, width,high]。
以上!
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。