首页 > 其他分享 >如何度量两幅图像的相似度--结构相似度 SSIM 原理及代码

如何度量两幅图像的相似度--结构相似度 SSIM 原理及代码

时间:2023-06-14 22:33:10浏览次数:56  
标签:-- SSIM ssim pytorch 相似 图像 img2 img1


本文目录


文章目录

  • 1. 什么是 SSIM
  • 2. SSIM 有什么用
  • 3. 使用 pytorch 计算 SSIM
  • 3.1 二维图像 SSIM 计算
  • 3.1.1 准备工作
  • 3.1.2 官网的第一个案例
  • 3.1.3 官网的第二个案例
  • 3.2 在图片上写字,并制作GIF
  • 3.2.1 使用Python在图片上写字
  • 3.2.2 制作GIF
  • 3.3 3D 图像的 SSIM 计算和 loss


1. 什么是 SSIM

结构相似性指数(Structural Similarity Index measure,SSIM)用作度量两个给定图像之间的相似性。

如何度量两幅图像的相似度--结构相似度 SSIM 原理及代码_深度学习


如,这两个图像之间的 相似度=0.7816

SSIM 指标从图像中提取 3 个关键特征:

  • 亮度
  • 对比
  • 结构

两个图像之间的比较是基于这 3 个特征进行的

如何度量两幅图像的相似度--结构相似度 SSIM 原理及代码_深度学习_02

公式:
如何度量两幅图像的相似度--结构相似度 SSIM 原理及代码_二维_03

公式详情见 维基百科

ssim计算原理参考链接

SSIM 有很多变体,如: Multi-Scale SSIM, Multi-component SSIM, Structural Dissimilarity,Complex Wavelet SSIM等等。维基百科可查看更多描述。

2. SSIM 有什么用

  1. 用做评价指标,度量两个图像的相似度。比如:做图像恢复/建模的时候,评价图像的恢复情况。
  2. 用做 loss function: 可用作分割以及图像重建的损失函数。不同的任务用法不一样。也是比较流行的方法。

3. 使用 pytorch 计算 SSIM

这部分是本次的重点,会详细介绍 二维图像以及三维图像的SSIM计算方法, 以及如何用将其用做loss。

本部分实战简单,知识点丰富,内容有趣。一起来学习吧。

3.1 二维图像 SSIM 计算

2D SSIM pytorch code

这个代码是 pytorch 计算 SSIM 的标准方法,在github上搜索会发现,大家使用的都是这个方法。

这里我会带领大家一起实现官方的例子。

获得上述 GIF 结果大概需要如下技能:

  • SSIM 的计算
  • SSIM 用做 loss, 训练一个随机图像接近我们的目标图像(爱因斯坦肖像)
  • 将上述训练中,每个epoch生成的图像保存下来制作GIF
  • 用 Python 给图片加字
  • 用 Python 制作 GIF

任务很多,但是每个任务都很简单,我们开始吧~~


3.1.1 准备工作

下载 3.1 节中给出的地址中的代码,copy 整个 pytorch_ssim 文件夹。不知道如何单独下载一个文件夹,查看之前的教程。

Github 单文件快速下载 – 使用 DownGit

这个文件夹其实就只有一个初始化文件。

如何度量两幅图像的相似度--结构相似度 SSIM 原理及代码_pytorch_04


如果还是不会下载,就自己新建一个同名文件夹(注意在 pycharm 中选择 新建 python package 而不是普通的文件夹),这样新建好后就会自动创建 __init__.py 文件. 然后把内容复制进去。

如何度量两幅图像的相似度--结构相似度 SSIM 原理及代码_官网_05

新建一个项目,把下载好的文件夹放进去。同时下载实验数据 ’einstein.png‘ 爱因斯坦肖像图。此时,你的项目里应该有打勾的3个文件。

如何度量两幅图像的相似度--结构相似度 SSIM 原理及代码_二维_06

3.1.2 官网的第一个案例

第一个案例:随机生成两个二维图像,并计算他们的 SSIM。

import pytorch_ssim
import torch
from torch.autograd import Variable

img1 = Variable(torch.rand(1, 1, 256, 256))
img2 = Variable(torch.rand(1, 1, 256, 256))

if torch.cuda.is_available():
    img1 = img1.cuda()
    img2 = img2.cuda()

print(pytorch_ssim.ssim(img1, img2))

ssim_loss = pytorch_ssim.SSIM(window_size = 11)

print(ssim_loss(img1, img2))

这里 import pytorch_ssim就是我们copy下来的文件夹 调用
pytorch_ssim.ssim直接计算二者的相似度 调用
pytorch_ssim.SSIM大写的SSIM是计算loss,但是二者的计算方法是一样的,只是写法不一样。

3.1.3 官网的第二个案例

第二个案例: 使用 SSIM 作为loss, 把随机数训练成目标图像(爱因斯坦)。

这里和官网的代码有些略微差别,官网的copy下来是有BUG的。改过的行 我会在后面 加 ###

import pytorch_ssim
import torch
from torch.autograd import Variable
from torch import optim
import cv2
import numpy as np

