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

median_filter is two orders of magnitude slower than opencv::imgproc::median_blur. #530

Open
wangm23456 opened this issue Jun 7, 2023 · 3 comments

Comments

@wangm23456
Copy link

#[cfg(test)]
mod tests{
    use std::{path::PathBuf, time::SystemTime};

    use cv::{imgcodecs::IMREAD_GRAYSCALE, core::CV_8UC1};
    use image::{DynamicImage, GrayImage, buffer::ConvertBuffer};
    use opencv as cv;
    use opencv::prelude::*;
    use tiff::decoder::{Decoder, ifd};
    use imageproc::filter;

    #[test]
    fn test_image(){
        let path = "a.tiff".to_string();
        let pathbuf = PathBuf::from(path);
        let img = image::open(pathbuf).unwrap();
        let img = img.as_luma16().unwrap();
        let img: GrayImage = img.convert();
        let t0 = SystemTime::now();
        let img_median = filter::median_filter(&img, 7, 7);
        let t1 = SystemTime::now();
        println!("{:?}", img_median.dimensions());
        println!(
            "time: {}s",
            t1.duration_since(t0).unwrap().as_millis() as f64 / 1000.
        );
    }
    #[test]
    fn test_opencv(){
        let path = "a.tiff";
        let img = cv::imgcodecs::imread(path, cv::imgcodecs::IMREAD_GRAYSCALE).unwrap();
        let mut img_8 = Mat::default();
        img.convert_to(&mut img_8, CV_8UC1, 1.0/255.0, 0.0).unwrap();
        let t0 = SystemTime::now();
        let mut img_median = Mat::default();
        cv::imgproc::median_blur(&img, &mut img_median, 7).unwrap();
        let t1 = SystemTime::now();
        println!("{:?}", img_median.size());
        println!(
            "time: {}s",
            t1.duration_since(t0).unwrap().as_millis() as f64 / 1000.
        );
    }
}
Ok(Size_ { width: 9720, height: 11340 })
time: 0.924s
test tests::test_opencv ... ok

(9720, 11340)
time: 216.174s
test tests::test_image ... ok
@cospectrum
Copy link
Contributor

The first thing to check is whether opencv is using the GPU in this case or not.

@theotherphil
Copy link
Contributor

OpenCV may well be doing something smarter, but one difference here is that you're using a 7x7 filter for OpenCV and a 15x15 filter for imageproc. OpenCV takes a width parameter that it requires to be odd, whereas imageproc takes a radius parameter and uses a filter of size 2*radius + 1 to ensure it's always odd. This is possibly a confusing API!

@theotherphil
Copy link
Contributor

theotherphil commented Apr 28, 2024

Having reminded myself of what the code does, the imageproc implementation is linear in kernel width so your accidental difference in parameters shouldn't account for much of the difference between the two libraries!

Quick empirical sanity check for this:

use std::time::SystemTime;
use image::{GrayImage, Luma};
use imageproc::filter::median_filter;

fn main() {
    let image = GrayImage::from_fn(9720, 11340, |_, _| Luma([7]));
    
    let t0 = SystemTime::now();
    let _f1 = median_filter(&image, 3, 3);
    let t1 = SystemTime::now();
    let _f2 = median_filter(&image, 7, 7);
    let t2 = SystemTime::now();
    
    println!("{:?}", t1.duration_since(t0));
    println!("{:?}", t2.duration_since(t1));
}

Ok(3.232656s)
Ok(6.872397s)

That's still slower than your OpenCV run time, but far faster than your imageproc run time. I suspect you might be running your code in debug mode and so comparing a debug build of imageproc against a release build of OpenCV.

From a quick glance at the source code for OpenCV's implementation, it looks to be doing something roughly similar to what we do in imageproc, but with SIMD acceleration. I wouldn't be too surprised by a 5-10x difference in run time, but 200x looks wrong.

@wangm23456 can you check if you're running imageproc in debug or release mode.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants