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(())
}
示例说明
-
这个完整示例展示了如何:
- 初始化DSSIM结构
- 加载原始图像作为比较基准
- 批量处理多个修改后的图像
- 计算并输出每张图像与原始图像的相似度值
-
相似度值说明:
- 0表示完全相同
- 值越大表示差异越大
- 结果保留5位小数提高精度
-
错误处理:
- 使用?操作符简化错误处理
- 返回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(())
}
性能提示
- 对于大量图像比较,可以重复使用
Dssim
实例,它是线程安全的 - 如果图像尺寸不同,dssim-core会自动调整较小的图像尺寸以匹配较大的图像
- 对于非常大的图像,考虑先调整大小再比较以提高性能
应用场景
- 图像质量评估
- 图像压缩效果分析
- 自动化测试中的视觉回归测试
- 图像处理算法优化
- 重复图像检测
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 # 比较并保存差异图像