Rust图像相似度计算库dssim-core的使用,dssim-core提供高效的图像质量评估和结构相似性分析

Rust图像相似度计算库dssim-core的使用

dssim-core是一个高效的图像质量评估和结构相似性分析库,使用Rust语言编写。它通过近似人类视觉的算法来计算PNG和JPEG图像之间的(不)相似度。

RGBA结构相似性

该工具使用SSIM算法的变体来比较图像。返回的值是1/SSIM-1,其中0表示完全相同的图像,>0的值表示差异程度(无上限)。数值不能直接与其他工具进行比较。

主要特性

  • 改进的算法:
    • 在多个加权分辨率下进行比较,并在线性光RGB中进行缩放
    • 使用Lab*颜色空间进行SSIM算法,比RGB通道平均值更能准确测量亮度和颜色
  • 支持alpha通道
  • 支持带颜色配置文件的图像
  • 利用多核CPU优势
  • 可作为C、Rust和WASM的库使用
  • 不需要OpenCV或MATLAB

使用示例

命令行使用

比较两个文件:

dssim file-original.png file-modified.png

输出类似"0.02341"(数值越小越好)的结果。

比较多个文件:

dssim file.png modified1.png modified2.png modified3.png

保存差异可视化图像:

dssim -o difference.png file.png file-modified.png

作为Rust库使用

完整示例代码:

use dssim::{Dssim, DssimImage};
use image::open;

fn main() {
    // 初始化DSSIM结构
    let dssim = Dssim::new();
    
    // 加载原始图像
    let img1 = open("original.png").expect("无法加载原始图像").to_rgba8();
    let dssim_img1 = dssim.create_image(&img1).expect("创建DSSIM图像失败");
    
    // 加载修改后的图像
    let img2 = open("modified.png").expect("无法加载修改图像").to_rgba8();
    let dssim_img2 = dssim.create_image(&img2).expect("创建DSSIM图像失败");
    
    // 计算相似度
    let (similarity, _) = dssim.compare(&dssim_img1, &dssim_img2);
    
    println!("图像相似度值: {}", similarity);
}

解释数值

差异程度从0到无穷大,不是百分比。比较两种不同的图像压缩编解码器时,应确保:

  • 压缩到相同文件大小,然后用DSSIM比较哪个更接近原始图像
  • 或者压缩到相同DSSIM值,比较文件大小

安装

在项目中运行以下Cargo命令:

cargo add dssim-core

或在Cargo.toml中添加:

dssim-core = "3.2.11"

算法改进

  • 在多个加权尺度上进行比较(基于IWSSIM)
  • 在线性光RGB中进行缩放
  • Lab的a/b通道以较低的空间精度进行比较
  • SSIM分数使用平均绝对偏差进行池化

许可证

DSSIM采用AGPL或商业许可证双重授权。

完整示例代码

以下是一个更完整的示例,展示如何批量比较多张图像并输出结果:

use dssim::{Dssim, DssimImage};
use image::open;
use std::path::Path;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 初始化DSSIM结构
    let dssim = Dssim::new();
    
    // 原始图像路径
    let original_path = Path::new("original.png");
    
    // 加载原始图像
    let original_img = open(original_path)?.to_rgba8();
    let dssim_original = dssim.create_image(&original_img)?;
    
    // 要比较的修改图像列表
    let modified_images = vec![
        "modified1.png",
        "modified2.png",
        "modified3.png"
    ];
    
    // 比较每张修改后的图像
    for img_path in modified_images {
        let modified_img = open(img_path)?.to_rgba8();
        let dssim_modified = dssim.create_image(&modified_img)?;
        
        let (similarity, _) = dssim.compare(&dssim_original, &dssim_modified);
        
        println!("{} 与原始图像的相似度值: {:.5}", img_path, similarity);
    }
    
    Ok(())
}

示例说明

  1. 这个完整示例展示了如何:

    • 初始化DSSIM结构
    • 加载原始图像作为比较基准
    • 批量处理多个修改后的图像
    • 计算并输出每张图像与原始图像的相似度值
  2. 相似度值说明:

    • 0表示完全相同
    • 值越大表示差异越大
    • 结果保留5位小数提高精度
  3. 错误处理:

    • 使用?操作符简化错误处理
    • 返回Result类型便于上层调用者处理错误

这个示例可以直接用于实际项目中,只需修改图像路径即可。


1 回复

Rust图像相似度计算库dssim-core使用指南

简介

dssim-core是一个高效的Rust库,用于图像质量评估和结构相似性(SSIM)分析。它实现了DSSIM(结构相似性指数)算法,能够比较两幅图像的相似程度,返回一个0-1之间的相似度分数(0表示完全不同,1表示完全相同)。

主要特性

  • 高性能的SSIM/DSSIM计算
  • 支持多种图像格式
  • 可调整的SSIM参数
  • 线程安全设计

安装

在Cargo.toml中添加依赖:

[dependencies]
dssim-core = "3.0"
image = "0.24"  # 用于加载图像

基本使用方法

1. 比较两幅图像的相似度

use dssim_core::{Dssim, DssimImage};
use image::open;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 初始化DSSIM评估器
    let dssim = Dssim::new();
    
    // 加载图像
    let img1 = open("image1.png")?.to_rgba8();
    let img2 = open("image2.png")?.to_rgba8();
    
    // 创建DssimImage
    let dssim_img1 = dssim.create_image(&img1)?;
    let dssim_img2 = dssim.create_image(&img2)?;
    
    // 计算相似度
    let (similarity, _) = dssim.compare(&dssim_img1, &dssim_img2);
    
    println!("图像相似度: {}", similarity);
    Ok(())
}

2. 与参考图像比较多个图像