npImg1 = cv2.imread("einstein.png")

img1 = torch.from_numpy(np.rollaxis(npImg1, 2)).float().unsqueeze(0) / 255.0
img2 = torch.rand(img1.size())

if torch.cuda.is_available():
    img1 = img1.cuda()
    img2 = img2.cuda()

img1 = Variable(img1, requires_grad=False)
img2 = Variable(img2, requires_grad=True)

# Functional: pytorch_ssim.ssim(img1, img2, window_size = 11, size_average = True)
ssim_value = pytorch_ssim.ssim(img1, img2).item()  ###
print("Initial ssim:", ssim_value)

# Module: pytorch_ssim.SSIM(window_size = 11, size_average = True)
ssim_loss = pytorch_ssim.SSIM()

optimizer = optim.Adam([img2], lr=0.01)

epoch = 1   ###
while ssim_value < 0.95:
    optimizer.zero_grad()
    ssim_out = -ssim_loss(img1, img2)
    ssim_value = round(- ssim_out.item(), 4)  ### round 保留4位小数
    # save image
    vutils.save_image(img2, f'SSIMPNG/einstein_{epoch}_{ssim_value}.png')  ### 官网教程没有保存每一次迭代的图像,这里我们保存下来。 如果没有SSIMPNG这个文件夹,手动创建一个。
    print(ssim_value)
    ssim_out.backward()
    optimizer.step()
    epoch += 1   ###

这部分代码也比较简单,就是当 SSIM 值小于 0.95 时一直循环迭代。中途保存每次迭代的图像,之后我们可以查看图像的变化过程。

这里另外涉及到一个知识点: 如何使用 pytorch 保存图片?

这个链接提供了3种保存方法

到这里 官网的教程结束了,但是我们没有得到想要的 GIF!

只得到了每个 epoch 的图像

如何度量两幅图像的相似度--结构相似度 SSIM 原理及代码_pytorch_07

现在我们要做的就是:把每个epoch的SSIM 值写在图像上,然后把这些图像做成GIF。

3.2 在图片上写字,并制作GIF

3.2.1 使用Python在图片上写字

主要用到的库: pillow

from PIL import Image, ImageDraw, ImageFont  
# pip install pillow

def drawssim(filepath, value):

    # 打开图像
    im = Image.open(filepath)

    # 告诉系统,你要在图像上画画了
    draw = ImageDraw.Draw(im)

    # 设置字体,大小=50
    font = ImageFont.truetype('/usr/share/fonts/truetype/Sarai/Sarai.ttf', 40)
    # 如何找系统上自带的字体: 百度搜索Linux字体存放位置

    # 写内容, 初始位置(30, 10) 颜色红色
    draw.text((30, 10), f'ssim = {value}', fill='red', font=font)

    # 保存
    im.save(filepath.replace('SSIMPNG', 'SSIM_VALUE'))
    
if __name__ == '__main__':
    from glob import glob
    imgs = glob('SSIMPNG/*.png')
    for img in imgs:
        filepath = img
        value = img.split('_')[-1].split('.png')[0]
        drawssim(filepath, value)

drawssim函数接收一个单独的文件地址和SSIM值,把值写在该图像上,并且保存到 ‘SSIM_VALUE’ 文件夹(如果没有,手动创建)

如何度量两幅图像的相似度--结构相似度 SSIM 原理及代码_二维_08


我们就得到了这样的一些图片。

3.2.2 制作GIF

我们把这些图片,按照epoch的顺序依次播放,并保存为GIF。

这里涉及到图片的排序问题。如果我们直接使用 sorted()函数排序

imgs = sorted(glob('SSIM_VALUE/*.png'))

会发现排出来的顺序跟我们要的顺序不一样。

如何度量两幅图像的相似度--结构相似度 SSIM 原理及代码_官网_09

而我们想要按数字大小排序,从1–76.

因此,我们需要自写一个排序算法。

import imageio  # pip install imageio
# create gif
def create_gif(image_list, gif_name, duration=1.5):
    '''
    image_list: 图片列表,文件名
    gif_name: 生成的 GIF 文件名
    duratuion: 图像间隔时间
    '''

    frames = []
    for img in image_list:
        frames.append(imageio.imread(img))
    imageio.mimsave(gif_name, frames, 'GIF', duration=duration)


class sortimg():

    def tryint(self, s):
        try:
            return int(s)
        except ValueError:
            return s

    def str2int(self, v_str):
        return [self.tryint(sub_str) for sub_str in re.split('([0-9]+)', v_str)]

    def sort_humanly(self, v_list):
        return sorted(v_list, key=self.str2int)


if __name__ == '__main__':
    from glob import glob
    imgs = glob('SSIM_VALUE/*.png')
    # 排序
    sorted_imgs = sortimg().sort_humanly(imgs)

    create_gif(sorted_imgs, 'ssim.gif', duration=0.1)

sortimg()对列表进行排序(按数字大小), create_gif()使用imageio制作GIF。

如此我们就得到了之前那个 GIF 图像。官网教程实验已经完美复现啦。

3.3 3D 图像的 SSIM 计算和 loss

