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

Drop conv dependency #562

Merged
merged 1 commit into from
Mar 30, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
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
Loading