Closed bedapisl closed 2 months ago
Do you ask about downscaling or upscaling?
As I understand, OpenCV uses "convolution" with fixed kernel size. In this case, downscaling very big image into very small one looks like a result of nearest "interpolation".
fast_image_resize
uses convolution with adaptive kernel size. It requires more computations but makes more better result.
Look at results of downscaling big image into small one with use of different OpenCV interpolations.
Downscaling is more important but I would ideally I would like both.
Yes, I see the results are visually better. But my goal is to reproduce a pipeline written in Python that uses OpenCV. I need exactly same results as in the OpenCV, no matter which ones look better.
I can try to implement a fixed kernel size, but I'm not sure if that would be enough to get exactly the same results. The result also depends on how a particular solution handles rounding of numbers, accuracy of intermediate calculations and other things.
Hello, can I ask you about some rough time estimate for this? Alternatively if you don't have time for it, I can try implementing it myself and send it to you for review.
I think I can do it for about 5-7 days. But I don't know what name to give these resizing methods.
ConvolutionWithFixedKernalSize
? Interpolation
? Do you have any ideas?
I think both names you suggested make sense, I don't have any other idea.
I implemented Interpolation
resize algorithm. I did the simple test to compare the result of Interpolation(FilterType::Bilinear)
with the result of INTER_LINEAR
from OpenCV. They look the same.
Perfect thanks. I will try it later.
I will publish this version on crates.org within 1-2 days.
I released version 4.2.0
Hello, I have tested the solution. The results are closer to these of OpenCV, but there are still some small +1/-1 differences. These are probably due to rounding as you said in your previous comment.
I am posting a reproducible example:
create_image.py
import cv2
import numpy as np
def create_image():
width = 640
height = 360
np.random.seed(0)
image = np.random.randint(0, 256, (height, width), dtype='uint8')
cv2.imwrite("test_image.png", image)
def main():
create_image()
if __name__ == "__main__":
create_image()
resize_python.py
import cv2
import numpy as np
def resize_image(
image: np.ndarray
) -> np.ndarray:
new_height = 144
new_width = 256
scaled_image = cv2.resize(image, (new_width, new_height), interpolation=cv2.INTER_LINEAR)
return scaled_image
def main():
image = cv2.imread("test_image.png")
resized = resize_image(image)
print(resized[0:200,0,0].tolist())
if __name__ == "__main__":
main()
main.rs
use std::fs;
use std::io::{BufWriter, Write};
use image::codecs::png::PngEncoder;
use image::{ImageEncoder, ImageReader};
use fast_image_resize::{FilterType, ResizeAlg, ResizeOptions, Resizer};
use fast_image_resize::images::Image;
fn main() {
// Load test image
let img = ImageReader::open("../test_image.png")
.unwrap()
.decode()
.unwrap();
let src_image = Image::from_vec_u8(img.width(), img.height(), img.into_bytes(), fast_image_resize::PixelType::U8).unwrap();
// Create an empty destination image
let new_height: usize = 144;
let new_width: usize = 256;
let mut dst_image = Image::from_vec_u8(new_width as u32, new_height as u32, vec![0; new_width*new_height as usize], fast_image_resize::PixelType::U8).unwrap();
// Create a resizer
let mut resizer = Resizer::new();
let resize_options = ResizeOptions::new().resize_alg(ResizeAlg::Interpolation(FilterType::Bilinear));
// Resize
resizer.resize(
&src_image,
&mut dst_image,
&resize_options,
).unwrap();
// Print some pixels
let pixels: Vec<u8> = dst_image.copy().into_vec().into_iter().step_by(new_width).collect();
let pixel_strings: Vec<String> = pixels.into_iter().map(|pixel_value| pixel_value.to_string()).collect();
println!("{}", pixel_strings.join(", "));
// Save image
let mut result_buf = BufWriter::new(Vec::new());
PngEncoder::new(&mut result_buf)
.write_image(
dst_image.buffer(),
new_width as u32,
new_height as u32,
image::ExtendedColorType::L8,
)
.unwrap();
fs::write("../rust_output_image.png", result_buf.buffer()).expect("Unable to write file");
}
After running create_image.py
I get following output from resize_image.py`:
[80, 113, 153, 116, 141, 74, 207, 216, 128, 62, 163, 138, 196, 59, 167, 194, 207, 188, 46, 149, 225, 191, 107, 143, 86, 62, 74, 103, 83, 156, 106, 192, 73, 149, 41, 103, 170, 150, 170, 76, 52, 149, 115, 129, 182, 81, 112, 122, 103, 147, 149, 90, 127, 128, 52, 125, 214, 146, 137, 174, 109, 150, 157, 103, 74, 133, 39, 208, 178, 167, 77, 178, 92, 158, 199, 189, 153, 153, 152, 112, 180, 75, 80, 144, 122, 84, 79, 228, 41, 177, 40, 60, 127, 159, 164, 128, 114, 181, 60, 55, 145, 153, 134, 95, 137, 67, 157, 130, 36, 151, 154, 68, 47, 93, 121, 77, 149, 185, 83, 136, 165, 49, 75, 208, 157, 168, 89, 67, 121, 143, 154, 151, 132, 72, 165, 131, 175, 97, 76, 85, 139, 182, 48, 166]
and a sligthly different output from running the rust code:
81, 113, 153, 117, 142, 74, 207, 216, 128, 62, 163, 138, 196, 59, 167, 195, 207, 188, 46, 150, 225, 191, 108, 144, 86, 62, 75, 103, 84, 157, 106, 192, 73, 150, 41, 103, 170, 151, 170, 76, 53, 149, 115, 130, 182, 81, 112, 122, 103, 147, 149, 90, 128, 129, 53, 125, 214, 147, 137, 174, 109, 150, 157, 103, 75, 134, 39, 209, 178, 167, 77, 179, 92, 158, 199, 189, 154, 154, 152, 112, 180, 75, 80, 145, 122, 84, 79, 228, 41, 177, 40, 60, 127, 159, 165, 128, 114, 181, 60, 55, 146, 154, 135, 96, 137, 67, 157, 130, 36, 152, 154, 69, 47, 93, 122, 78, 150, 185, 83, 136, 165, 49, 75, 208, 157, 168, 90, 67, 122, 143, 154, 151, 132, 73, 165, 132, 175, 97, 76, 86, 139, 182, 48, 166
The differences are at most 1.
For my usecase it would be the best to have a complete compatibility but I guess that is not a goal of this library. I don't know yet whether I will use the Interpolation
or try some other approach. Anyway thanks for implementing it.
Hello is it possible to achieve exactly same results with this library as if I was using
cv2.resize
withinterpolation=cv2.INTER_LINEAR
from OpenCV?I tried using
Resizer::new(Convolution(Bilinear))
but the pixel values in the resulting image are slightly different.Thanks