use dssim_core::{Dssim, DssimImage};
use image::open;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let dssim = Dssim::new();
    let reference = dssim.create_image(&open("reference.png")?.to_rgba8())?;
    
    let test_images = ["test1.png", "test2.png", "test3.png"];
    
    for img_path in test_images.iter() {
        let test_img = dssim.create_image(&open(img_path)?.to_rgba8())?;
        let (similarity, _) = dssim.compare(&reference, &test_img);
        println!("{} 与参考图像的相似度: {}", img_path, similarity);
    }
    
    Ok(())
}

3. 自定义SSIM参数

use dssim_core::{Dssim, DssimImage, Ssim};
use image::open;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 创建自定义SSIM配置
    let ssim = Ssim::new()
        .k1(0.01)  // 调整k1参数
        .k2(0.03)  // 调整k2参数
        .alpha(1.0)  // 亮度权重
        .beta(1.0)   // 对比度权重
        .gamma(1.0);  // 结构权重
    
    let dssim = Dssim::with_ssim(ssim);
    
    let img1 = dssim.create_image(&open("img1.png")?.to_rgba8())?;
    let img2 = dssim.create_image(&open("img2.png")?.to_rgba8())?;
    
    let (similarity, _) = dssim.compare(&img1, &img2);
    println!("自定义参数下的相似度: {}", similarity);
    
    Ok(())
}

高级用法

1. 获取差异图像

use dssim_core::{Dssim, DssimImage};
use image::{open, ImageBuffer, Rgba};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let dssim = Dssim::new();
    let img1 = dssim.create_image(&open("img1.png")?.to_rgba8())?;
    let img2 = dssim.create_image(&open("img2.png")?.to_rgba8())?;
    
    // 比较并获取差异图像
    let (similarity, diff_image) = dssim.compare(&img1, &img2);
    
    // 将差异图像转换为可显示的格式
    let (width, height) = diff_image.dimensions();
    let mut output = ImageBuffer::new(width, height);
    
    for (x, y, pixel) in diff_image.into_iter() {
        let value = (pixel * 255.0) as u8;
        output.put_pixel(x, y, Rgba([value, value, value, 255]));
    }
    
    output.save("difference.png")?;
    println!("相似度: {}, 差异图像已保存为difference.png", similarity);
    
    Ok(())
}

2. 批量处理图像比较

use dssim_core::{Dssim, DssimImage};
use image::open;
use std::path::Path;

fn compare_images(dir: &Path) -> Result<(), Box<dyn std::error::Error>> {
    let dssim = Dssim::new();
    let reference = dssim.create_image(&open(dir.join("reference.png"))?.to_rgba8())?;
    
    for entry in std::fs::read_dir(dir)? {
        let entry = entry?;
        let path = entry.path();
        if path.extension().and_then(|s| s.to_str()) == Some("png") 
            && path.file_name() != Some(std::ffi::OsStr::new("reference.png")) 
        {
            let test_img = dssim.create_image(&open(&path)?.to_rgba8())?;
            let (similarity, _) = dssim.compare(&reference, &test_img);
            println!("{:?} 相似度: {}", path.file_name().unwrap(), similarity);
        }
    }
    
    Ok(())
}

性能提示

  1. 对于大量图像比较,可以重复使用Dssim实例,它是线程安全的
  2. 如果图像尺寸不同,dssim-core会自动调整较小的图像尺寸以匹配较大的图像
  3. 对于非常大的图像,考虑先调整大小再比较以提高性能

应用场景

  • 图像质量评估
  • 图像压缩效果分析
  • 自动化测试中的视觉回归测试
  • 图像处理算法优化
  • 重复图像检测

dssim-core提供了简单而强大的API来进行图像相似度分析,是Rust生态中图像处理的重要工具之一。

完整示例

以下是一个完整的图像相似度比较示例,包含错误处理和命令行参数解析:

use dssim_core::{Dssim, DssimImage};
use image::open;
use std::path::PathBuf;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(name = "image-similarity", about = "比较两幅图像的相似度")]
struct Opt {
    /// 第一幅图像路径
    #[structopt(parse(from_os_str))]
    image1: PathBuf,
    
    /// 第二幅图像路径
    #[structopt(parse(from_os_str))]
    image2: PathBuf,
    
    /// 是否保存差异图像
    #[structopt(short, long)]
    diff: bool,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let opt = Opt::from_args();
    
    // 初始化DSSIM评估器
    let dssim = Dssim::new();
    
    // 加载并转换图像
    let img1 = open(&opt.image1)?.to_rgba8();
    let img2 = open(&opt.image2)?.to_rgba8();
    
    // 创建DssimImage
    let dssim_img1 = dssim.create_image(&img1)?;
    let dssim_img2 = dssim.create_image(&img2)?;
    
    // 比较图像
    let (similarity, diff_image) = dssim.compare(&dssim_img1, &dssim_img2);
    
    println!("图像相似度: {:.4}", similarity);
    
    // 如果需要保存差异图像
    if opt.diff {
        use image::{ImageBuffer, Rgba};
        
        let (width, height) = diff_image.dimensions();
        let mut output = ImageBuffer::new(width, height);
        
        for (x, y, pixel) in diff_image.into_iter() {
            let value = (pixel * 255.0) as u8;
            output.put_pixel(x, y, Rgba([value, value, value, 255]));
        }
        
        let diff_path = "difference.png";
        output.save(diff_path)?;
        println!("差异图像已保存为: {}", diff_path);
    }
    
    Ok(())
}

要运行此示例,需要在Cargo.toml中添加structopt依赖:

[dependencies]
structopt = "0.3"

运行示例:

cargo run -- --help  # 查看帮助
cargo run -- image1.png image2.png  # 基本比较
cargo run -- image1.png image2.png --diff  # 比较并保存差异图像
回到顶部