Skip to content
Advertisement

OpenCV different results on Windows and Linux

I’m writing a cross-platform wrapper for OpenCV on rust. And I wrote several tests to check that my wrapper is working correctly. Some tests are passing, some tests are failing with slightly different values, but one test has completely different results.

Right number is what I get on windows, left – on linux

---- compare_hist_chi_square stdout ----
    thread 'compare_hist_chi_square' panicked at '2697.981816285168 == 1360.7', tests/test_imgproc.rs:81:4
---- compare_hist_bhattacharyya stdout ----
    thread 'compare_hist_bhattacharyya' panicked at '0.6798259690477988 == 0.6679', tests/test_imgproc.rs:81:4
---- compare_hist_chi_square_alternative stdout ----
    thread 'compare_hist_chi_square_alternative' panicked at '41.65613074156445 == 41.027', tests/test_imgproc.rs:81:4
---- compare_hist_correlation stdout ----
    thread 'compare_hist_correlation' panicked at '0.20456957916644988 == 0.211', tests/test_imgproc.rs:81:4
---- compare_hist_intersection stdout ----
    thread 'compare_hist_intersection' panicked at '5.440850785933435 == 5.682', tests/test_imgproc.rs:81:4
---- compare_hist_kullback_leibler_divergence stdout ----
    thread 'compare_hist_kullback_leibler_divergence' panicked at '55.71912075710992 == 54.06287', tests/test_imgproc.rs:81:4

I tried to reproduce code from this article. I took same images and wanted to get same results. However, it didn’t happen.

Here is some Rust code that tests (just for reference):

extern crate cv;
extern crate float_cmp;
mod utils;

use cv::*;
use cv::imgproc::*;
use float_cmp::ApproxEqRatio;
use utils::*;

#[test]
#[should_panic]
fn compare_hist_different_dimensions_panic() {
    let first_image = load_unchanged("assets/Histogram_Comparison_Source_0.jpg");
    let second_image = load_unchanged("assets/Histogram_Comparison_Source_1.jpg");
    let _ = first_image.compare_hist(&second_image, HistogramComparisionMethod::Corellation).unwrap();
}

#[test]
fn compare_hist_correlation() {
    compare_hist(HistogramComparisionMethod::Corellation, 0.211);
}

#[test]
fn compare_hist_chi_square() {
    compare_hist(HistogramComparisionMethod::ChiSquare, 1360.7);
}

#[test]
fn compare_hist_intersection() {
    compare_hist(HistogramComparisionMethod::Intersection, 5.682);
}

#[test]
fn compare_hist_bhattacharyya() {
    compare_hist(HistogramComparisionMethod::Bhattacharyya, 0.6679);
}

#[test]
fn compare_hist_chi_square_alternative() {
    compare_hist(HistogramComparisionMethod::ChiSquareAlternative, 41.027);
}

#[test]
fn compare_hist_kullback_leibler_divergence() {
    compare_hist(
        HistogramComparisionMethod::KullbackLeiblerDivergence,
        54.06287,
    );
}

fn compare_hist(method: HistogramComparisionMethod, expected_result: f64) {
    let first_image = get_image_histogram("assets/Histogram_Comparison_Source_0.jpg");
    let second_image = get_image_histogram("assets/Histogram_Comparison_Source_1.jpg");
    let result = first_image.compare_hist(&second_image, method).unwrap();
    assert_eq(result, expected_result);
}

fn get_image_histogram(path: &'static str) -> Mat {
    let image = load_unchanged(path);
    let image = image.cvt_color(ColorConversionCodes::BGR2HSV);
    let hsize = [50, 60];
    let h_ranges = [0_f32, 180_f32];
    let s_ranges = [0_f32, 256_f32];
    let ranges = [
        h_ranges.as_ptr() as *const f32,
        s_ranges.as_ptr() as *const f32,
    ];
    let channels = [0, 1];
    let image = image.calc_hist(
        channels.as_ptr(),
        Mat::new(),
        2,
        hsize.as_ptr(),
        ranges.as_ptr(),
    );
    let image = image.normalize(0_f64, 1_f64, NormTypes::NormMinMax);
    image
}

fn assert_eq(a: f64, b: f64) {
    assert!(a.approx_eq_ratio(&b, 0.001), format!("{} == {}", a, b));
}

pub fn load_unchanged<P: AsRef<Path>>(img: P) -> Mat {
    let buf = load_image_as_buf(img);
    Mat::imdecode(&buf, ImreadModes::ImreadUnchanged)
}

fn load_image_as_buf<P: AsRef<Path>>(img: P) -> Vec<u8> {
    let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    d.push(img);
    let mut buf = Vec::new();
    File::open(d).unwrap().read_to_end(&mut buf).unwrap();
    buf
}

Probably it’s because of jpg and different jpg readers on different platforms, but it can’t explain 2697.98 vs 1360.7, it’s almost 2x difference!

What could be wrong here? Here is my entire pull request where I’m trying to add this functionality (careful, some Rust code is included)

Advertisement

Answer

Thanksto @VTT, this issue happens because of different jpg interpretation on different platforms. Switch to png solves the problem

Advertisement