Potential bug in cv::mean() for CV_32S?

Hello,

I am new to OpenCV and new to this forum so please go easy on me. :wink:

I have a test case that generates a faulty answer and wonder if there might be a bug in the cv::mean() method or if I am simply doing some newbie error.

Here is my test case:

int buffer[] = {
	-1951604497, -1576126781, -1048552445,   638096737,  374919884,  1849368146,
	 1201985774,  -716197524,   904658473,  -770415778,  583557857,   719101560,
	 -613502793,  -782012263,  -342082139,  1379255953, 1670949389,  1757926314,
	 -281705026,  1341462613, -1148159493, -1187220669,  563026587,   457255110,
	 -854231508,  -461342458,   320669161, -1938001093,  401558855, -1727039178,
	-1882661010, -1784502717,  -557639100, -2109135101, 1037216761,   662579286,
	 2044265374, -1276827335,   643791975,  1134686385,  567248739,   545889712 };

cv::Mat mat(6, 7, CV_32S, static_cast<void*>(buffer));
cv::Scalar mean = cv::mean(mat);

EXPECT_EQ(mean[0], -52606863.4047619);

The test reports -1.54868e+08 as the mean, which is quite far from the expected value (-5.26069e+07).

Could someone please either tell me what I am missing or confirm that cv::mean() indeed can compute wrong answers for CV_32S data.

If I convert the data to CV_64F before calling cv::mean() it produces the correct result (which could indicate internal overflow/underflow errors if OpenCV uses some low-bit integer representation in the accumulated sum but I could not mimic the behavior), but the documentation does not mention that you have to make this conversion.

This gives the correct result:

cv::Mat mat(6, 7, CV_32S, static_cast<void*>(buffer));
mat.convertTo(mat, CV_64F);     // <--- Need to convert input buffer to double
cv::Scalar mean = cv::mean(mat);

what version of OpenCV?
who compiled OpenCV?
what OS?
what platform/architecture?
what compiler?

taking your code, I can’t reproduce this. I get the expected result.

Thank you for taking your time with this. I think I could find at least some of the information needed.

OpenCV revision: 4cdb4652cfd5ed94a415dc8e161595edaea152b9
OpenCV version: 4.3.0 ("-pre"?)
OS/Platform: Windows 10 Pro (Version 10.0.19042 Build 19042)
Compiler: MSVC(?)

OpenCV was compiled from code to a static library. Here is a part of the build script that shows parameters used in the build.

...
buildstatic=True

for config in ['Debug','Release']:
    builddir=os.path.join(sys.path[0],'build-static' if buildstatic else 'build',config)

    print("will build in {}".format(builddir))

    args=[cmake,'-S',srcdir,'-B',builddir]
    args.append('-DBUILD_SHARED_LIBS=OFF')
    args.append('-DBUILD_WITH_STATIC_CRT=OFF')

    for dontbuildstuff in ('DOCS','EXAMPLES','JAVA','opencv_python'):
         args.append("-DBUILD_" + dontbuildstuff + "=Off")

    for shouldbeon in ('ENABLE_PRECOMPILED_HEADERS','CV_ENABLE_INTRINSICS'):
         args.append("-D" + shouldbeon + "=On")

    for notwith in ('tbb','qt','gtk','win32ui','ffmpeg','msmf','msmf_dxva','directx','protobuf'):
         args.append("-DWITH_" + notwith.upper() + "=Off")
    for yeswith in ('opencl',):
         args.append("-DWITH_" + yeswith.upper() + "=On")

    args.append("-DBUILD_LIST=core,imgproc")

    # simd dispatch, this may be wrong, disabling sse4.2 and avx for algorithms that
    # have no avx2 implementation
    args.append("-DCPU_BASELINE=AVX2")
    args.append("-DCPU_BASELINE_REQUIRE=AVX2")
    args.append("-DCPU_DISPATCH=AVX2")

    print( '"' + '" "'.join(args) + '"')

    #configure
    ans=subprocess.run(args,capture_output=True,encoding='utf-8',check=True)
    #print(ans)

    #compile
    ans=subprocess.run([cmake,'--build',builddir,'--config',config,'--target','install'],encoding='utf-8',check=True)

Let me know if there is anything else that might help getting to the bottom of this.

