-
Notifications
You must be signed in to change notification settings - Fork 65
Update tiff reading - writing methods for f32 and u8 datatype #345
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.
Comments suppressed due to low confidence (2)
crates/kornia-io/src/tiff.rs:52
- [nitpick] Consider translating the comment 'Đảm bảo T::Inner là u8' to English for consistency with the rest of the codebase.
T: ColorType<Inner = u8>, // Đảm bảo T::Inner là u8
crates/kornia-io/src/tiff.rs:203
- [nitpick] The test function name 'test_read_image_tiff_rgb8' does not match the usage of 'read_image_tiff_rgba8'; consider renaming the test function for clarity.
let image = read_image_tiff_rgba8(&file_path).unwrap();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make sure to format your code with rustfmt and run the tests as one of your test fails.
crates/kornia-io/src/error.rs
Outdated
@@ -26,6 +26,15 @@ pub enum IoError { | |||
#[error("Error with Jpeg encoding")] | |||
JpegEncodingError(#[from] jpeg_encoder::EncodingError), | |||
|
|||
|
|||
/// Error decoding the TIFF image. | |||
#[error("Error with TIFF decoding")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#[error("Error with TIFF decoding")] | |
#[error("Error with TIFF decoding. {0}")] |
Let's make the errors more informational. I have also made them in #336
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i advocate more to use #[error(transparent)]
to forward directly the original errors
https://github.com/kornia/kornia-rs/blob/main/crates/kornia-io/src/stream/error.rs#L5
crates/kornia-io/src/error.rs
Outdated
TiffError(#[from] tiff::TiffError), | ||
|
||
/// Error to create the TIFF image. | ||
#[error("Error with TIFF encoding")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#[error("Error with TIFF encoding")] | |
#[error("Error with TIFF encoding. {0}")] |
Same
crates/kornia-io/src/tiff.rs
Outdated
image: &Image<u8, C>, | ||
) -> Result<(), IoError> | ||
where | ||
T: ColorType<Inner = u8>, // Đảm bảo T::Inner là u8 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick, consider writing the comment in english
crates/kornia-io/src/tiff.rs
Outdated
if image.num_channels() != C { | ||
return Err(IoError::TiffEncodingError( | ||
format!("Image has {} channels, but expected {}", image.num_channels(), C) | ||
)); | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if image.num_channels() != C { | |
return Err(IoError::TiffEncodingError( | |
format!("Image has {} channels, but expected {}", image.num_channels(), C) | |
)); | |
} |
Consider removing this check, as it is a internal function and the public facing functions ensure that the correct number of channels are provided.
/// Reads a TIFF image with a single channel (rgb8). | ||
/// #Arguments | ||
/// file_path - The path to the TIFF file. | ||
/// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Reads a TIFF image with a single channel (rgb8). | |
/// #Arguments | |
/// file_path - The path to the TIFF file. | |
/// | |
/// Reads a TIFF image with a three channel (rgb8). | |
/// | |
/// # Arguments | |
/// | |
/// - `file_path` - The path to the TIFF file. |
Make it in markdown format, so it render properly on docs.rs
#[test] | ||
fn read_jpeg_f32() -> Result<(), IoError> { | ||
let image = read_image_jpeg_mono8("../../tests/data/dog.jpeg")?; | ||
assert_eq!(image.cols(), 258); | ||
assert_eq!(image.rows(), 195); | ||
Ok(()) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#[test] | |
fn read_jpeg_f32() -> Result<(), IoError> { | |
let image = read_image_jpeg_mono8("../../tests/data/dog.jpeg")?; | |
assert_eq!(image.cols(), 258); | |
assert_eq!(image.rows(), 195); | |
Ok(()) | |
} |
Firstly, the name of the test doesn't make sense as jpeg doesn't support f32 and you are using read_image_jpeg_mono8
in it.
And secondly, this doesn't work. It will give ImageCreationError(InvalidChannelShape(150930, 50310))
error.
Make sure to run the tests first.
/// | ||
/// This trait is used to convert TIFF values (u8 or f32) to a specific type (e.g., u8 or f32). | ||
/// It provides two methods: | ||
pub trait TiffValueConverter: Sized { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should have a simple trait (could be internal?) with only one function like type_
and should have it's implementation for all numeric primitive types that could be bound to generic T
(P
in your case, change it to T
so that it's globally same).
The type_
function could be used to verify if the decoded image is of same type, if not return error.
This could be used to to only allow integer primitive types. Also, we should not deal with any conversion and make it up to the user if they want to covert the type.
Then your functions should look something like:
pub trait NumericTrait {
fn type_() -> NumericType;
}
pub fn read_image_tiff_rgba8<T: NumericTrait>(file_path: impl AsRef<Path>) -> Result<Image<T, 4>, IoError> {
todo!()
}
pub fn read_image_tiff_internal<T: NumericTrait>(/* arguments */) -> /* ... */
What do you say @edgarriba ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds good to me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello, I think we should provide more details when implementing images for our application. It could be a marker type instead of struct u8 in this context, for example:
let rgb_image: Image<u8, 4> = read_image_any::<Rgba8>("image.jpg")?;
From my vision, this could be more sustainable in case we would provide more features for the fourth channel, like depth or heat instead of alpha.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@edgarriba , @AS1100K
Would it be a good one in this case? If it's good to go, i'm gonna include these for the next pull request
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for now we decided in a previous conversation in discord to hold on the read_any and leave generalizations for later
use std::fs; | ||
use std::path::PathBuf; | ||
use kornia_image::ImageSize; | ||
#[test] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, add a read_write test
Refer
kornia-rs/crates/kornia-io/src/jpeg.rs
Lines 123 to 139 in d959fb3
fn read_write_jpeg() -> Result<(), IoError> { | |
let tmp_dir = tempfile::tempdir()?; | |
create_dir_all(tmp_dir.path())?; | |
let file_path = tmp_dir.path().join("dog.jpeg"); | |
let image_data = read_image_jpeg_rgb8("../../tests/data/dog.jpeg")?; | |
write_image_jpeg_rgb8(&file_path, &image_data)?; | |
let image_data_back = read_image_jpeg_rgb8(&file_path)?; | |
assert!(file_path.exists(), "File does not exist: {:?}", file_path); | |
assert_eq!(image_data_back.cols(), 258); | |
assert_eq!(image_data_back.rows(), 195); | |
assert_eq!(image_data_back.num_channels(), 3); | |
Ok(()) | |
} |
let image = Image::new(ImageSize { width: 100, height: 100 }, vec![0; 30000]).unwrap(); | ||
let file_path = PathBuf::from("test_rgb8.tiff"); | ||
assert!(write_image_tiff_rgb8(&file_path, &image).is_ok()); | ||
fs::remove_file(file_path).unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use tempfile
crate for this, as all the similar tests in this crate uses it
crates/kornia-io/src/tiff.rs
Outdated
let image = Image::new(ImageSize { width: 100, height: 100 }, vec![0; 10000]).unwrap(); | ||
let file_path = PathBuf::from("test_gray8.tiff"); | ||
assert!(write_image_tiff_gray8(&file_path, &image).is_ok()); | ||
fs::remove_file(file_path).unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same
crates/kornia-io/src/error.rs
Outdated
@@ -26,6 +26,15 @@ pub enum IoError { | |||
#[error("Error with Jpeg encoding")] | |||
JpegEncodingError(#[from] jpeg_encoder::EncodingError), | |||
|
|||
|
|||
/// Error decoding the TIFF image. | |||
#[error("Error with TIFF decoding")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i advocate more to use #[error(transparent)]
to forward directly the original errors
https://github.com/kornia/kornia-rs/blob/main/crates/kornia-io/src/stream/error.rs#L5
}; | ||
use std::fs::File; | ||
use std::path::Path; | ||
use std::io::BufWriter; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
group properly the imports, probably cargo fmt will do this for you
/// | ||
/// This trait is used to convert TIFF values (u8 or f32) to a specific type (e.g., u8 or f32). | ||
/// It provides two methods: | ||
pub trait TiffValueConverter: Sized { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds good to me
} | ||
|
||
let file = File::open(&file_path)?; | ||
let mut decoder = Decoder::new(file).map_err(IoError::TiffError)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let mut decoder = Decoder::new(file).map_err(IoError::TiffError)?; | |
let mut decoder = Decoder::new(file)?; |
forward error diectly like this
|
add traits TiffValueConverter
add write_image_tiff_internal(), and example for u8 only
add read_image_tiff_internal(), and example for u8, f32 (experiments)