Rust-Imageproc: imageproc — An image processing library, based on the image library.

imageproc

crates.io Build Status License

An image processing library, based on the image library. There may initially be overlap between the functions in this library and those in image::imageops.

This is very much a work in progress. If you have ideas for things that could be done better, or new features you'd like to see, then please create issues for them. Nothing's set in stone.

API documentation

Goals

A performant, well-tested, well-documented library with a consistent API, suitable for use as the basis of computer vision applications or graphics editors.

Non-goals

Maximum genericity over image storages or formats, or support for higher-dimensional images.

Full blown computer vision applications (e.g. face recognition or image registration) probably also belong elsewhere, but the line's a bit blurred here (e.g. is image in-painting an image processing task or a computer vision task?). However, worrying about how to structure the code can probably wait until we have more code to structure...

How to contribute

All pull requests are welcome. Some specific areas that would be great to get some help with are:

  • New features! If you're planning on adding some new functions or modules, please create an issue with a name along the lines of "Add [feature name]" and assign it to yourself (or comment on the issue that you're planning on doing it). This way we'll not have multiple people working on the same functionality.
  • Performance - profiling current code, documenting or fixing performance problems, adding benchmarks, comparisons to other libraries.
  • Testing - more unit tests and regression tests. Some more property-based testing would be particularly nice.
  • APIs - are the current APIs hard to use or inconsistent? Some open questions: Should we return Result types more often? How should functions indicate acceptable input image dimensions? Should we use enum arguments or have lots of similarly named functions? What's the best way to get concise code while still allowing control over allocations?
  • Documentation - particularly more example code showing what's currently possible. Pretty pictures in this README.
  • Feature requests - are there any functions you'd like to see added? Is the library currently unsuitable for your use case for some reason?

