phil-opp / fast_image_resize

Rust library for fast image resizing with using of SIMD instructions.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

fast_image_resize

Rust library for fast image resizing with using of SIMD instructions.

Note: This library does not support converting image color spaces. If it is important for you to resize images with a non-linear color space (e.g. sRGB) correctly, then you need to convert it to a linear color space before resizing. Read more about resizing with respect to color space.

CHANGELOG

Supported pixel formats and available optimisations:

  • U8 - one u8 component per pixel:
    • native Rust-code without forced SIMD
    • AVX2
  • U8x3 - three u8 components per pixel (e.g. RGB):
    • native Rust-code without forced SIMD
    • SSE4.1 (auto-vectorization)
    • AVX2
  • U8x4 - four u8 components per pixel (RGBA, RGBx, CMYK and other):
    • native Rust-code without forced SIMD
    • SSE4.1
    • AVX2
  • U16x3 - three u16 components per pixel (e.g. RGB):
    • native Rust-code without forced SIMD
  • I32 - one i32 component per pixel:
    • native Rust-code without forced SIMD
  • F32 - one f32 component per pixel:
    • native Rust-code without forced SIMD

Benchmarks

Environment:

  • CPU: Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz
  • RAM: DDR4 3000 MHz
  • Ubuntu 20.04 (linux 5.11)
  • Rust 1.57.1
  • fast_image_resize = "0.6.0"
  • glassbench = "0.3.1"
  • rustflags = ["-C", "llvm-args=-x86-branches-within-32B-boundaries"]

Other Rust libraries used to compare of resizing speed:

Resize algorithms:

  • Nearest
  • Convolution with Bilinear filter
  • Convolution with CatmullRom filter
  • Convolution with Lanczos3 filter

Resize RGB image (U8x3) 4928x3279 => 852x567

Pipeline:

src_image => resize => dst_image

  • Source image nasa-4928x3279.png
  • Numbers in table is mean duration of image resizing in milliseconds.
Nearest Bilinear CatmullRom Lanczos3
image 96.466 186.243 268.888 358.235
resize 15.812 68.793 125.291 181.471
fir rust 0.495 56.372 93.182 127.870
fir sse4.1 - 44.775 56.014 78.759
fir avx2 - 11.290 14.731 20.678

Resize RGBA image (U8x4) 4928x3279 => 852x567

Pipeline:

src_image => multiply by alpha => resize => divide by alpha => dst_image

Nearest Bilinear CatmullRom Lanczos3
image 102.809 185.787 266.163 356.038
resize 18.723 83.072 156.063 229.400
fir rust 12.518 65.821 92.371 122.981
fir sse4.1 9.529 21.008 27.444 35.534
fir avx2 7.622 15.755 19.369 25.184

Resize grayscale image (U8) 4928x3279 => 852x567

Pipeline:

src_image => resize => dst_image

  • Source image nasa-4928x3279.png has converted into grayscale image with one byte per pixel.
  • Numbers in table is mean duration of image resizing in milliseconds.
Nearest Bilinear CatmullRom Lanczos3
image 80.937 132.497 174.721 219.534
resize 10.107 25.514 49.871 84.692
fir rust 0.208 23.255 26.471 37.642
fir avx2 - 9.927 8.054 12.298

Resize RGB16 image (U16x3) 4928x3279 => 852x567

Pipeline:

src_image => resize => dst_image

  • Source image nasa-4928x3279.png
  • Numbers in table is mean duration of image resizing in milliseconds.
Nearest Bilinear CatmullRom Lanczos3
image 98.962 180.516 255.045 335.265
resize 16.504 66.861 120.973 174.806
fir rust 0.800 53.874 89.453 123.963

Examples

Resize image

use std::io::BufWriter;
use std::num::NonZeroU32;

use image::codecs::png::PngEncoder;
use image::io::Reader as ImageReader;
use image::{ColorType, GenericImageView};

use fast_image_resize as fr;

#[test]
fn resize_image_example() {
    // Read source image from file
    let img = ImageReader::open("./data/nasa-4928x3279.png")
        .unwrap()
        .decode()
        .unwrap();
    let width = NonZeroU32::new(img.width()).unwrap();
    let height = NonZeroU32::new(img.height()).unwrap();
    let mut src_image = fr::Image::from_vec_u8(
        width,
        height,
        img.to_rgba8().into_raw(),
        fr::PixelType::U8x4,
    )
        .unwrap();

    // Create MulDiv instance
    let alpha_mul_div = fr::MulDiv::default();
    // Multiple RGB channels of source image by alpha channel
    alpha_mul_div
        .multiply_alpha_inplace(&mut src_image.view_mut())
        .unwrap();

    // Create container for data of destination image
    let dst_width = NonZeroU32::new(1024).unwrap();
    let dst_height = NonZeroU32::new(768).unwrap();
    let mut dst_image = fr::Image::new(
        dst_width,
        dst_height,
        src_image.pixel_type(),
    );

    // Get mutable view of destination image data
    let mut dst_view = dst_image.view_mut();

    // Create Resizer instance and resize source image
    // into buffer of destination image
    let mut resizer = fr::Resizer::new(
        fr::ResizeAlg::Convolution(fr::FilterType::Lanczos3)
    );
    resizer.resize(&src_image.view(), &mut dst_view).unwrap();

    // Divide RGB channels of destination image by alpha
    alpha_mul_div.divide_alpha_inplace(&mut dst_view).unwrap();

    // Write destination image as PNG-file
    let mut result_buf = BufWriter::new(Vec::new());
    PngEncoder::new(&mut result_buf)
        .encode(
            dst_image.buffer(),
            dst_width.get(),
            dst_height.get(),
            ColorType::Rgba8,
        )
        .unwrap();
}

Change CPU extensions used by resizer

use fast_image_resize as fr;

fn main() {
    let mut resizer = fr::Resizer::new(
        fr::ResizeAlg::Convolution(fr::FilterType::Lanczos3),
    );
    unsafe {
        resizer.set_cpu_extensions(fr::CpuExtensions::Sse4_1);
    }
}

About

Rust library for fast image resizing with using of SIMD instructions.

License:Apache License 2.0


Languages

Language:Rust 100.0%