作者:Pranjal Datta

编译:ronghuaiyang

导读

有很多资料解释了SSIM背后的理论,但很少有资源深入研究细节,本文就是试图填补这一空白的谦虚尝试。

最近,在实现一篇深度估计论文时,我遇到了术语结构相似性指数(SSIM)。SSIM作为度量两个给定图像之间相似度的度量指标。由于这项技术从2004年就开始了,有很多资料解释了SSIM背后的理论,但很少有资源深入研究细节,这对于基于梯度的实现太特别了,因为SSIM经常被用作损失函数。因此,本文就是我试图填补这一空白的谦虚尝试!

本文的目标有两个:

  • 解释SSIM背后的理论和直觉,探索其在当前前沿深度学习中的一些应用。

  • 深入PyTorch实现。

所以让我们开始吧!

理论

SSIM首先在2004年IEEE的论文中被引入,Image Quality Assessment: From Error Visibility to Structural Similarity

评估感知图像质量的客观方法,传统上试图量化失真图像和参考图像之间的误差(差异)可见性,使用人类视觉系统的各种已知属性。在假设人类视觉感知高度适应于从场景中提取结构信息的前提下,我们引入了一种基于结构信息退化的质量评估替代互补框架。

小结:作者提出了两点要点,

  • 大多数图像质量评估技术依赖于量化参考图像和样本图像之间的误差。一种常用的度量是量化样本和参考图像之间对应的每个像素的值的差异(例如,使用均方误差)

  • 人类视觉感知系统能够从一个场景中识别结构信息,从而识别从参考场景和样本场景中提取的信息之间的差异。因此,复制此行为的指标将在涉及区分样本图像和参考图像的任务中执行得更好。

结构相似性指数(SSIM)度量从一幅图像中提取3个关键特征:

  • 亮度

  • 对比度

  • 结构

两幅图像的比较就是根据这3个特征进行的。

结构相似性度量系统的组织和流程如下图所示。X和Y分别为参考图像和样本图像。

图1: 结构相似性度量系统

这个度量是计算什么呢?

这个系统计算2幅给定图像之间的结构相似度指数,其值在-1到+1之间。值为+1表示两张给定的图像非常相似或相同,值为-1表示两张给定的图像非常不同。这些值通常被调整到范围[0,1],其中极端值具有相同的含义。

现在,让我们简要地探讨一下这些特性是如何用数学表示的,以及它们是如何影响最终的SSIM分数的。

  • 亮度:亮度通过对所有像素值进行平均测量。用μ表示,公式如下:

式中,xi为图像x的第i个像素值,N为像素值的总数。

  • 对比度:取所有像素值的标准差(方差的平方根)来测量。用σ表示,表示为:

其中x和y为两幅图像,μ为图像像素值的平均值。

  • 结构:结构比较是通过使用一个合并公式来完成的(后面会详细介绍),但在本质上,我们用输入信号的标准差来除以它,因此结果有单位标准差,这可以得到一个更稳健的比较。

其中x是输入图像。

现在我们已经建立了这三个参数背后的数学直觉。我们还没有完成数学运算,还有一点。我们现在缺少的是比较函数,它可以在这些参数上比较两个给定的图像,最后,一个组合函数,将它们组合在一起。在这里,我们定义了比较函数,最后定义了产生相似性指标值的组合函数。

  • 亮度比较函数:由函数定义,l(x, y),如下图所示。μ表示给定图像的平均值。x和y是被比较的两个图像。

其中C1为常数,保证分母为0时的稳定性。C1这样给出:

  • 对比度比较函数:由函数c(x, y)定义,如下图所示。σ表示给定图像的标准差。x和y是被比较的两个图像。

其中C2这样给出:

  • 结构比较函数:由函数s(x, y)定义,如下图所示。σ表示给定图像的标准差。x和y是被比较的两个图像。

其中σ(xy)定义为:

最后,SSIM定义为:

其中 α > 0, β > 0, γ > 0 表示每个度量标准的相对重要性。为了简化表达式,我们设:

现在问题来了!

虽然你可以使用上述公式实现SSIM,但它可能不如已有的现成实现那么好,正如作者解释的那样,

