Skip to content
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

image: implement image getter and setter for dev purpose #230

Merged
merged 4 commits into from
Jan 26, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 88 additions & 19 deletions crates/kornia-image/src/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,8 @@ impl<T, const C: usize> Image<T, C> {

/// Get the pixel data of the image.
///
/// NOTE: experimental api
/// NOTE: this is method is for convenience and not optimized for performance.
/// We recommend using the `get` method instead.
///
/// # Arguments
///
Expand All @@ -429,11 +430,7 @@ impl<T, const C: usize> Image<T, C> {
/// # Returns
///
/// The pixel value at the given coordinates.
#[deprecated(since = "0.1.6", note = "Please use the `get` method instead.")]
pub fn get_pixel(&self, x: usize, y: usize, ch: usize) -> Result<T, ImageError>
where
T: Copy,
{
pub fn get_pixel(&self, x: usize, y: usize, ch: usize) -> Result<&T, ImageError> {
if x >= self.width() || y >= self.height() {
return Err(ImageError::PixelIndexOutOfBounds(
x,
Expand All @@ -452,7 +449,42 @@ impl<T, const C: usize> Image<T, C> {
None => return Err(ImageError::ImageDataNotContiguous),
};

Ok(*val)
Ok(val)
}

/// Set the pixel value at the given coordinates.
///
/// NOTE: this is method is for convenience and not optimized for performance.
/// We recommend creating a mutable slice and operating on it directly.
///
/// # Arguments
///
/// * `x` - The x-coordinate of the pixel.
/// * `y` - The y-coordinate of the pixel.
/// * `ch` - The channel index of the pixel.
/// * `val` - The value to set the pixel to.
///
/// # Returns
///
/// The pixel value at the given coordinates.
pub fn set_pixel(&mut self, x: usize, y: usize, ch: usize, val: T) -> Result<(), ImageError> {
if x >= self.width() || y >= self.height() {
return Err(ImageError::PixelIndexOutOfBounds(
x,
y,
self.width(),
self.height(),
));
}

if ch >= C {
return Err(ImageError::ChannelIndexOutOfBounds(ch, C));
}

let idx = y * self.width() * C + x * C + ch;
self.as_slice_mut()[idx] = val;

Ok(())
}
}

Expand Down Expand Up @@ -500,7 +532,7 @@ mod tests {
use kornia_tensor::{CpuAllocator, Tensor};

#[test]
fn image_size() {
fn test_image_size() {
let image_size = ImageSize {
width: 10,
height: 20,
Expand All @@ -510,7 +542,7 @@ mod tests {
}

#[test]
fn image_smoke() -> Result<(), ImageError> {
fn test_image_smoke() -> Result<(), ImageError> {
let image = Image::<u8, 3>::new(
ImageSize {
width: 10,
Expand All @@ -526,7 +558,7 @@ mod tests {
}

#[test]
fn image_from_vec() -> Result<(), ImageError> {
fn test_image_from_vec() -> Result<(), ImageError> {
let image: Image<f32, 3> = Image::new(
ImageSize {
height: 3,
Expand All @@ -542,7 +574,7 @@ mod tests {
}

#[test]
fn image_cast() -> Result<(), ImageError> {
fn test_image_cast() -> Result<(), ImageError> {
let data = vec![0, 1, 2, 3, 4, 5];
let image_u8 = Image::<_, 3>::new(
ImageSize {
Expand All @@ -560,7 +592,7 @@ mod tests {
}

#[test]
fn image_rgbd() -> Result<(), ImageError> {
fn test_image_rgbd() -> Result<(), ImageError> {
let image = Image::<f32, 4>::new(
ImageSize {
height: 2,
Expand All @@ -576,7 +608,7 @@ mod tests {
}

#[test]
fn image_channel() -> Result<(), ImageError> {
fn test_image_channel() -> Result<(), ImageError> {
let image = Image::<f32, 3>::new(
ImageSize {
height: 2,
Expand All @@ -592,7 +624,7 @@ mod tests {
}

#[test]
fn image_split_channels() -> Result<(), ImageError> {
fn test_image_split_channels() -> Result<(), ImageError> {
let image = Image::<f32, 3>::new(
ImageSize {
height: 2,
Expand All @@ -611,7 +643,7 @@ mod tests {
}

#[test]
fn scale_and_cast() -> Result<(), ImageError> {
fn test_scale_and_cast() -> Result<(), ImageError> {
let data = vec![0u8, 0, 255, 0, 0, 255];
let image_u8 = Image::<u8, 3>::new(
ImageSize {
Expand All @@ -627,7 +659,7 @@ mod tests {
}

#[test]
fn cast_and_scale() -> Result<(), ImageError> {
fn test_cast_and_scale() -> Result<(), ImageError> {
let data = vec![0u8, 0, 255, 0, 0, 255];
let image_u8 = Image::<u8, 3>::new(
ImageSize {
Expand All @@ -643,7 +675,7 @@ mod tests {
}

#[test]
fn image_from_tensor() -> Result<(), ImageError> {
fn test_image_from_tensor() -> Result<(), ImageError> {
let data = vec![0u8, 1, 2, 3, 4, 5];
let tensor = Tensor::<u8, 2, _>::from_shape_vec([2, 3], data, CpuAllocator)?;

Expand All @@ -661,7 +693,7 @@ mod tests {
}

#[test]
fn image_from_tensor_3d() -> Result<(), ImageError> {
fn test_image_from_tensor_3d() -> Result<(), ImageError> {
let tensor = Tensor::<u8, 3, CpuAllocator>::from_shape_vec(
[2, 3, 4],
vec![0u8; 2 * 3 * 4],
Expand All @@ -682,7 +714,7 @@ mod tests {
}

#[test]
fn image_from_raw_parts() -> Result<(), ImageError> {
fn test_image_from_raw_parts() -> Result<(), ImageError> {
let data = vec![0u8, 1, 2, 3, 4, 5];
let image =
unsafe { Image::<_, 1>::from_raw_parts([2, 3].into(), data.as_ptr(), data.len())? };
Expand All @@ -692,4 +724,41 @@ mod tests {
assert_eq!(image.num_channels(), 1);
Ok(())
}

#[test]
fn test_get_pixel() -> Result<(), ImageError> {
let image = Image::<u8, 3>::new(
ImageSize {
height: 2,
width: 1,
},
vec![1, 2, 5, 19, 255, 128],
)?;
assert_eq!(image.get_pixel(0, 0, 0)?, &1);
assert_eq!(image.get_pixel(0, 0, 1)?, &2);
assert_eq!(image.get_pixel(0, 0, 2)?, &5);
assert_eq!(image.get_pixel(0, 1, 0)?, &19);
assert_eq!(image.get_pixel(0, 1, 1)?, &255);
assert_eq!(image.get_pixel(0, 1, 2)?, &128);
Ok(())
}

#[test]
fn test_set_pixel() -> Result<(), ImageError> {
let mut image = Image::<u8, 3>::new(
ImageSize {
height: 2,
width: 1,
},
vec![1, 2, 5, 19, 255, 128],
)?;

image.set_pixel(0, 0, 0, 128)?;
image.set_pixel(0, 1, 1, 25)?;

assert_eq!(image.get_pixel(0, 0, 0)?, &128);
assert_eq!(image.get_pixel(0, 1, 1)?, &25);

Ok(())
}
}
4 changes: 2 additions & 2 deletions crates/kornia-image/src/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ use crate::{Image, ImageError};
///
/// cast_and_scale(&image, &mut image_f32, 1. / 255.0).unwrap();
///
/// assert_eq!(image_f32.get_pixel(0, 0, 0).unwrap(), 0.0f32);
/// assert_eq!(image_f32.get_pixel(1, 0, 0).unwrap(), 1.0f32);
/// assert_eq!(image_f32.get_pixel(0, 0, 0).unwrap(), &0.0f32);
/// assert_eq!(image_f32.get_pixel(1, 0, 0).unwrap(), &1.0f32);
/// ```
pub fn cast_and_scale<T, U, const C: usize>(
src: &Image<T, C>,
Expand Down
4 changes: 2 additions & 2 deletions crates/kornia-imgproc/src/threshold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,8 +329,8 @@ where
/// assert_eq!(thresholded.num_channels(), 1);
/// assert_eq!(thresholded.size().width, 2);
///
/// assert_eq!(thresholded.get_pixel(0, 0, 0).unwrap(), 255);
/// assert_eq!(thresholded.get_pixel(1, 0, 0).unwrap(), 0);
/// assert_eq!(thresholded.get_pixel(0, 0, 0).unwrap(), &255);
/// assert_eq!(thresholded.get_pixel(1, 0, 0).unwrap(), &0);
/// ```
pub fn in_range<T, const C: usize>(
src: &Image<T, C>,
Expand Down
Loading