image-rs / image

Encoding and decoding images in Rust
Apache License 2.0
4.97k stars 618 forks source link

Pixel conversions could be more generic to enable more optimal operations #1083

Open nagisa opened 4 years ago

nagisa commented 4 years ago

To rotate by 180 degrees while also converting BGR to RGB, the most efficient implementation is to invert the memory buffer by e.g. a backward memcpy.

I think optimizer should be able to figure this out fairly easily, but we still need a way to do this conversion and rotation in a single operation, which would require some generic way to convert between colourspaces, to allow implementations like these (somewhat pseudo-code):

/// Rotate an image 180 degrees clockwise.
pub fn rotate180<I: GenericImageView, NewPixel: Pixel>(
    image: &I,
) -> ImageBuffer<NewPixel, Vec<<NewPixel as Pixel>::Subpixel>>
    where I::Pixel: Into<NewPixel> + 'static,
{
    let (width, height) = image.dimensions();
    let mut out = ImageBuffer::new(width, height);

    for y in 0..height {
        for x in 0..width {
            let p = image.get_pixel(x, y);
            out.put_pixel(width - 1 - x, height - 1 - y, p.into());
        }
    }

    out
}
fintelia commented 4 years ago

Is this a common operation for some use case?

HeroicKatora commented 4 years ago

If it is common, I imagine a specific implementation on ImageBuffer would be more optimized in any case as it could be implemented to be cache-oblivious which the pseudo-code is not. Look for matrix transposition algorithms if you want to know the details. (Note: optimization potential like this probably already exists for a few other algorithms in imageops.)

nagisa commented 4 years ago

I wouldn’t say it is common, but it is an optimisation that we had implemented in our code when we needed to squeeze out some extra performance. This was a very low hanging fruit.

Originally we had a BayerRG image buffer and wanted to obtain a 180° rotated RGB buffer. Converting to BGR and then reversing the buffer was significantly faster than converting to RGB and then running a plain 180 rotation algorithm.