okay so “regular” environment (x64, right? Visual Studio 2015/2017/2019, right?), nothing funky, with a somewhat old version of OpenCV.

4cdb4652cfd5ed94a415dc8e161595edaea152b9 is from Mar 20, 2020.

it is universally true that bug reports should be reproducible on the latest version, or as close as possible. why? because the bug could have been fixed since that time.

so I would recommend that you reproduce this on the latest release or on the master branch.

I was unable to reproduce this on my build of 4.5.2. if you can reproduce on 4.5.2, that would exclude OpenCV’s source as the cause of the different behavior.

I would also recommend not using your build script there. build as regularly as possible. that also means not building statically. OpenCV is meant to be used as a dynamic library.

you might also want to try a binary release, something you haven’t built yourself. maybe something in your build environment caused this.

here is the complete code I used to try to reproduce your issue. make sure you use the same code, or show me your complete code.

#include <iostream>
#include <opencv2/core.hpp>

using namespace std;

int main()
{
	int buffer[] = {
	-1951604497, -1576126781, -1048552445,   638096737,  374919884,  1849368146,
	 1201985774,  -716197524,   904658473,  -770415778,  583557857,   719101560,
	 -613502793,  -782012263,  -342082139,  1379255953, 1670949389,  1757926314,
	 -281705026,  1341462613, -1148159493, -1187220669,  563026587,   457255110,
	 -854231508,  -461342458,   320669161, -1938001093,  401558855, -1727039178,
	-1882661010, -1784502717,  -557639100, -2109135101, 1037216761,   662579286,
	 2044265374, -1276827335,   643791975,  1134686385,  567248739,   545889712 };

	cv::Mat mat(6, 7, CV_32S, static_cast<void*>(buffer));
	cv::Scalar mean = cv::mean(mat);

	cout << mean[0] << " actual" << endl;
	cout << -52606863.4047619 << " expected" << endl;

	return 0;
}

Yes, a “regular” environment with x64 and VS2019 on a Dell Precision 5530 laptop.

I will update to the latest version and see if the error persists. But it sounds like it might fix the issue. I will report back in this thread about any new findings.

Thank you so much for your input.

Hello again,

Now I have examined this a bit further.

  1. I downloaded the 4.5.2 sources and compiled it to a dynamic library using the cmake gui app (I followed point (7) under Building the library from here: OpenCV: Installation in Windows but only built the core and imgproc dlls). I then created a fresh Solution in Visual Studio with a single C++ project and used your code, but I still got the wrong result from cv::mean() (-1.54868e+08).

  2. I downloaded the pre-built 4.5.2 dlls from here: Download OpenCV from SourceForge.net and updated the C++ project I created in step (1) to use that dll (opencv_world452d.lib in vc15/) but I still get the wrong result from cv::mean() (-1.54868e+08).

So it sounds unlikely that the error comes from the build environment (or the OpenCV source since your build does not reproduce the error).

1 Like

good effort !
are you able to debug it, to see, which code path / optimization is taken inside cv::mean ?

and, btw, same problem with cv::meanStdDev() ?

Thanks,

Being a bit of a newbie on C++ development I am unsure how to setup the development environment so I can follow the internal execution path within cv::mean.

When I try cv::meanStdDev() it gives the correct result, so no, I don’t have the same problem with cv::meanStdDev().

1 Like

the parallel backends can be controlled. see if you can force one thread: cv::setNumThreads.

maybe that does something. I think there’s some mechanism to disable specific backends at runtime. if there is, it should be in the docs… I can’t find anything like that right now, so maybe there isn’t.

you should also see about disabling runtime dispatch of instruction sets. stick with SSE2 or whatever’s the baseline. this might, at most, require a rebuild with different cmake variables.

it is possible that the bug is in OpenCV’s source, but the buggy code path is used in your situation and not in mine.

I have just reported a similar issue with meanStdDev, see meanStdDev bug while RUN_TESTS for opencv_test_core ¡ Issue #22698 ¡ opencv/opencv ¡ GitHub. I compiled OpenCV 4.6.0 with contrib, and RUN_TESTS gives me an error in meanStdDev.
As shown in the URL above, I added v2 and v3 variables in core\src\mean_simd.hpp, and it works fine. But it does not make sense.
I agree with @crackwitz that maybe something is wrong with the parallel backends, but I am not an expert of it. Should I shut down something like AVX2?