mirror of
https://github.com/Cykooz/fast_image_resize.git
synced 2026-10-08 01:11:09 +00:00
- Fixed benchmark for resizing of RGB images.
- Added benchmark for resizing of RGBA images.
This commit is contained in:
@@ -24,24 +24,35 @@ Other Rust libraries used to compare of resizing speed:
|
||||
|
||||
Resize algorithms:
|
||||
- Nearest
|
||||
- Bilinear
|
||||
- CatmullRom
|
||||
- Lanczos3
|
||||
- Convolution with Bilinear filter
|
||||
- Convolution with CatmullRom filter
|
||||
- Convolution with Lanczos3 filter
|
||||
|
||||
### Resize 4928x3279 => 852x567
|
||||
### Resize RGB image 4928x3279 => 852x567
|
||||
|
||||
- Source image [nasa-4928x3279.png](https://github.com/Cykooz/fast_image_resize/blob/main/data/nasa-4928x3279.png)
|
||||
- Numbers in table is time of image resizing in milliseconds.
|
||||
|
||||
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|
||||
|------------|:-------:|:--------:|:----------:|:--------:|
|
||||
| image | 101.98 | 204.79 | 307.0 | 421.58 |
|
||||
| resize | 23.139 | 103.84 | 182.36 | 261.64 |
|
||||
| fir native | 0.486 | 54.479 | 81.625 | 113.37 |
|
||||
| fir sse4.1 | - | 12.08 | 18.733 | 26.689 |
|
||||
| fir avx2 | - | 9.58 | 14.319 | 20.133 |
|
||||
| image | 105.38 | 204.21 | 301.58 | 399.52 |
|
||||
| resize | 16.223 | 72.447 | 132.64 | 193.26 |
|
||||
| fir native | 0.476 | 57.003 | 87.564 | 120.65 |
|
||||
| fir sse4.1 | - | 12.143 | 18.662 | 26.334 |
|
||||
| fir avx2 | - | 9.346 | 13.342 | 18.934 |
|
||||
|
||||
fir - fast_image_resize
|
||||
### Resize RGBA image 4928x3279 => 852x567
|
||||
|
||||
- Source image [nasa-4928x3279.png](https://github.com/Cykooz/fast_image_resize/blob/main/data/nasa-4928x3279.png)
|
||||
- Numbers in table is time of image resizing in milliseconds.
|
||||
|
||||
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|
||||
|------------|:-------:|:--------:|:----------:|:--------:|
|
||||
| image | 110.45 | 264.84 | 421.25 | 596.17 |
|
||||
| resize | 23.919 | 100.38 | 173.62 | 247.39 |
|
||||
| fir native | 13.832 | 70.448 | 100.87 | 133.84 |
|
||||
| fir sse4.1 | 12.03 | 23.721 | 30.266 | 37.874 |
|
||||
| fir avx2 | 6.949 | 15.873 | 19.956 | 25.527 |
|
||||
|
||||
|
||||
## Examples of code
|
||||
|
||||
+173
-11
@@ -3,19 +3,20 @@ use std::num::NonZeroU32;
|
||||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||
use image::imageops;
|
||||
use resize::px::RGBA;
|
||||
use resize::Pixel::RGBA8;
|
||||
use rgb::FromSlice;
|
||||
use resize::Pixel::{RGB8, RGBA8};
|
||||
use rgb::{FromSlice, RGB};
|
||||
|
||||
use fast_image_resize::ImageData;
|
||||
use fast_image_resize::{CpuExtensions, FilterType, PixelType, ResizeAlg, Resizer};
|
||||
use fast_image_resize::{ImageData, MulDiv};
|
||||
|
||||
mod utils;
|
||||
|
||||
pub fn bench_downscale(c: &mut Criterion) {
|
||||
pub fn bench_downscale_rgb(c: &mut Criterion) {
|
||||
let src_image = utils::get_big_rgb_image();
|
||||
let new_width = NonZeroU32::new(852).unwrap();
|
||||
let new_height = NonZeroU32::new(567).unwrap();
|
||||
|
||||
let mut group = c.benchmark_group("Downscale (4928x3279 => 852x567)");
|
||||
let mut group = c.benchmark_group("Downscale RGB (4928x3279 => 852x567)");
|
||||
|
||||
for alg_num in 0..4 {
|
||||
// image crate
|
||||
@@ -39,8 +40,8 @@ pub fn bench_downscale(c: &mut Criterion) {
|
||||
|
||||
// resize crate
|
||||
// https://crates.io/crates/resize
|
||||
let resize_src_image = src_image.as_raw().as_rgba();
|
||||
let mut dst = vec![RGBA::new(0, 0, 0, 0); (new_width.get() * new_height.get()) as usize];
|
||||
let resize_src_image = src_image.as_raw().as_rgb();
|
||||
let mut dst = vec![RGB::new(0, 0, 0); (new_width.get() * new_height.get()) as usize];
|
||||
|
||||
group.bench_with_input(
|
||||
BenchmarkId::new("resize", alg_num),
|
||||
@@ -58,7 +59,7 @@ pub fn bench_downscale(c: &mut Criterion) {
|
||||
src_image.height() as usize,
|
||||
new_width.get() as usize,
|
||||
new_height.get() as usize,
|
||||
RGBA8,
|
||||
RGB8,
|
||||
filter,
|
||||
)
|
||||
.unwrap();
|
||||
@@ -68,11 +69,12 @@ pub fn bench_downscale(c: &mut Criterion) {
|
||||
},
|
||||
);
|
||||
|
||||
// fast_image_resize crate
|
||||
// fast_image_resize crate;
|
||||
let src_rgba_image = utils::get_big_rgba_image();
|
||||
let src_image_data = ImageData::new(
|
||||
NonZeroU32::new(src_image.width()).unwrap(),
|
||||
NonZeroU32::new(src_image.height()).unwrap(),
|
||||
src_image.as_raw(),
|
||||
src_rgba_image.as_raw(),
|
||||
PixelType::U8x4,
|
||||
)
|
||||
.unwrap();
|
||||
@@ -149,5 +151,165 @@ pub fn bench_downscale(c: &mut Criterion) {
|
||||
group.finish();
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_downscale,);
|
||||
pub fn bench_downscale_rgba(c: &mut Criterion) {
|
||||
let src_image = utils::get_big_rgba_image();
|
||||
let new_width = NonZeroU32::new(852).unwrap();
|
||||
let new_height = NonZeroU32::new(567).unwrap();
|
||||
|
||||
let mut group = c.benchmark_group("Downscale RGBA (4928x3279 => 852x567)");
|
||||
|
||||
for alg_num in 0..4 {
|
||||
// image crate
|
||||
// https://crates.io/crates/image
|
||||
group.bench_with_input(
|
||||
BenchmarkId::new("image", alg_num),
|
||||
&alg_num,
|
||||
|b, alg_num| {
|
||||
b.iter(|| {
|
||||
let filter = match alg_num {
|
||||
0 => imageops::Nearest,
|
||||
1 => imageops::Triangle,
|
||||
2 => imageops::CatmullRom,
|
||||
3 => imageops::Lanczos3,
|
||||
_ => return,
|
||||
};
|
||||
imageops::resize(&src_image, new_width.get(), new_height.get(), filter);
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
// resize crate
|
||||
// https://crates.io/crates/resize
|
||||
let resize_src_image = src_image.as_raw().as_rgba();
|
||||
let mut dst = vec![RGBA::new(0, 0, 0, 0); (new_width.get() * new_height.get()) as usize];
|
||||
|
||||
group.bench_with_input(
|
||||
BenchmarkId::new("resize", alg_num),
|
||||
&alg_num,
|
||||
|b, alg_num| {
|
||||
let filter = match alg_num {
|
||||
0 => resize::Type::Point,
|
||||
1 => resize::Type::Triangle,
|
||||
2 => resize::Type::Catrom,
|
||||
3 => resize::Type::Lanczos3,
|
||||
_ => return,
|
||||
};
|
||||
let mut resizer = resize::new(
|
||||
src_image.width() as usize,
|
||||
src_image.height() as usize,
|
||||
new_width.get() as usize,
|
||||
new_height.get() as usize,
|
||||
RGBA8,
|
||||
filter,
|
||||
)
|
||||
.unwrap();
|
||||
b.iter(|| {
|
||||
resizer.resize(resize_src_image, &mut dst).unwrap();
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
// fast_image_resize crate;
|
||||
let src_image_data = ImageData::new(
|
||||
NonZeroU32::new(src_image.width()).unwrap(),
|
||||
NonZeroU32::new(src_image.height()).unwrap(),
|
||||
src_image.as_raw(),
|
||||
PixelType::U8x4,
|
||||
)
|
||||
.unwrap();
|
||||
let src_view = src_image_data.src_view();
|
||||
let mut premultiplied_src_image = ImageData::new_owned(
|
||||
NonZeroU32::new(src_image.width()).unwrap(),
|
||||
NonZeroU32::new(src_image.height()).unwrap(),
|
||||
PixelType::U8x4,
|
||||
);
|
||||
let mut dst_image = ImageData::new_owned(new_width, new_height, PixelType::U8x4);
|
||||
let mut dst_view = dst_image.dst_view();
|
||||
let mut fast_resizer = Resizer::new(ResizeAlg::Nearest);
|
||||
let mut mul_div = MulDiv::default();
|
||||
unsafe {
|
||||
fast_resizer.set_cpu_extensions(CpuExtensions::None);
|
||||
mul_div.set_cpu_extensions(CpuExtensions::None);
|
||||
}
|
||||
group.bench_with_input(
|
||||
BenchmarkId::new("fast_wo_simd", alg_num),
|
||||
&alg_num,
|
||||
|b, alg_num| {
|
||||
let resize_alg = match alg_num {
|
||||
0 => ResizeAlg::Nearest,
|
||||
1 => ResizeAlg::Convolution(FilterType::Bilinear),
|
||||
2 => ResizeAlg::Convolution(FilterType::CatmulRom),
|
||||
3 => ResizeAlg::Convolution(FilterType::Lanczos3),
|
||||
_ => return,
|
||||
};
|
||||
fast_resizer.algorithm = resize_alg;
|
||||
b.iter(|| {
|
||||
mul_div
|
||||
.multiply_alpha(&src_view, &mut premultiplied_src_image.dst_view())
|
||||
.unwrap();
|
||||
fast_resizer.resize(&premultiplied_src_image.src_view(), &mut dst_view);
|
||||
mul_div.divide_alpha_inplace(&mut dst_view).unwrap();
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
let mut fast_resizer = Resizer::new(ResizeAlg::Nearest);
|
||||
unsafe {
|
||||
fast_resizer.set_cpu_extensions(CpuExtensions::Sse4_1);
|
||||
mul_div.set_cpu_extensions(CpuExtensions::Sse4_1);
|
||||
}
|
||||
group.bench_with_input(
|
||||
BenchmarkId::new("fast_sse4", alg_num),
|
||||
&alg_num,
|
||||
|b, alg_num| {
|
||||
let resize_alg = match alg_num {
|
||||
0 => ResizeAlg::Nearest,
|
||||
1 => ResizeAlg::Convolution(FilterType::Bilinear),
|
||||
2 => ResizeAlg::Convolution(FilterType::CatmulRom),
|
||||
3 => ResizeAlg::Convolution(FilterType::Lanczos3),
|
||||
_ => return,
|
||||
};
|
||||
fast_resizer.algorithm = resize_alg;
|
||||
b.iter(|| {
|
||||
mul_div
|
||||
.multiply_alpha(&src_view, &mut premultiplied_src_image.dst_view())
|
||||
.unwrap();
|
||||
fast_resizer.resize(&premultiplied_src_image.src_view(), &mut dst_view);
|
||||
mul_div.divide_alpha_inplace(&mut dst_view).unwrap();
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
let mut fast_resizer = Resizer::new(ResizeAlg::Nearest);
|
||||
unsafe {
|
||||
fast_resizer.set_cpu_extensions(CpuExtensions::Avx2);
|
||||
mul_div.set_cpu_extensions(CpuExtensions::Avx2);
|
||||
}
|
||||
group.bench_with_input(
|
||||
BenchmarkId::new("fast_avx2", alg_num),
|
||||
&alg_num,
|
||||
|b, alg_num| {
|
||||
let resize_alg = match alg_num {
|
||||
0 => ResizeAlg::Nearest,
|
||||
1 => ResizeAlg::Convolution(FilterType::Bilinear),
|
||||
2 => ResizeAlg::Convolution(FilterType::CatmulRom),
|
||||
3 => ResizeAlg::Convolution(FilterType::Lanczos3),
|
||||
_ => return,
|
||||
};
|
||||
fast_resizer.algorithm = resize_alg;
|
||||
b.iter(|| {
|
||||
mul_div
|
||||
.multiply_alpha(&src_view, &mut premultiplied_src_image.dst_view())
|
||||
.unwrap();
|
||||
fast_resizer.resize(&premultiplied_src_image.src_view(), &mut dst_view);
|
||||
mul_div.divide_alpha_inplace(&mut dst_view).unwrap();
|
||||
})
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
group.finish();
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_downscale_rgb, bench_downscale_rgba);
|
||||
criterion_main!(benches);
|
||||
|
||||
+13
-4
@@ -1,9 +1,18 @@
|
||||
use std::env;
|
||||
|
||||
use image::io::Reader;
|
||||
use image::RgbaImage;
|
||||
use image::{RgbImage, RgbaImage};
|
||||
|
||||
pub fn get_big_rgb_image() -> RgbaImage {
|
||||
pub fn get_big_rgb_image() -> RgbImage {
|
||||
let cur_dir = env::current_dir().unwrap();
|
||||
let img = Reader::open(cur_dir.join("data/nasa-4928x3279.png"))
|
||||
.unwrap()
|
||||
.decode()
|
||||
.unwrap();
|
||||
img.to_rgb8()
|
||||
}
|
||||
|
||||
pub fn get_big_rgba_image() -> RgbaImage {
|
||||
let cur_dir = env::current_dir().unwrap();
|
||||
let img = Reader::open(cur_dir.join("data/nasa-4928x3279.png"))
|
||||
.unwrap()
|
||||
@@ -12,11 +21,11 @@ pub fn get_big_rgb_image() -> RgbaImage {
|
||||
img.to_rgba8()
|
||||
}
|
||||
|
||||
pub fn get_small_rgb_image() -> RgbaImage {
|
||||
pub fn get_small_rgb_image() -> RgbImage {
|
||||
let cur_dir = env::current_dir().unwrap();
|
||||
let img = Reader::open(cur_dir.join("data/nasa-852x567.png"))
|
||||
.unwrap()
|
||||
.decode()
|
||||
.unwrap();
|
||||
img.to_rgba8()
|
||||
img.to_rgb8()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user