1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
#![crate_name = "image_compare"]
//! # Comparing images
//! This crate allows to compare grayscale images
//! The easiest use is loading two images, converting them to grayscale and running a comparison:
//! ```no_run
//! use image_compare::Algorithm;
//! let image_one = image::open("image1.png").expect("Could not find test-image").into_luma8();
//! let image_two = image::open("image2.png").expect("Could not find test-image").into_luma8();
//! let result = image_compare::gray_similarity(Algorithm::MSSIMSimple, &image_one, &image_two).expect("Images had different dimensions");
//! ```
//!
//! Check the [`Algorithm`] enum for implementation details
//!
#![warn(missing_docs)]
#![warn(unused_qualifications)]
#![deny(deprecated)]
mod squared_error;
mod ssim;
mod utils;
#[doc(hidden)]
pub mod prelude {
pub use image::{GrayImage, ImageBuffer, Luma};
use thiserror::Error;
/// The enum for selecting a grayscale comparison implementation
pub enum Algorithm {
/// A simple RMSE implementation - will return: <img src="https://render.githubusercontent.com/render/math?math=1-\sqrt{\frac{(\sum_{x,y=0}^{x,y=w,h}\left(f(x,y)-g(x,y)\right)^2)}{w*h}}">
RootMeanSquared,
/// a simple MSSIM implemenation - will run SSIM (implemented as on wikipedia) over 8x8 px windows and average the results
MSSIMSimple,
}
#[derive(Error, Debug)]
/// The errors that can occur during comparison of the images
pub enum CompareError {
#[error("The dimensions of the input images are not identical")]
DimensionsDiffer,
}
/// a single-channel f32 typed image containing a result-score for each pixel
pub type SimilarityImage = ImageBuffer<Luma<f32>, Vec<f32>>;
#[derive(Debug)]
/// A struct containing the results of a grayscale comparison
pub struct Similarity {
/// Contains the resulting differences per pixel.
/// The buffer will contain the resulting values of the respective algorithms:
/// - RMS will be between 0. for all-white vs all-black and 1.0 for identical
/// - SSIM usually is near 1. for similar, near 0. for different but can take on negative values for negative covariances
pub image: SimilarityImage,
/// the averaged resulting score
pub score: f64,
}
}
#[doc(inline)]
pub use prelude::Algorithm;
#[doc(inline)]
pub use prelude::CompareError;
#[doc(inline)]
pub use prelude::Similarity;
use prelude::*;
/// The current main function of the crate
///
/// # Arguments
///
/// * `algorithm` - The comparison algorithm to use
///
/// * `first` - The first of the images to compare
///
/// * `second` - The first of the images to compare
pub fn gray_similarity(
algorithm: Algorithm,
first: &GrayImage,
second: &GrayImage,
) -> Result<Similarity, CompareError> {
match algorithm {
Algorithm::RootMeanSquared => squared_error::root_mean_squared_error_simple(first, second),
Algorithm::MSSIMSimple => ssim::ssim_simple(first, second),
}
}