上述代码只提供了二维图像的计算方法,那如何计算三维呢?

这里,copy 另一个代码。
3D 代码地址

import pytorch_ssim
import torch
from torch.autograd import Variable

img1 = Variable(torch.rand(1, 1, 256, 256, 256))
img2 = Variable(torch.rand(1, 1, 256, 256, 256))

if torch.cuda.is_available():
    img1 = img1.cuda()
    img2 = img2.cuda()

print(pytorch_ssim.ssim3D(img1, img2))

ssim_loss = pytorch_ssim.SSIM3D(window_size = 11)

print(ssim_loss(img1, img2))

这个代码在原来的基础上新增了几个 3D 函数,同 2D 使用方法一样。

文章持续更新,可以关注微信公众号【医学图像人工智能实战营】获取最新动态,一个关注于医学图像处理领域前沿科技的公众号。坚持已实践为主,手把手带你做项目,打比赛,写论文。凡原创文章皆提供理论讲解,实验代码,实验数据。只有实践才能成长的更快,关注我们,一起学习进步~

我是Tina, 我们下篇博客见~

白天工作晚上写文,呕心沥血

标签:--,SSIM,ssim,pytorch,相似,图像,img2,img1
From: https://blog.51cto.com/u_16159492/6481774

相关文章

  • 哈希搜索算法及C语言实现
    一、哈希搜索算法原理哈希搜索,也叫散列查找,是一种通过哈希表(散列表)实现快速查找目标元素的算法。哈希搜索算法通常适用于需要快速查找一组数据中是否存在某个元素的场景,其时间复杂度最高为O(1),而平均情况下的时间复杂度通常相当接近O(1),因此在实际应用中具有很高的效率和性能。哈......
  • 【Azure 应用服务】Azure Function App在部署时候遇见 503 ServiceUnavailable
    问题描述在VSCode中编写好AzureFunctionApp代码后,通过 funcazurefunctionapppublish部署失败,抛出503ServiceUnavailable错误。Gettingsitepublishinginfo...Creatingarchiveforcurrentdirectory...Performingremotebuildforfunctionsproject.Deleting......
  • 《C++》对象的初始化和清理
    不设计构造和析构函数 编译器会提供空语句的构造和析构初始化--构造函数无返回类型函数名与类名相同构造函数可以有参数可以发生重载创建对象的时候构造函数会自动调用且只调用一次classPerson{public: Person() { cout<<"无参构造函数调用"<<endl; }Person(inta......
  • 一文实战K8S中的服务发现和负载均衡
    开篇在Kubernetes集群中,服务发现和负载均衡是非常重要的概念和功能。它们可以帮助我们管理应用程序的访问和流量分发,确保应用程序的高可用性和性能。在本文中,我们将通过一个实战案例,探索Kubernetes中的服务发现和负载均衡机制,并演示如何在集群中部署和管理具有负载均衡能力的应用......
  • 探秘WebMagic:爬虫神器
    一、介绍WebMagic是一款基于Java的开源网络爬虫框架,能够快速、灵活、高效地实现网络数据的爬取和抽取。WebMagic支持多线程、分布式、自动重试等特性,而且使用起来也非常方便。二、优点1.快速:使用了NIO框架,能够高效地进行网络通信,提高爬虫效率。2.灵活:支持自定义爬取规则,能够......
  • 秒杀(高并发)系统关注的问题
    //如果当前这个场次的商品库存信息已经上架就不需要上架//5、使用库存作为分布式Redisson信号量(限流)//使用库存作为分布式信号量RSemaphoresemaphore=redissonClient.getSemaphore(SKU_STOCK_SEMAPHORE+token);//商品可以秒杀的数量作为信号量semaphore.trySetPerm......
  • 2-技术篇
    本篇是数据挖掘技术的主体部分,系统介绍了数据挖掘的相关技术及其这些技术的应用实例。该部分又分三个层次:1)数据挖掘前期的一些技术,包括数据的准备(收集数据、数据质量分析、数据预处理等)和数据的探索(衍生变量、数据可视化、样本选择、数据降维等)。2)数据挖掘的核心六大......
  • 实验七
    实验任务四程序源码#include<stdio.h>#include<stdlib.h>#include<string.h>#defineN5#defineM100intmain(){charch[M];intn=0;FILE*fp;fp=fopen("C://Users//Lenovo//Desktop//实验7数据文件及部分代码//实验7数据文件及部分代码//da......
  • mysql 数据完整性
    一、实体完整性(表中的一行或一条数据。行级约束)1、主键约束(数据唯一且不能为NULL)添加方式createtablestu(idintprimarykey,namevarchar(20));   唯一约束自动增长列二、域完整性三、引用完整性......
  • 硬件设计LLM:AI辅助创建微处理芯片
    编辑|绿萝通常,开发任何类型的硬件(包括芯片,作为电子设备大脑的微小电子元件),都是从用正常语言描述硬件应该做什么开始的。然后,经过专门训练的工程师将该描述翻译成硬件描述语言(HDL),例如Verilog,以创建允许硬件执行其任务的实际电路元件。自动化此翻译可以减少工程过程中的人为错......