Comments

  • Random color palette utils for visual debugging/visualization purposes
    Random color palette utils for visual debugging/visualization purposes

    Jan 19, 2020

    Alright results are looking interesting I think Dy-b6Y3 Dy-b6Y3 debug

    Using this:

    pub fn preprocess(image: &DynamicImage) -> DynamicImage {
        // let image = image.resize_exact(700, 700, ::image::FilterType::Lanczos3);
        let image = image.to_luma();
        let image = imageproc::contrast::equalize_histogram(&image);
        let image = imageproc::filter::sharpen_gaussian(&image, 12.0, 38.0);
        let image = imageproc::region_labelling::connected_components(
            &image,
            Connectivity::Eight,
            Luma::black()
        );
        let image = color_palette::filter_luma_u32_regions(&image, 100);
        let image = image.to_pretty_rgb_palette();
        DynamicImage::ImageRgb8(image)
    }
    
    Reply
  • Add
    Add "Contour Following" (Simple)

    Feb 9, 2020

    Context: as part of my Biscuits project I had a need to extract the borders from a set of connected components. I used the "square tracing algorithm" + "Jacob's stopping criterion" as that was sufficient for my context; see https://github.com/mikemoraned/biscuits/commit/beb5bafad9e706124f38a45a146c34a12e33dcc7#diff-4dbdcb36de9736e49bb8d6d7a7f96736 . Here's the final code I refactored this to: https://github.com/mikemoraned/biscuits/tree/master/garibaldi/biscuiting-lib/src/border

    I now plan to rework this into a form that's not tied to my project and contribute into imageproc within the region_labelling module. I will aim to do this in a way which is extensible to other more complicated needs; the above algorithm only works for 4-connected regions.

    Reply
  • Support drawing oblique ellipse
    Support drawing oblique ellipse

    Feb 27, 2020

    For an ellipse with center (u, v), semi-axis (a, b), angle θ, the circum points can be calculated from parametric equation and 2D rotation:

    x = a cost cosθ - b sint sinθ + u
    y = a cost sinθ + b sint cosθ + v
    t ∈ [0, 2π)
    

    To draw elliptic arc, set t ∈ [start_angle, end_angle].

    Reply
  • getting a Projection by from_control_points makes program freezing
    getting a Projection by from_control_points makes program freezing

    Mar 22, 2020

    This occurs every time you run the program. Here is the minimal code.

    fn main() -> Result<(), Box<dyn Error>>{
        println!("get a projection from control points...");
        let from = [(0.0, 0.0), (250.0, 17.481735), (7.257017, 82.94814), (250.0, 104.18543)]; 
        let to = [(0.0, 0.0), (249.0, 0.0), (0.0, 105.0), (249.0, 105.0)];
        let projection = Projection::from_control_points(from, to);
        match projection {
            Some(_p) => println!("new projection"),
            None => println!("failed")
        }
        Ok(())
    }
    

    Here is all the output I get, nothing else: image I think Projection::from_control_points should either return Some(_) or None, rather than just keeps freezing. Thanks all the work you have done! This may be a bug, please someone check it.

    Reply
  • Rotation introduces black bars
    Rotation introduces black bars

    May 9, 2020

    The issue in #391 is also present in the cropping rotate function.

    Rotating a square by multiples of pi/2 about centre shouldn't have any pixels with a preimage outside the original square. But calling rotate_about_center introduces bars of 99s.

    I've added the following test

        fn test_rotate_half_pi_zero_square_about_center() {
            let image = gray_image!(
                00, 00, 00, 00;
                00, 00, 00, 00;
                00, 00, 00, 00;
                00, 00, 00, 00);
    
            let expected = gray_image!(
                00, 00, 00, 00;
                00, 00, 00, 00;
                00, 00, 00, 00;
                00, 00, 00, 00);
    
            let rotated = rotate_about_center(
                &image,
                std::f32::consts::PI / 2f32,
                Interpolation::Nearest,
                Luma([99u8]),
            );
            assert_pixels_eq!(rotated, expected);
        }
    

    which fails because a bar of 99s has been introduced.

    thread 'geometric_transformations::tests::test_rotate_half_pi_zero_square_about_center' panicked at 'pixels do not match.
    Actual:
           0   1   2 
       +-------------
       | 
      0|  99   0   0 
       | 
      1|  99   0   0 
       | 
      2|  99   0   0 
       | 
      3|  99   0   0 
       | 
    Expected:
          0  1  2 
       +----------
       | 
      0|  0  0  0 
       | 
      1|  0  0  0 
       | 
      2|  0  0  0 
       | 
      3|  0  0  0 
       | 
    ', src/geometric_transformations.rs:895:9
    

    Rotating by pi introduces bars in the top and side.

    Actual:
           0   1   2   3 
       +-----------------
       | 
      0|  99  99  99  99 
       | 
      1|  99   0   0   0 
       | 
      2|  99   0   0   0 
       | 
      3|  99   0   0   0 
       | 
    Expected:
          0  1  2  3 
       +-------------
       | 
      0|  0  0  0  0 
       | 
      1|  0  0  0  0 
       | 
      2|  0  0  0  0 
       | 
      3|  0  0  0  0 
       | 
    ', src/geometric_transformations.rs:895:9
    

    Similarly, rotating by 3pi/2 introduces a black bar at the top. Testing with non-zero squares shows that the result square is offset by one pixel.

    ---- geometric_transformations::tests::test_rotate_half_pi_square_about_center stdout ----
    thread 'geometric_transformations::tests::test_rotate_half_pi_square_about_center' panicked at 'pixels do not match.
    Actual:
           0   1   2   3 
       +-----------------
       | 
      0|  99  31  21  10 
       | 
      1|  99  32  22  11 
       | 
      2|  99  33  23  12 
       | 
      3|  99  34  25  14 
       | 
    Expected:
           0   1   2   3 
       +-----------------
       | 
      0|  31  21  10   0 
       | 
      1|  32  22  11   1 
       | 
      2|  33  23  12   2 
       | 
      3|  34  25  14   3 
       | 
    ', src/geometric_transformations.rs:899:9
    
    

    Some of these additional tests are there in this branch https://github.com/chocolatier/imageproc/commits/fix_rotate

    Reply
  • Switch from rulinalg to nalgebra for SVD
    Switch from rulinalg to nalgebra for SVD

    Jun 2, 2020

    Fixes #412

    This is working fine on a private project, but I don't know much about linear algebra and there aren't nearly enough test cases to ensure this doesn't break a bunch of stuff, so someone who's more knowledgeable should double check this.

    Reply
  • Fix circle drawing
    Fix circle drawing

    Jul 4, 2019

    Fixes #328

                                                                                                                                                                                                           
    Reply
  • Drawing TTF fonts/text
    Drawing TTF fonts/text

    Feb 4, 2017

    It would be interesting to look at ways to draw TTF fonts (or just any text) onto supported images. Let me know what you think!

    Take a look at https://github.com/dylanede/rusttype as well

    Reply
  • Add image tinting
    Add image tinting

    Jan 10, 2016

    @softprops was looking for something like ImageMagick's TintImage function: https://github.com/ImageMagick/ImageMagick/blob/master/MagickCore/fx.c.

    Visual effects seem like something that should eventually go in a separate crate, but for now it should be pretty easy to add a module containing some ImageMagick-y effects.

    Reply
  • Initial crate release
    Initial crate release

    Oct 11, 2015

    We don't have to make this polished, just less rough than the code is now.

    • ~~Try to reduce signature bloat a little. Unfortunately I think we're stuck with the I: 'static, I::Pixel: 'static, <I::Pixel as Pixel>::Subpixel: + 'static spam for now (but I'd be very happy to be shown wrong).~~
    • Check the TODOs for anything easily fixable.
    • Profile performance. I've still not looked at this, but I fear the performance is pretty woeful. If we're 2x slower than, say, OpenCV that's fine for now. If we're 100x slower not so much.
    • ~~Make the existing functions nicer to call, probably with a mix of functions taking loads of options and functions providing sensible defaults for some of those options that forward to the verbose ones.~~
    • ~~Stop spamming everything directly into master. I'll create a fork and move my future commits to go via pull requests.~~
    • ~~Set up continuous integration. Anyone want to help with this one?~~
    • ~~Better readme - give usage examples, and briefly discuss future plans and how to contribute.~~
    • ~~Add a license.~~
    • ~~Build on stable.~~
    Reply
  • Geometric Transformations Module
    Geometric Transformations Module

    Aug 13, 2019

    Added a module named proj that defines projective transformations, and means to construct, combine and apply them to images.

    The module exports warp* functions that allow performing projective transformations on images. Some of the functionality of this module overlaps with the affine module.

    It exports a type Proj that can be used to define projective transformations by

    • Constructing them from primitive transformations
    • From a given 3x3 projective matrix (in homogeneous coordinates)
    • Or from a set of 4 control point pairs (for this calculation I have added a new dependency rulinalg 0.4.2 - a linear algebra crate

    image dependency bumped to 0.22.1 and all functions deprecated in the image crate marked with #[allow_deprecated] to suppress warnings.

    Bumped the version of the imageproc crate. Don't know if this is common practice in additions like this one.

    Reply
  • Add support for drawing anti-aliased lines and thick lines.
    Add support for drawing anti-aliased lines and thick lines.

    Jan 10, 2016

    This might help: http://members.chello.at/~easyfilter/bresenham.html

    Reply