RGB2Gray ushort specialization not defined for SSE2 && !SSE4_1 (Bug #4460)


Added by Fraser Cormack over 9 years ago. Updated over 9 years ago.


Status:Done Start date:2015-07-03
Priority:Normal Due date:
Assignee:- % Done:

100%

Category:imgproc, video
Target version:3.0
Affected version:branch 'master' (3.0-dev) Operating System:Linux
Difficulty: HW Platform:x86
Pull request:https://github.com/Itseez/opencv/pull/4193

Description

I was getting a test failure running the OCL_ImgProc/CvtColor.BGRA2GRAY/3 unit test. The results were different between X86 and OpenCL on device.

I found out that it's because the kernel was doing this in the RGB2Gray kernel (modules/imgproc/src/opencl/cvtcolor.cl:156):

  dst[0] = (DATA_TYPE)CV_DESCALE(mad24(src_pix.B_COMP, B2Y, mad24(src_pix.G_COMP, G2Y, mul24(src_pix.R_COMP, R2Y))), yuv_shift);

whereas on host it was doing this in the default RGB2Gray templated struct (modules/imgproc/src/color.cpp:1269)

  dst[i] = saturate_cast<_Tp>(src[0]*cb + src[1]*cg + src[2]*cr);

This means the host is doing floating-point arithmetic and comparing it against integer (short) arithmetic on the device. Due to floating-point rounding, 61.4444...9 was being rounded to 61.5 and then to 62 in the call to saturate_cast. The device's integer arithmetic produced 61.

I then found that there's a suitable-looking RGB2Gray ushort specialization further down in @modules/imgproc/src/color.cpp:1679:

template<> struct RGB2Gray<ushort>
{
    typedef ushort channel_type;

    RGB2Gray(int _srccn, int blueIdx, const int* _coeffs) : srccn(_srccn)
    {
        static const int coeffs0[] = { R2Y, G2Y, B2Y };
        memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 3*sizeof(coeffs[0]));
        if( blueIdx == 0 )
            std::swap(coeffs[0], coeffs[2]);
    }

    void operator()(const ushort* src, ushort* dst, int n) const
    {
        int scn = srccn, cb = coeffs[0], cg = coeffs[1], cr = coeffs[2];
        for(int i = 0; i < n; i++, src += scn)
            dst[i] = (ushort)CV_DESCALE((unsigned)(src[0]*cb + src[1]*cg + src[2]*cr), yuv_shift);
    }
    int srccn;
    int coeffs[3];
};

I bet if this was used then the test wouldn't fail. The problem is that my X86 machine has SSE2 but not SSE4, so some preprocessor guards further up in that file prevent this from being defined.

It's something like this:

#if CV_NEON
template<> struct RGB2Gray<ushort> ...
#elif CV_SSE2
  #if CV_SSE4_1
    template<> struct RGB2Gray<ushort> ...
  #endif
#else
template<> struct RGB2Gray<ushort> ...
#endif

Shouldn't this last ushort specialization be declared in all cases, as a fall-back?

This might also apply to other colour conversion helpers in that same file: I haven't checked.


History

Updated by Philip L over 9 years ago

yes your assumption is correct, checking this...

  • Status changed from New to Open

Updated by Philip L over 9 years ago

created PR for this
https://github.com/Itseez/opencv/pull/4180

btw. i checked other branches and this seems to be the only one were this was wrong atleast for the color.cpp.
If you find more of such errors pleases report.

  • % Done changed from 0 to 100

Updated by Alexander Alekhin over 9 years ago

  • Pull request set to https://github.com/Itseez/opencv/pull/4193
  • Status changed from Open to Done

Updated by Fraser Cormack over 9 years ago

Thanks, this fixes the issue I was seeing!

Also available in: Atom PDF