Skip to content

Commit

Permalink
Drop conv dependency (#562)
Browse files Browse the repository at this point in the history
  • Loading branch information
paolobarbolini authored Mar 30, 2024
1 parent 1c756b3 commit 8c3ae86
Show file tree
Hide file tree
Showing 8 changed files with 42 additions and 67 deletions.
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ display-window = ["sdl2"]
[dependencies]
ab_glyph = "0.2.23"
approx = "0.5"
conv = "0.3.3"
image = { version = "0.25.0", default-features = false }
itertools = "0.12"
nalgebra = { version = "0.32", default-features = false, features = ["std"] }
Expand Down
5 changes: 2 additions & 3 deletions src/drawing/text.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use conv::ValueInto;
use image::{GenericImage, ImageBuffer, Pixel};
use std::f32;

Expand Down Expand Up @@ -59,7 +58,7 @@ pub fn draw_text_mut<C>(
text: &str,
) where
C: Canvas,
<C::Pixel as Pixel>::Subpixel: ValueInto<f32> + Clamp<f32>,
<C::Pixel as Pixel>::Subpixel: Into<f32> + Clamp<f32>,
{
let image_width = canvas.width() as i32;
let image_height = canvas.height() as i32;
Expand Down Expand Up @@ -97,7 +96,7 @@ pub fn draw_text<I>(
) -> Image<I::Pixel>
where
I: GenericImage,
<I::Pixel as Pixel>::Subpixel: ValueInto<f32> + Clamp<f32>,
<I::Pixel as Pixel>::Subpixel: Into<f32> + Clamp<f32>,
{
let mut out = ImageBuffer::new(image.width(), image.height());
out.copy_from(image, 0, 0).unwrap();
Expand Down
20 changes: 9 additions & 11 deletions src/filter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ use crate::integral_image::{column_running_sum, row_running_sum};
use crate::map::{ChannelMap, WithChannel};
use num::{abs, pow, Num};

use crate::math::cast;
use conv::ValueInto;
use std::cmp::{max, min};
use std::f32;

Expand Down Expand Up @@ -237,7 +235,7 @@ impl<'a, K: Num + Copy + 'a> Kernel<'a, K> {
pub fn filter<P, F, Q>(&self, image: &Image<P>, mut f: F) -> Image<Q>
where
P: Pixel,
<P as Pixel>::Subpixel: ValueInto<K>,
<P as Pixel>::Subpixel: Into<K>,
Q: Pixel,
F: FnMut(&mut Q::Subpixel, K),
{
Expand Down Expand Up @@ -304,7 +302,7 @@ fn gaussian_kernel_f32(sigma: f32) -> Vec<f32> {
pub fn gaussian_blur_f32<P>(image: &Image<P>, sigma: f32) -> Image<P>
where
P: Pixel,
<P as Pixel>::Subpixel: ValueInto<f32> + Clamp<f32>,
<P as Pixel>::Subpixel: Into<f32> + Clamp<f32>,
{
assert!(sigma > 0.0, "sigma must be > 0.0");
let kernel = gaussian_kernel_f32(sigma);
Expand All @@ -317,7 +315,7 @@ where
pub fn separable_filter<P, K>(image: &Image<P>, h_kernel: &[K], v_kernel: &[K]) -> Image<P>
where
P: Pixel,
<P as Pixel>::Subpixel: ValueInto<K> + Clamp<K>,
<P as Pixel>::Subpixel: Into<K> + Clamp<K>,
K: Num + Copy,
{
let h = horizontal_filter(image, h_kernel);
Expand All @@ -330,7 +328,7 @@ where
pub fn separable_filter_equal<P, K>(image: &Image<P>, kernel: &[K]) -> Image<P>
where
P: Pixel,
<P as Pixel>::Subpixel: ValueInto<K> + Clamp<K>,
<P as Pixel>::Subpixel: Into<K> + Clamp<K>,
K: Num + Copy,
{
separable_filter(image, kernel, kernel)
Expand All @@ -341,7 +339,7 @@ where
#[must_use = "the function does not modify the original image"]
pub fn filter3x3<P, K, S>(image: &Image<P>, kernel: &[K]) -> Image<ChannelMap<P, S>>
where
P::Subpixel: ValueInto<K>,
P::Subpixel: Into<K>,
S: Clamp<K> + Primitive,
P: WithChannel<S>,
K: Num + Copy,
Expand All @@ -357,7 +355,7 @@ where
pub fn horizontal_filter<P, K>(image: &Image<P>, kernel: &[K]) -> Image<P>
where
P: Pixel,
<P as Pixel>::Subpixel: ValueInto<K> + Clamp<K>,
<P as Pixel>::Subpixel: Into<K> + Clamp<K>,
K: Num + Copy,
{
// Don't replace this with a call to Kernel::filter without
Expand Down Expand Up @@ -453,7 +451,7 @@ where
pub fn vertical_filter<P, K>(image: &Image<P>, kernel: &[K]) -> Image<P>
where
P: Pixel,
<P as Pixel>::Subpixel: ValueInto<K> + Clamp<K>,
<P as Pixel>::Subpixel: Into<K> + Clamp<K>,
K: Num + Copy,
{
// Don't replace this with a call to Kernel::filter without
Expand Down Expand Up @@ -550,11 +548,11 @@ where
fn accumulate<P, K>(acc: &mut [K], pixel: &P, weight: K)
where
P: Pixel,
<P as Pixel>::Subpixel: ValueInto<K>,
<P as Pixel>::Subpixel: Into<K>,
K: Num + Copy,
{
for i in 0..(P::CHANNEL_COUNT as usize) {
acc[i] = acc[i] + cast(pixel.channels()[i]) * weight;
acc[i] = acc[i] + pixel.channels()[i].into() * weight;
}
}

Expand Down
38 changes: 18 additions & 20 deletions src/geometric_transformations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
//! projective transformations.
use crate::definitions::{Clamp, Image};
use crate::math::cast;
use conv::ValueInto;
use image::{GenericImageView, ImageBuffer, Pixel};
#[cfg(feature = "rayon")]
use rayon::prelude::*;
Expand Down Expand Up @@ -286,7 +284,7 @@ pub fn rotate_about_center<P>(
where
P: Pixel + Send + Sync,
<P as Pixel>::Subpixel: Send + Sync,
<P as Pixel>::Subpixel: ValueInto<f32> + Clamp<f32>,
<P as Pixel>::Subpixel: Into<f32> + Clamp<f32>,
{
let (w, h) = image.dimensions();
rotate(
Expand All @@ -311,7 +309,7 @@ pub fn rotate<P>(
where
P: Pixel + Send + Sync,
<P as Pixel>::Subpixel: Send + Sync,
<P as Pixel>::Subpixel: ValueInto<f32> + Clamp<f32>,
<P as Pixel>::Subpixel: Into<f32> + Clamp<f32>,
{
let (cx, cy) = center;
let projection =
Expand Down Expand Up @@ -384,7 +382,7 @@ pub fn warp<P>(
where
P: Pixel + Send + Sync,
<P as Pixel>::Subpixel: Send + Sync,
<P as Pixel>::Subpixel: ValueInto<f32> + Clamp<f32>,
<P as Pixel>::Subpixel: Into<f32> + Clamp<f32>,
{
let (width, height) = image.dimensions();
let mut out = ImageBuffer::new(width, height);
Expand All @@ -404,7 +402,7 @@ pub fn warp_into<P>(
) where
P: Pixel + Send + Sync,
<P as Pixel>::Subpixel: Send + Sync,
<P as Pixel>::Subpixel: ValueInto<f32> + Clamp<f32> + Sync,
<P as Pixel>::Subpixel: Into<f32> + Clamp<f32> + Sync,
{
let projection = projection.invert();
let nn = |x, y| interpolate_nearest(image, x, y, default);
Expand Down Expand Up @@ -456,7 +454,7 @@ where
F: Fn(f32, f32) -> (f32, f32) + Sync + Send,
P: Pixel + Send + Sync,
<P as Pixel>::Subpixel: Send + Sync,
<P as Pixel>::Subpixel: ValueInto<f32> + Clamp<f32>,
<P as Pixel>::Subpixel: Into<f32> + Clamp<f32>,
{
let (width, height) = image.dimensions();
let mut out = ImageBuffer::new(width, height);
Expand All @@ -478,7 +476,7 @@ pub fn warp_into_with<P, F>(
F: Fn(f32, f32) -> (f32, f32) + Send + Sync,
P: Pixel + Send + Sync,
<P as Pixel>::Subpixel: Send + Sync,
<P as Pixel>::Subpixel: ValueInto<f32> + Clamp<f32>,
<P as Pixel>::Subpixel: Into<f32> + Clamp<f32>,
{
let nn = |x, y| interpolate_nearest(image, x, y, default);
let bl = |x, y| interpolate_bilinear(image, x, y, default);
Expand All @@ -498,7 +496,7 @@ fn warp_inner<P, Fc, Fi>(out: &mut Image<P>, mapping: Fc, get_pixel: Fi)
where
P: Pixel,
<P as Pixel>::Subpixel: Send + Sync,
<P as Pixel>::Subpixel: ValueInto<f32> + Clamp<f32>,
<P as Pixel>::Subpixel: Into<f32> + Clamp<f32>,
Fc: Fn(f32, f32) -> (f32, f32) + Send + Sync,
Fi: Fn(f32, f32) -> P + Send + Sync,
{
Expand Down Expand Up @@ -600,15 +598,15 @@ fn mul3x3(a: [f32; 9], b: [f32; 9]) -> [f32; 9] {
fn blend_cubic<P>(px0: &P, px1: &P, px2: &P, px3: &P, x: f32) -> P
where
P: Pixel,
P::Subpixel: ValueInto<f32> + Clamp<f32>,
P::Subpixel: Into<f32> + Clamp<f32>,
{
let mut outp = *px0;

for i in 0..(P::CHANNEL_COUNT as usize) {
let p0 = cast(px0.channels()[i]);
let p1 = cast(px1.channels()[i]);
let p2 = cast(px2.channels()[i]);
let p3 = cast(px3.channels()[i]);
let p0 = px0.channels()[i].into();
let p1 = px1.channels()[i].into();
let p2 = px2.channels()[i].into();
let p3 = px3.channels()[i].into();
#[rustfmt::skip]
let pval = p1 + 0.5 * x * (p2 - p0 + x * (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3 + x * (3.0 * (p1 - p2) + p3 - p0)));
outp.channels_mut()[i] = <P as Pixel>::Subpixel::clamp(pval);
Expand All @@ -620,7 +618,7 @@ where
fn interpolate_bicubic<P>(image: &Image<P>, x: f32, y: f32, default: P) -> P
where
P: Pixel,
<P as Pixel>::Subpixel: ValueInto<f32> + Clamp<f32>,
<P as Pixel>::Subpixel: Into<f32> + Clamp<f32>,
{
let left = x.floor() - 1f32;
let right = left + 4f32;
Expand Down Expand Up @@ -664,25 +662,25 @@ fn blend_bilinear<P>(
) -> P
where
P: Pixel,
P::Subpixel: ValueInto<f32> + Clamp<f32>,
P::Subpixel: Into<f32> + Clamp<f32>,
{
let top = top_left.map2(&top_right, |u, v| {
P::Subpixel::clamp((1f32 - right_weight) * cast(u) + right_weight * cast(v))
P::Subpixel::clamp((1f32 - right_weight) * u.into() + right_weight * v.into())
});

let bottom = bottom_left.map2(&bottom_right, |u, v| {
P::Subpixel::clamp((1f32 - right_weight) * cast(u) + right_weight * cast(v))
P::Subpixel::clamp((1f32 - right_weight) * u.into() + right_weight * v.into())
});

top.map2(&bottom, |u, v| {
P::Subpixel::clamp((1f32 - bottom_weight) * cast(u) + bottom_weight * cast(v))
P::Subpixel::clamp((1f32 - bottom_weight) * u.into() + bottom_weight * v.into())
})
}

fn interpolate_bilinear<P>(image: &Image<P>, x: f32, y: f32, default: P) -> P
where
P: Pixel,
<P as Pixel>::Subpixel: ValueInto<f32> + Clamp<f32>,
<P as Pixel>::Subpixel: Into<f32> + Clamp<f32>,
{
let left = x.floor();
let right = left + 1f32;
Expand Down
13 changes: 0 additions & 13 deletions src/math.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
//! Assorted mathematical helper functions.
use conv::ValueInto;

/// L1 norm of a vector.
pub fn l1_norm(xs: &[f32]) -> f32 {
xs.iter().fold(0f32, |acc, x| acc + x.abs())
Expand All @@ -11,14 +9,3 @@ pub fn l1_norm(xs: &[f32]) -> f32 {
pub fn l2_norm(xs: &[f32]) -> f32 {
xs.iter().fold(0f32, |acc, x| acc + x * x).sqrt()
}

/// Helper for a conversion that we know can't fail.
pub fn cast<T, U>(x: T) -> U
where
T: ValueInto<U>,
{
match x.value_into() {
Ok(y) => y,
Err(_) => panic!("Failed to convert"),
}
}
8 changes: 3 additions & 5 deletions src/noise.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
//! Functions for adding synthetic noise to images.
use crate::definitions::{Clamp, HasBlack, HasWhite, Image};
use crate::math::cast;
use conv::ValueInto;
use image::Pixel;
use rand::{rngs::StdRng, SeedableRng};
use rand_distr::{Distribution, Normal, Uniform};
Expand All @@ -12,7 +10,7 @@ use rand_distr::{Distribution, Normal, Uniform};
pub fn gaussian_noise<P>(image: &Image<P>, mean: f64, stddev: f64, seed: u64) -> Image<P>
where
P: Pixel,
P::Subpixel: ValueInto<f64> + Clamp<f64>,
P::Subpixel: Into<f64> + Clamp<f64>,
{
let mut out = image.clone();
gaussian_noise_mut(&mut out, mean, stddev, seed);
Expand All @@ -24,15 +22,15 @@ where
pub fn gaussian_noise_mut<P>(image: &mut Image<P>, mean: f64, stddev: f64, seed: u64)
where
P: Pixel,
P::Subpixel: ValueInto<f64> + Clamp<f64>,
P::Subpixel: Into<f64> + Clamp<f64>,
{
let mut rng: StdRng = SeedableRng::seed_from_u64(seed);
let normal = Normal::new(mean, stddev).unwrap();

for p in image.pixels_mut() {
for c in p.channels_mut() {
let noise = normal.sample(&mut rng);
*c = P::Subpixel::clamp(cast(*c) + noise);
*c = P::Subpixel::clamp((*c).into() + noise);
}
}
}
Expand Down
10 changes: 4 additions & 6 deletions src/pixelops.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
//! Pixel manipulations.
use crate::definitions::Clamp;
use crate::math::cast;
use conv::ValueInto;
use image::Pixel;

/// Adds pixels with the given weights. Results are clamped to prevent arithmetical overflows.
Expand All @@ -24,7 +22,7 @@ use image::Pixel;
/// ```
pub fn weighted_sum<P: Pixel>(left: P, right: P, left_weight: f32, right_weight: f32) -> P
where
P::Subpixel: ValueInto<f32> + Clamp<f32>,
P::Subpixel: Into<f32> + Clamp<f32>,
{
left.map2(&right, |p, q| {
weighted_channel_sum(p, q, left_weight, right_weight)
Expand All @@ -50,17 +48,17 @@ where
/// ```
pub fn interpolate<P: Pixel>(left: P, right: P, left_weight: f32) -> P
where
P::Subpixel: ValueInto<f32> + Clamp<f32>,
P::Subpixel: Into<f32> + Clamp<f32>,
{
weighted_sum(left, right, left_weight, 1.0 - left_weight)
}

#[inline(always)]
fn weighted_channel_sum<C>(left: C, right: C, left_weight: f32, right_weight: f32) -> C
where
C: ValueInto<f32> + Clamp<f32>,
C: Into<f32> + Clamp<f32>,
{
Clamp::clamp(cast(left) * left_weight + cast(right) * right_weight)
Clamp::clamp(left.into() * left_weight + right.into() * right_weight)
}

#[cfg(test)]
Expand Down
14 changes: 6 additions & 8 deletions src/stats.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
//! Statistical properties of images.
use crate::definitions::Image;
use crate::math::cast;
use conv::ValueInto;
use image::{GenericImageView, GrayImage, Pixel, Primitive};
use num::Bounded;

Expand Down Expand Up @@ -110,7 +108,7 @@ where
I: GenericImageView<Pixel = P>,
J: GenericImageView<Pixel = P>,
P: Pixel,
P::Subpixel: ValueInto<f64>,
P::Subpixel: Into<f64>,
{
mean_squared_error(left, right).sqrt()
}
Expand All @@ -124,9 +122,9 @@ where
I: GenericImageView<Pixel = P>,
J: GenericImageView<Pixel = P>,
P: Pixel,
P::Subpixel: ValueInto<f64> + Primitive,
P::Subpixel: Into<f64> + Primitive,
{
let max: f64 = cast(<P::Subpixel as Bounded>::max_value());
let max: f64 = <P::Subpixel as Bounded>::max_value().into();
let mse = mean_squared_error(original, noisy);
20f64 * max.log(10f64) - 10f64 * mse.log(10f64)
}
Expand All @@ -136,14 +134,14 @@ where
I: GenericImageView<Pixel = P>,
J: GenericImageView<Pixel = P>,
P: Pixel,
P::Subpixel: ValueInto<f64>,
P::Subpixel: Into<f64>,
{
assert_dimensions_match!(left, right);
let mut sum_squared_diffs = 0f64;
for (p, q) in left.pixels().zip(right.pixels()) {
for (c, d) in p.2.channels().iter().zip(q.2.channels().iter()) {
let fc: f64 = cast(*c);
let fd: f64 = cast(*d);
let fc: f64 = (*c).into();
let fd: f64 = (*d).into();
let diff = fc - fd;
sum_squared_diffs += diff * diff;
}
Expand Down

0 comments on commit 8c3ae86

Please sign in to comment.