bindings to Nvidia Labs's [ꟻLIP] image comparison and error visualization library.
This library allows you to visualize and reason about the human-noticable differences between rendered images. Especially when comparing images that are noisy or other small differences, FLIP's comparison can be more meaningful than a simple pixel-wise comparison.
In order to keep a small dependency closure, this crate does not depend on image
,
but interop is simple.
```rust // First we load the "reference image". This is the image we want to compare against. // // We make sure to turn the image into RGB8 as FLIP doesn't deal with alpha. let refimagedata = image::open("../etc/tree-ref.png").unwrap().intorgb8(); let refimage = nvflip::FlipImageRgb8::withdata( refimagedata.width(), refimagedata.height(), &refimagedata );
// We then load the "test image". This is the image we want to compare to the reference. let testimagedata = image::open("../etc/tree-test.png").unwrap().intorgb8(); let testimage = nvflip::FlipImageRgb8::withdata( testimagedata.width(), testimagedata.height(), &testimagedata );
// We now run the comparison. This will produce a "error map" that that is the per-pixel
// visual difference between the two images between 0 and 1.
//
// The last parameter is the number of pixels per degree of visual angle. This is used
// to determine the size of imperfections that can be seen. See the pixels_per_degree
// for more information. By default this value is 67.0.
let errormap = nvflip::flip(refimage, testimage, nvflip::DEFAULTPIXELSPERDEGREE);
// We can now visualize the error map using a LUT that maps the error value to a color. let visualized = errormap.applycolorlut(&nvflip::magma_lut());
// Finally we can the final image into an image
crate image and save it.
let image = image::RgbImage::fromraw(
visualized.width(),
visualized.height(),
visualized.tovec()
).unwrap();
// We can get statistics about the error map by using their "Pool" type, // which is essentially a weighted histogram. let mut pool = nvflip::FlipPool::fromimage(&error_map);
// These are the same statistics shown by the command line. // // The paper's writers recommend that, if you are to use a single number to // represent the error, they recommend the mean. println!("Mean: {}", pool.mean()); println!("Weighted median: {}", pool.getpercentile(0.5, true)); println!("1st weighted quartile: {}", pool.getpercentile(0.25, true)); println!("3rd weighted quartile: {}", pool.getpercentile(0.75, true)); println!("Min: {}", pool.minvalue()); println!("Max: {}", pool.max_value()); ``` The result of this example looks like this:
| Reference | ⠀⠀Test⠀⠀ | ⠀Result⠀ |
|:---------:|:---------:|:---------:|
| |
|
|
The binding and rust interop code is tri-licensed under MIT, Apache-2.0, and ZLib.
The ꟻLIP library itself is licensed under the BSD-3-Clause license.
The example images used are licensed under the [Unsplash License].
License: MIT OR Apache-2.0 OR Zlib