对于图像质量评估,应该局部应用SSIM指数而不是全局应用。首先,图像统计特征通常是高度空间非平稳的。其次,图像失真可能取决于或不取决于局部图像统计,也可能是空间变量。第三,在典型的观测距离下,由于HVS的凹点特征,人眼一次只能看到图像中的具有高分辨率的局部区域。最后,局部质量测量可以提供一个空间变化的图像质量图,它提供了更多关于图像质量退化的信息,在某些应用中可能有用。

总结:与其在全局范围内应用上述度量值(即一次在图像上的所有区域),不如在局部范围内应用这些度量值(即在图像的小部分中,然后取整体的平均值)。

这种方法通常被称为平均结构相似度指数。

由于方法上的这种变化,我们的公式也应该进行修改以反映相同的情况(应该注意的是,这种方法更常见,将用于解释代码)。

(:如果下面的内容看起来有点难以应付,不用担心!如果你理解了它的要点,那么浏览一下代码会让你更清楚。)

作者使用一个11x11圆对称高斯加权函数(基本上就是一个11x11矩阵,其值来自高斯分布)在整个图像上逐像素移动。在每一步中,在局部窗口内计算局部统计信息和SSIM索引。由于我们现在在局部计算,我们的公式被修改为:

其中wi是高斯加权函数。

如果你觉得这有点不直观,不用担心!可以将wi想象成乘法,并通过一些数学技巧来计算所需的值。

一旦对整个图像进行了计算,我们只需取所有局部SSIM值的平均值,就得到了全局的 SSIM值。

理论终于完成了!现在进入代码!

代码

在深入研究代码之前,需要注意的是,我们不会遍历每行,但是我们将深入研究最基本的那些代码。让我们开始吧!

首先,让我们研究一些执行一些基本任务的函数。

Function #1: gaussian(window_size, sigma)

这个函数本质上是从一个高斯分布中采样的一个数字列表(长度等于window_size)。所有元素的和等于1,值被归一化。Sigma是高斯分布的标准差。

注意:它用于生成上面提到的11x11高斯窗口。

例子

Code:gauss_dis = gaussian(11, 1.5)
print("Distribution: ", gauss_dis)
print("Sum of Gauss Distribution:", torch.sum(gauss_dis))Output: Distribution:  tensor([0.0010, 0.0076, 0.0360, 0.1094, 0.2130, 0.2660, 0.2130, 0.1094, 0.0360,0.0076, 0.0010])Sum of Gauss Distribution: tensor(1.)

Function #2: create_window(window_size, channel)

当我们生成一维高斯张量时,一维张量本身对我们没有用处。因此,我们必须将它转换为一个2D张量(我们之前谈到的11x11张量)。该函数的步骤如下:

  • 使用高斯函数生成一维张量

  • 该一维张量与其转置交叉相乘得到二维张量(这保持了高斯特性)

  • 增加两个额外的维度,将其转换为四维。(仅当SSIM在计算机视觉中用作损失函数时)

  • Reshape得到PyTorch的权值格式。

Code:window = create_window(11, 3)
print(window.shape)Output:torch.Size([3, 1, 11, 11])

现在我们已经研究了两个函数,让我们看一下主代码!核心的SSIM是通过下面讨论的SSIM()函数实现的。

Function #3: ssim(img1, img2, val_range, window_size=11, window=None, size_average=True, full=False)

在讨论基本内容之前,让我们先看看在计算ssim指标之前函数中发生了什么,

  • 我们设置了标准化像素的最大值

  • 如果在函数调用期间没有提供窗口,我们通过*create_window()*函数初始化高斯窗口。

一旦这些步骤完成,我们开始计算各种值,这是得到最终SSIM分数所需要的。

:由于我们在计算局部统计数据,并且我们需要使其计算更效率,使用的公式有轻微不同。

我们首先计算μ(x),μ(y),它们的平方,以及μ(xy)。这里的channels存储了输入图像的彩色通道的数量。参数的groups用于应用卷积滤波器的所有的输入通道。

channels, height, width = img1.size()mu1 = F.conv2d(img1, window, padding=pad, groups=channels)
mu2 = F.conv2d(img2, window, padding=pad, groups=channels)mu1_sq = mu1 ** 2
mu2_sq = mu2 ** 2mu12 = mu1 * mu2
  • 然后我们继续计算σ(x), σ(y)和σ(xy)的平方。

