Skip to content

Commit

Permalink
revives stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
edgarriba committed Feb 15, 2024
1 parent 41874db commit e442e11
Show file tree
Hide file tree
Showing 14 changed files with 346 additions and 258 deletions.
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ candle = ["candle-core"]
name = "color_benchmark"
harness = false

#[[bench]]
#name = "resize_benchmark"
#harness = false
[[bench]]
name = "resize_benchmark"
harness = false
15 changes: 8 additions & 7 deletions benches/color_benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use candle_core::{DType, Device, Storage, Tensor};
use std::ops::Deref;

// vanilla version
fn gray_iter(image: &Image<u8, 3>) -> Image<u8, 1> {
fn gray_iter(image: &Image<f32, 3>) -> Image<u8, 1> {
let data = vec![0u8; image.image_size().width * image.image_size().height];
let mut gray_image = Image::new(image.image_size(), data).unwrap();
for y in 0..image.height() {
Expand All @@ -26,9 +26,9 @@ fn gray_iter(image: &Image<u8, 3>) -> Image<u8, 1> {
gray_image
}

fn gray_vec(image: &Image<u8, 3>) -> Image<u8, 1> {
fn gray_vec(image: &Image<f32, 3>) -> Image<u8, 1> {
// convert to f32
let mut image_f32 = image.data_ref().mapv(|x| x as f32);
let mut image_f32 = image.data.mapv(|x| x as f32);

// get channels
let mut binding = image_f32.view_mut();
Expand Down Expand Up @@ -105,20 +105,21 @@ fn bench_grayscale(c: &mut Criterion) {
let id = format!("{}x{}", width, height);
let image_data = vec![0u8; width * height * 3];
let image = Image::new(ImageSize { width, height }, image_data).unwrap();
group.bench_with_input(BenchmarkId::new("zip", &id), &image, |b, i| {
let image_f32 = image.clone().cast::<f32>().unwrap();
group.bench_with_input(BenchmarkId::new("zip", &id), &image_f32, |b, i| {
b.iter(|| F::gray_from_rgb(black_box(i)))
});
group.bench_with_input(BenchmarkId::new("iter", &id), &image, |b, i| {
group.bench_with_input(BenchmarkId::new("iter", &id), &image_f32, |b, i| {
b.iter(|| gray_iter(black_box(&i.clone())))
});
group.bench_with_input(BenchmarkId::new("vec", &id), &image, |b, i| {
group.bench_with_input(BenchmarkId::new("vec", &id), &image_f32, |b, i| {
b.iter(|| gray_vec(black_box(&i.clone())))
});
group.bench_with_input(BenchmarkId::new("image_crate", &id), &image, |b, i| {
b.iter(|| gray_image_crate(black_box(&i.clone())))
});
#[cfg(feature = "candle")]
group.bench_with_input(BenchmarkId::new("candle", &id), &image, |b, i| {
group.bench_with_input(BenchmarkId::new("candle", &id), &image_f32, |b, i| {
b.iter(|| gray_candle(black_box(i.clone())))
});
}
Expand Down
9 changes: 5 additions & 4 deletions benches/resize_benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use kornia_rs::image::{Image, ImageSize};
use kornia_rs::resize as F;
use kornia_rs::resize::{InterpolationMode, ResizeOptions};

fn resize_image_crate(image: Image, new_size: ImageSize) -> Image {
fn resize_image_crate(image: Image<u8, 3>, new_size: ImageSize) -> Image<u8, 3> {
let image_data = image.data.as_slice().unwrap();
let rgb = image::RgbImage::from_raw(
image.image_size().width as u32,
Expand All @@ -20,7 +20,7 @@ fn resize_image_crate(image: Image, new_size: ImageSize) -> Image {
image::imageops::FilterType::Gaussian,
);
let data = image_resized.into_rgb8().into_raw();
Image::from_shape_vec([new_size.height as usize, new_size.width as usize, 3], data)
Image::new(new_size, data).unwrap()
}

fn bench_resize(c: &mut Criterion) {
Expand All @@ -30,12 +30,13 @@ fn bench_resize(c: &mut Criterion) {
for (width, height) in image_sizes {
let image_size = ImageSize { width, height };
let id = format!("{}x{}", width, height);
let image = Image::new(image_size.clone(), vec![0; width * height * 3]);
let image = Image::<u8, 3>::new(image_size.clone(), vec![0u8; width * height * 3]).unwrap();
let image_f32 = image.clone().cast::<f32>().unwrap();
let new_size = ImageSize {
width: width / 2,
height: height / 2,
};
group.bench_with_input(BenchmarkId::new("zip", &id), &image, |b, i| {
group.bench_with_input(BenchmarkId::new("zip", &id), &image_f32, |b, i| {
b.iter(|| {
F::resize(
black_box(i),
Expand Down
32 changes: 13 additions & 19 deletions examples/binarize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,27 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// read the image
let image_path = std::path::Path::new("tests/data/dog.jpeg");
let image = F::read_image_jpeg(image_path)?;
let image_viz = image.clone();

// convert the image to grayscale
let gray = kornia_rs::color::gray_from_rgb(&image)?;
let gray_viz = gray.clone();

// binarize the image
let gray_bin = kornia_rs::threshold::threshold_binary(&gray, 127, 255)?;

// Option1: convert the grayscale image to floating point
let gray_f32 = gray.cast::<f32>()?;

// Option 2: onvert and normalize the grayscale image to floating point
// let gray_f32 = gray.cast_and_scale::<f32>(1.0 / 255, 0.0)?;
// binarize the image as u8
let _image_bin = kornia_rs::threshold::threshold_binary(&image.clone(), 127, 255)?;

// normalize the image between 0 and 1
let gray_f32 = kornia_rs::normalize::normalize_mean_std(&gray_f32, &[0.0], &[255.0])?;
let image_f32 = image.cast_and_scale::<f32>(1.0 / 255.0)?;

// convert to grayscale as floating point
let gray_f32 = kornia_rs::color::gray_from_rgb(&image_f32)?;
let gray_viz = gray_f32.clone();

// binarize the image as floating point
let gray_f32 = kornia_rs::threshold::threshold_binary(&gray_f32, 0.5, 1.0)?;
// binarize the gray image as floating point
let gray_bin = kornia_rs::threshold::threshold_binary(&gray_f32, 0.5, 1.0)?;

// create a Rerun recording stream
let rec = rerun::RecordingStreamBuilder::new("Kornia App").connect()?;

let _ = rec.log("image", &rerun::Image::try_from(image.data())?);
let _ = rec.log("gray", &rerun::Image::try_from(gray_viz.data())?);
let _ = rec.log("gray_bin", &rerun::Image::try_from(gray_bin.data())?);
let _ = rec.log("gray_f32", &rerun::Image::try_from(gray_f32.data())?);
let _ = rec.log("image", &rerun::Image::try_from(image_viz.data)?);
let _ = rec.log("gray", &rerun::Image::try_from(gray_viz.data)?);
let _ = rec.log("gray_bin", &rerun::Image::try_from(gray_bin.data)?);

Ok(())
}
5 changes: 4 additions & 1 deletion examples/hello_world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let image_path = std::path::Path::new("tests/data/dog.jpeg");
let image = F::read_image_jpeg(image_path)?;

println!("Image size: {:?}", image.image_size());
println!("Hello, world!");
println!("Loaded Image size: {:?}", image.image_size());
println!("\nGoodbyte!");

Ok(())
}
13 changes: 8 additions & 5 deletions examples/imgproc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// read the image
let image_path = std::path::Path::new("tests/data/dog.jpeg");
let image = F::read_image_jpeg(image_path)?;
let image_viz = image.clone();

let image_f32 = image.cast_and_scale::<f32>(1.0 / 255.0)?;

// convert the image to grayscale
let gray = kornia_rs::color::gray_from_rgb(&image)?;
let gray = kornia_rs::color::gray_from_rgb(&image_f32)?;

let gray_resize = kornia_rs::resize::resize(
&gray,
Expand All @@ -18,17 +21,17 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
kornia_rs::resize::ResizeOptions {
interpolation: kornia_rs::resize::InterpolationMode::Bilinear,
},
);
)?;

println!("gray_resize: {:?}", gray_resize.image_size());

// create a Rerun recording stream
let rec = rerun::RecordingStreamBuilder::new("Kornia App").connect()?;

// log the images
let _ = rec.log("image", &rerun::Image::try_from(image.data())?);
let _ = rec.log("gray", &rerun::Image::try_from(gray.data())?);
let _ = rec.log("gray_resize", &rerun::Image::try_from(gray_resize.data())?);
let _ = rec.log("image", &rerun::Image::try_from(image_viz.data)?);
let _ = rec.log("gray", &rerun::Image::try_from(gray.data)?);
let _ = rec.log("gray_resize", &rerun::Image::try_from(gray_resize.data)?);

Ok(())
}
30 changes: 30 additions & 0 deletions examples/normalize.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use kornia_rs::io::functions as F;

fn main() -> Result<(), Box<dyn std::error::Error>> {
// read the image
let image_path = std::path::Path::new("tests/data/dog.jpeg");
let image = F::read_image_jpeg(image_path)?;

// cast the image to floating point
let image_f32 = image.clone().cast::<f32>()?;

// normalize the image between 0 and 255
let _image_f32_norm = kornia_rs::normalize::normalize_mean_std(
&image_f32,
&[127.5, 127.5, 127.5],
&[127.5, 127.5, 127.5],
)?;

// alternative way to normalize the image between 0 and 255
let _image_f32_norm = image.clone().cast_and_scale::<f32>(1.0 / 255.0)?;
// Or: image.cast_and_scale::<f64>(1.0 / 255.0)?;

// alternative way to normalize the image between 0 and 1
let _image_f32_norm = image_f32.mul(1.0 / 255.0);
// Or: let image_f32_norm = image_f32.div(255.0);

let (min, max) = kornia_rs::normalize::find_min_max(&image_f32)?;
println!("min: {:?}, max: {:?}", min, max);

Ok(())
}
29 changes: 29 additions & 0 deletions examples/normalize_ii.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use kornia_rs::io::functions as F;

fn main() -> Result<(), Box<dyn std::error::Error>> {
// read the image
let image_path = std::path::Path::new("tests/data/dog.jpeg");
let image = F::read_image_jpeg(image_path)?;

// cast the image to floating point
let image_f32 = image.clone().cast_and_scale::<f32>(1.0 / 255.0)?;

// convert to grayscale
let gray_f32 = kornia_rs::color::gray_from_rgb(&image_f32)?;

// normalize the image each channel
let _image_norm =
kornia_rs::normalize::normalize_mean_std(&image_f32, &[0.5, 0.5, 0.5], &[0.5, 0.5, 0.5])?;

// normalize the grayscale image
let _gray_norm = kornia_rs::normalize::normalize_mean_std(&gray_f32, &[0.5], &[0.5])?;

// alternative way to normalize the image between 0 and 255
// let _gray_norm_min_max = kornia_rs::normalize::normalize_min_max(
// &gray, 0.0, 255.0)?;

let (min, max) = kornia_rs::normalize::find_min_max(&gray_f32)?;
println!("min: {:?}, max: {:?}", min, max);

Ok(())
}
2 changes: 1 addition & 1 deletion examples/rerun_viz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let rec = rerun::RecordingStreamBuilder::new("Kornia App").connect()?;

// log the image
let _ = rec.log("image", &rerun::Image::try_from(image.data())?);
let _ = rec.log("image", &rerun::Image::try_from(image.data)?);

Ok(())
}
12 changes: 5 additions & 7 deletions src/color.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use crate::image::Image;
use anyhow::Result;
use ndarray::{Array3, Zip};
use num_traits::{Num, NumCast};

// TODO: ideally we want something like this:
// let rgb: Image<u8, RGB> = load_image("image.jpg");
Expand Down Expand Up @@ -45,16 +43,16 @@ where

let mut output = Image::<T, 1>::from_shape(image.image_size())?;

Zip::from(output.data.rows_mut())
ndarray::Zip::from(output.data.rows_mut())
.and(image.data.rows())
.par_for_each(|mut out, inp| {
assert_eq!(inp.len(), 3);
let r = NumCast::from(inp[0]).unwrap();
let g = NumCast::from(inp[1]).unwrap();
let b = NumCast::from(inp[2]).unwrap();
let r = num_traits::NumCast::from(inp[0]).unwrap();
let g = num_traits::NumCast::from(inp[1]).unwrap();
let b = num_traits::NumCast::from(inp[2]).unwrap();
let gray = rw * r + gw * g + bw * b;

out[0] = NumCast::from(gray).unwrap();
out[0] = num_traits::NumCast::from(gray).unwrap();
});

Ok(output)
Expand Down
30 changes: 19 additions & 11 deletions src/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ impl<T, const CHANNELS: usize> Image<T, CHANNELS> {
Ok(image)
}

pub fn empty_like(&self) -> Result<Self>
pub fn zeros_like(&self) -> Result<Self>
where
T: Clone + Default,
{
Expand Down Expand Up @@ -122,6 +122,24 @@ impl<T, const CHANNELS: usize> Image<T, CHANNELS> {
Ok(Image { data: casted_data })
}

// TODO: optimize this
pub fn mul(&self, scale: T) -> Self
where
T: Copy + std::ops::Mul<Output = T>,
{
let scaled_data = self.data.map(|&x| x * scale);
Image { data: scaled_data }
}

// TODO: optimize this
pub fn div(&self, scale: T) -> Self
where
T: Copy + std::ops::Div<Output = T>,
{
let scaled_data = self.data.map(|&x| x / scale);
Image { data: scaled_data }
}

pub fn image_size(&self) -> ImageSize {
ImageSize {
width: self.width(),
Expand All @@ -138,18 +156,9 @@ impl<T, const CHANNELS: usize> Image<T, CHANNELS> {
}

pub fn num_channels(&self) -> usize {
//self.data.shape()[2]
CHANNELS
}

pub fn data(self) -> ndarray::Array<T, ndarray::Dim<[ndarray::Ix; 3]>> {
self.data
}

pub fn data_ref(&self) -> &ndarray::Array<T, ndarray::Dim<[ndarray::Ix; 3]>> {
&self.data
}

//pub fn from_shape_vec(shape: [usize; 2], data: Vec<T>) -> Image<T> {
// let image = match ndarray::Array::<T, _>::from_shape_vec(shape, data) {
// Ok(image) => image,
Expand Down Expand Up @@ -211,7 +220,6 @@ mod tests {
// assert_eq!(image.image_size().height, 195);
// assert_eq!(image.num_channels(), 3);
//}
#[test]
fn image_from_vec() {
use crate::image::Image;
let image: Image<f32, 3> = Image::new(
Expand Down
Loading

0 comments on commit e442e11

Please sign in to comment.