image-ndarray

Crates.ioimage-ndarray
lib.rsimage-ndarray
version0.1.5
created_at2025-10-27 12:05:19.992491+00
updated_at2025-11-12 18:36:19.255931+00
descriptionZero-copy implementations for the Image crate to convert to and from ndarrays
homepage
repositoryhttps://codeberg.org/gillesvink/image-ndarray
max_upload_size
id1902779
size52,006
Gilles Vink (gillesvink)

documentation

https://docs.rs/image-ndarray

README

Tests License Version

image-ndarray

Zero-copy implementations for the Image crate to convert to and from ndarrays.

Working with ndarrays allows for easy manipulation of pixel values.

While there is another crate called ndarray-image, that works with dedicated types. This crate does not and implements the methods directly onto the ImageBuffer objects.

Usage

Add the crate to your project:

cargo add image-ndarray

Then in your project, when you want to use the ndarrays on the images, make sure to add the prelude:

use image_ndarray::prelude::*;

Example

Adding a simple value:

#[cfg(feature = "image")]
{
    use image::Rgba32FImage;
    use image_ndarray::prelude::*;

    let mut my_image = Rgba32FImage::new(1920, 1080);

    assert!(my_image.to_vec() == vec![0.0; 1920 * 1080 * 4]);

    let mut array = my_image.as_ndarray_mut();
    array += 1.0;

    assert!(my_image.to_vec() == vec![1.0; 1920 * 1080 * 4]);
}

Adding another image:

#[cfg(feature = "image")]
{
    use image::Rgba32FImage;
    use image_ndarray::prelude::*;

    let mut my_image = Rgba32FImage::new(1920, 1080);
    let second_image = Rgba32FImage::from_vec(1920, 1080, vec![1.0; 1920 * 1080 * 4]).unwrap();
    assert!(my_image.to_vec() == vec![0.0; 1920 * 1080 * 4]);

    let mut array = my_image.as_ndarray_mut();
    array += &second_image.as_ndarray();

    assert!(my_image.to_vec() == vec![1.0; 1920 * 1080 * 4]);
}

Dividing another image (just any math operation supported by ndarray):

#[cfg(feature = "image")]
{
    use image::Rgba32FImage;
    use image_ndarray::prelude::*;

    let mut my_image = Rgba32FImage::from_vec(1920, 1080, vec![1.0; 1920 * 1080 * 4]).unwrap();
    let second_image = Rgba32FImage::from_vec(1920, 1080, vec![2.0; 1920 * 1080 * 4]).unwrap();
    assert!(my_image.to_vec() == vec![1.0; 1920 * 1080 * 4]);

    let mut array = my_image.as_ndarray_mut();
    array /= &second_image.as_ndarray();

    assert!(my_image.to_vec() == vec![0.5; 1920 * 1080 * 4]);
}

Convert image to array:

#[cfg(feature = "image")]
{
    use image::Rgba32FImage;
    use image_ndarray::prelude::*;

    let my_image = Rgba32FImage::from_vec(1920, 1080, vec![1.0; 1920 * 1080 * 4]).unwrap();
    let array = my_image.to_ndarray();

    assert!(array.as_slice().unwrap().to_vec() == vec![1.0; 1920 * 1080 * 4]);
}

Or just create an image from the provided array :

#[cfg(feature = "image")]
{
    use image::Rgba32FImage;
    use image_ndarray::prelude::*;
    use ndarray::Array3;

    let array = Array3::from_elem((1080, 1920, 4), 1.0);
    let my_image = Rgba32FImage::from_ndarray(array).unwrap();

    assert!(my_image.to_vec() == vec![1.0; 1920 * 1080 * 4]);
}

And convert an u8 image into a f32 array:

use image_ndarray::prelude::*;
use ndarray::Array3;

let array = Array3::<u8>::from_elem((1080, 1920, 4), 255);
let float_array = array.map(|f| f.to_f32_normalized().unwrap());

let max_value = float_array.iter().cloned().fold(f32::MIN, f32::max);
assert!(max_value == 1.0);

Commit count: 0

cargo fmt