sigma1_sq = F.conv2d(img1 * img1, window, padding=pad, groups=channels) - mu1_sq
sigma2_sq = F.conv2d(img2 * img2, window, padding=pad, groups=channels) - mu2_s
sigma12 =  F.conv2d(img1 * img2, window, padding=pad, groups=channels) - mu12
  • 第三,我们根据提到的公式计算对比度量

contrast_metric = (2.0 * sigma12 + C2) / (sigma1_sq + sigma2_sq + C2)contrast_metric = torch.mean(contrast_metric)
  • 最后,我们计算SSIM分数并根据前面提到的公式返回平均值

numerator1 = 2 * mu12 + C1
numerator2 = 2 * sigma12 + C2
denominator1 = mu1_sq + mu2_sq + C1
denominator2 = sigma1_sq + sigma2_sq + C2ssim_score = (numerator1 * numerator2) / (denominator1 * denominator2)return ssim_score.mean()

代码的执行情况

我们将在三种情况下测试代码,以检查其执行情况。

  • Case #1: 真图像vs假图像

在第一个场景中,我们对2个非常不同的图像执行SSIM。其中一个是真图像,而另一个是假图像。(既然我们测量的是差异,真伪标签本质上是可以互换的,它们仅被用作参考。)

这些图像是:

假图像(左)真图像(右)

代码如下:

