diff --git a/crates/kornia-image/src/lib.rs b/crates/kornia-image/src/lib.rs index 22b74bd8..e2b4c94c 100644 --- a/crates/kornia-image/src/lib.rs +++ b/crates/kornia-image/src/lib.rs @@ -10,5 +10,8 @@ pub mod error; /// module containing ops implementations. pub mod ops; +/// re-export the safe tensor types so that is easy to use them +pub use kornia_core::SafeTensorType; + pub use crate::error::ImageError; pub use crate::image::{Image, ImageSize}; diff --git a/crates/kornia-io/src/error.rs b/crates/kornia-io/src/error.rs index efdbee9c..69218618 100644 --- a/crates/kornia-io/src/error.rs +++ b/crates/kornia-io/src/error.rs @@ -25,4 +25,8 @@ pub enum IoError { /// Error to decode the image. #[error("Failed to decode the image")] ImageDecodeError(#[from] image::ImageError), + + /// Error to decode the image. + #[error("Unsupported image format")] + UnsupportedImageFormat, } diff --git a/crates/kornia-io/src/functional.rs b/crates/kornia-io/src/functional.rs index d6c15244..ffc2c725 100644 --- a/crates/kornia-io/src/functional.rs +++ b/crates/kornia-io/src/functional.rs @@ -1,6 +1,6 @@ -use std::path::Path; +use std::{ops::Deref, path::Path}; -use kornia_image::{Image, ImageSize}; +use kornia_image::{Image, ImageSize, SafeTensorType}; use crate::error::IoError; @@ -77,17 +77,45 @@ pub fn write_image_jpeg(file_path: impl AsRef, image: &Image) -> Re Ok(()) } +/// A generic image type that can be any of the supported image formats. +pub enum GenericImage { + /// 8-bit grayscale image + L8(Image), + /// 8-bit grayscale image with alpha channel + La8(Image), + /// 8-bit RGB image + Rgb8(Image), + /// 8-bit RGB image with alpha channel + Rgba8(Image), + /// 16-bit grayscale image + L16(Image), + /// 16-bit grayscale image with alpha channel + La16(Image), + /// 16-bit RGB image + Rgb16(Image), + /// 16-bit RGB image with alpha channel + Rgba16(Image), + /// 32-bit float RGB image + Rgb32F(Image), + /// 32-bit float RGB image with alpha channel + Rgba32F(Image), +} + +// NOTE: another option is to use define types for each of the image formats and then implement +// type Mono8 = Image; +// type Rgb8 = Image; + /// Reads an image from the given file path. /// /// The method tries to read from any image format supported by the image crate. /// /// # Arguments /// -/// * `file_path` - The path to the image. +/// * `file_path` - The path to a valid image file. /// /// # Returns /// -/// A tensor containing the image data. +/// An image containing the image data. /// /// # Example /// @@ -101,7 +129,13 @@ pub fn write_image_jpeg(file_path: impl AsRef, image: &Image) -> Re /// assert_eq!(image.size().height, 195); /// assert_eq!(image.num_channels(), 3); /// ``` -pub fn read_image_any(file_path: impl AsRef) -> Result, IoError> { +pub fn read_image_any( + file_path: impl AsRef, +) -> Result +where + T: SafeTensorType, +{ + // resolve the file path correctly let file_path = file_path.as_ref().to_owned(); // verify the file exists @@ -110,25 +144,32 @@ pub fn read_image_any(file_path: impl AsRef) -> Result, IoErr } // open the file and map it to memory + // TODO: explore whether we can use a more efficient memory mapping approach let file = std::fs::File::open(file_path)?; let mmap = unsafe { memmap2::Mmap::map(&file)? }; // decode the data directly from memory // TODO: update the image crate + // TODO: explore supporting directly the decoders #[allow(deprecated)] let img = image::io::Reader::new(std::io::Cursor::new(&mmap)) .with_guessed_format()? .decode()?; - // TODO: handle more image formats - // return the image data - let image = Image::new( - ImageSize { - width: img.width() as usize, - height: img.height() as usize, - }, - img.to_rgb8().to_vec(), - )?; + let size = ImageSize { + width: img.width() as usize, + height: img.height() as usize, + }; + + let image = match img.color() { + image::ColorType::L8 => { + GenericImage::L8(Image::::new(size, img.into_luma8().into_vec())?) + } + image::ColorType::Rgb8 => { + GenericImage::Rgb8(Image::::new(size, img.into_rgb8().into_vec())?) + } + _ => return Err(IoError::UnsupportedImageFormat), + }; Ok(image) } @@ -137,13 +178,16 @@ pub fn read_image_any(file_path: impl AsRef) -> Result, IoErr mod tests { use crate::error::IoError; use crate::functional::read_image_any; + use kornia_image::Image; #[cfg(feature = "jpegturbo")] use crate::functional::{read_image_jpeg, write_image_jpeg}; #[test] fn read_any() -> Result<(), IoError> { - let image = read_image_any("../../tests/data/dog.jpeg")?; + // let image: Image = read_image_any("../../tests/data/dog.jpeg")?; + let image: super::GenericImage = read_image_any("../../tests/data/dog.jpeg")?; + // NOTE: then how to access the size? we need to reimplment the methods ?? assert_eq!(image.size().width, 258); assert_eq!(image.size().height, 195); Ok(())