Image segmentation in OpenCV using Rust

Short post, just notes really. Been tinkering with image segmentation using opencv and the rust-bindings and specifically the hfs feature. Image Segmentation is creating regions in an image that somehow belong together, like the region of a bird in a bigger picture of two birds on a nest. See also here.

Installing opencv is easy, most of the time. Did have troubles on windows in the past, but at least on mac, it’s just brew install opencv

Next, working from rust is also easy using the opencv crate.

There was no hello-world type example for working with HFS in rust, (only c++), so here’s one:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
use opencv::{prelude::*, highgui};
use opencv::imgcodecs::{imread, IMREAD_COLOR};


fn main() -> anyhow::Result<()> {
    highgui::named_window("window", highgui::WINDOW_NORMAL)?;
    let img = imread("<PATH_TO_SOME_IMAGE>", IMREAD_COLOR)?;

    // setup HFS with parameters
    let mut obj = <dyn HfsSegment>::create(
        img.rows(), 
        img.cols(), 
        0.08, // seg_egb_threshold_i
        100,  // min_region_size_i
        0.28, // seg_egb_threshold_ii
        200,  // min_region_size_ii
        0.6,  // spatial_weight
        8,    // slic_spixel_size
        5     // num_slic_iter
    )?;
    // transform
    let out = obj.perform_segment_cpu(&img, true)?;

    highgui::imshow("window", &out)?;
    loop {
        let key = highgui::wait_key(1)?;
        if key == 27 {
            break;
        }
    }
    Ok(())
}

The <dyn HfsSegment>::create command is slightly odd, but HfsSegment is a trait and create is an associated function on it. The rest is pretty straighforward, if you know opencv.

The documentation is pretty short. I haven’t figured out what the parameters mean. But playing with them you will get different results.

Results:

input input output output

image from https://en.wikipedia.org/wiki/Image

NB. The authors state that you shouldn’t use perform_segment_cpu, but perform_segment_gpu instead, but that would require cuda. So use that if you are going to use it for real (because that is much faster, the cpu version does let you wait seconds (depending on image size/parameters of course)).