Code: img1 = load_images("img1.jpg") # helper function to load images
img2 = load_images("img2.jpg")_img1 = tensorify(img1) # helper function to convert cv2 image to tensors
_img2 = tensorify(img2)ssim_score = ssim(_img1, _img2, 225)print(True vs False Image SSIM Score: ", ssim_score)
Output:
True vs False Image SSIM Score: tensor(0.3385)
  • Case #2: 真图像 vs 加了高斯噪声的真图像

在这个场景中,我们比较了真实的图像和加了噪声的版本。图像如下所示:

加了噪声的真图像(左),真图像(右)

运行与上面一样的代码:

Code: noise = np.random.randint(0, 255, (640, 480, 3)).astype(np.float32)
noisy_img = img1 + noise_img1 = tensorify(img1)
_img2 = tensorify(noisy_img)true_vs_false = ssim(_img1, _img2, val_range=255)print("True vs Noised True Image SSIM Score:", true_vs_false)Output:True vs Noised True Image SSIM Score: tensor(0.0185)
  • Case #3: 真图像 vs 真图像

在最后一种情况下,我们比较真实的图像和它自己。因此,下面显示的图像是与自身进行比较的。如果我们的SSIM代码工作完美,分数应该是**1 **。

在运行下面所示的代码段时,我们可以确认这个给定场景的SSIM得分确实是1

Code:_img1 = tensorify(img1)
true_vs_false = ssim(_img1, _img1, val_range=255)print("True vs True Image SSIM Score:", true_vs_false)Output:True vs True Image SSIM Score: tensor(1.)

总结

在本文中,我们介绍了SSIM背后的理论和实现它的代码。希望你比我更容易理解SSIM。我试着专注于我个人觉得复杂和难以理解的领域,希望可以不仅巩固我所学到的知识,而且在这个过程中,可以帮助到其他人。

—END—

英文原文:https://medium.com/srm-mic/all-about-structural-similarity-index-ssim-theory-code-in-pytorch-6551b455541e

结构相似度索引(SSIM)全攻略:理论+代码(PyTorch)相关推荐

  1. MySQL 索引优化全攻略

    2019独角兽企业重金招聘Python工程师标准>>> 所谓索引就是为特定的mysql字段进行一些特定的算法排序,比如二叉树的算法和哈希算法,哈希算法是通过建立特征值,然后根据特征值 ...

  2. 从菜鸟出发!征服高清详细评测全攻略分页索引

    从菜鸟出发!征服高清详细评测全攻略分页索引 第1页:目录 第2页:高清发展历史与现状 第3页:高清概念初级快速入门-名词解释 第4页:永不妥协的两大蓝光阵营(上) 第5页:永不妥协的两大蓝光阵营(下) ...

  3. 网页制作HTML代码全攻略

    网页制作HTML代码全攻略 第一章:HTML 语言的结构 html文件是标准的ASCII文件,它看起来象是加入了许多被称为标注(tag)的特殊字符串的普遍文本文件.从结构上讲,html文件由元素(el ...

  4. 电影下载全攻略 [初、中、高级]——老猫

    电影下载全攻略 [初.中.高级]--老猫 初级篇 出于保护版权的目的,RM和ASF这两种格式文件的播放器--RealPlay和MediaPlayer都没有提供SAVE AS选项.如果希望看完节目后在w ...

  5. 搜索引擎优化SEO全攻略

    搜索引擎优化SEO全攻略 http://www.lelew.com/ 成功的搜索引擎营销策略应该是在网站建设之初开始的,从域名的选择到网页的源代码书写开始.但目前的现状是多数网站建设的分工和流程都是把 ...

  6. [RHEL5企业级Linux服务攻略]--第3季 DHCP服务全攻略

    1 DHCP原理  1.1 DHCP概述 DHCP(Dynamic Host Configuration Protocal)就是动态主机配置协议哈,可以自动配置主机的IP地址.子网掩码.网关及DNS等 ...

  7. 用C#制作PDF文件全攻略(转)

    PDF文件是目前比较流行的电子文档格式,在办公自动化(OA)等软件的开发中,经常要用到该格式,但介绍如何制作PDF格式文件的资料非常少,在网上搜来搜去,都转贴的是同一段"暴力"破解 ...

  8. 用C# itextsharp.dll制作PDF文件全攻略

    StreamWriter pPDF=new StreamWriter(filePath); ArrayList xRefs=new ArrayList(); float yPos =0f; long ...

  9. 用C#制作PDF文件全攻略 (专至csdn)

    前 言 丽水市汽车运输集团有限公司信息中心 苟安廷 PDF文件是目前比较流行的电子文档格式,在办公自动化(OA)等软件的开发中,经常要用到该格式,但介绍如何制作PDF格式文件的资料非常少,在网上搜来搜 ...

  10. Asp.net C#制作PDF文件全攻略

    StreamWriter pPDF=new StreamWriter(filePath); ArrayList xRefs=new ArrayList(); float yPos =0f; long ...

最新文章

  1. 【指标统计】统计装置总招遥信
  2. PHP生成日历(实例详解)
  3. es mysql 同步插件_[es和数据库怎么同步]mysql与elasticsearch实时同步常用插件及优缺点对比(ES与关系型数据库同步)...
  4. 【常见笔试面试算法题12续集五】动态规划算法案例分析5 01背包练习题
  5. 《吴恩达深度学习》第一课第四周任意层的神经网络实现及BUG处理
  6. MyBatis 使用
  7. nginx反向代理镜像网站做小偷站
  8. sql优化的N种方法_持续更新
  9. 谈谈四大行和外小行软开—工行软开待遇
  10. python化学公式配平_最简单易懂的化学方程式的配平方法
  11. Dev C++ 下载地址和安装教程
  12. Struts1.x 登录实验-无数据库版
  13. 基于802.1q技术实现单线复用的一种思路
  14. 区块链——物联网解决方案平台
  15. 计算机网络:以太网中的MTU与MSS
  16. [转]李战大师-悟透delphi-第二章 DELPHI与WIN32时空
  17. How to use Clang Static Analyzer
  18. python 图片识别服装_[Python设计模式] 第6章 衣服搭配系统——装饰模式
  19. 隐语v0.8.2版本更新,首次发布TEEU
  20. 你会用Python写洗脑神曲吗?

热门文章

  1. 基于Java+SpringBoot+Thymeleaf+Mysql多用户B2C商城平台系统设计与实现
  2. head first系列pdf下载
  3. LoadRunner教程(7)-LoadRunner 创建测试场景
  4. mysql 主键B+Tree 3层存2000W行数据
  5. 量子统计中的涨落和时间关联函数的概念(谐振子例子)
  6. EXE4J 错误提醒 Pleasedefine EXE4J_JAVA_HOME to point to an installes 64-bit JDK or JRE
  7. 笔记本 续航测试软件,续航能力测试
  8. oracle 卸载(手动,无universal installer)
  9. t检验的显著性p值python_t检验中的t值和p值是什么关系_t检验和p值的关系
  10. 理解t检验的一个简单技巧和手动计算P值