diff --git a/modules/imgproc/src/color.cpp b/modules/imgproc/src/color.cpp index 5196e13fb8..85fd3260ed 100644 --- a/modules/imgproc/src/color.cpp +++ b/modules/imgproc/src/color.cpp @@ -1344,6 +1344,9 @@ struct RGB2Lab_b }; +#define clip(value) \ + value < 0.0f ? 0.0f : value > 1.0f ? 1.0f : value; + struct RGB2Lab_f { typedef float channel_type; @@ -1355,17 +1358,22 @@ struct RGB2Lab_f volatile int _3 = 3; initLabTabs(); - if(!_coeffs) _coeffs = sRGB2XYZ_D65; - if(!_whitept) _whitept = D65; - float scale[] = { LabCbrtTabScale/_whitept[0], LabCbrtTabScale, LabCbrtTabScale/_whitept[2] }; + if (!_coeffs) + _coeffs = sRGB2XYZ_D65; + if (!_whitept) + _whitept = D65; + + float scale[] = { 1.0f / _whitept[0], 1.0f, 1.0f / _whitept[2] }; for( int i = 0; i < _3; i++ ) { - coeffs[i*3+(blueIdx^2)] = _coeffs[i*3]*scale[i]; - coeffs[i*3+1] = _coeffs[i*3+1]*scale[i]; - coeffs[i*3+blueIdx] = _coeffs[i*3+2]*scale[i]; - CV_Assert( coeffs[i*3] >= 0 && coeffs[i*3+1] >= 0 && coeffs[i*3+2] >= 0 && - coeffs[i*3] + coeffs[i*3+1] + coeffs[i*3+2] < 1.5f*LabCbrtTabScale ); + int j = i * 3; + coeffs[j + (blueIdx ^ 2)] = _coeffs[j] * scale[i]; + coeffs[j + 1] = _coeffs[j + 1] * scale[i]; + coeffs[j + blueIdx] = _coeffs[j + 2] * scale[i]; + + CV_Assert( coeffs[j] >= 0 && coeffs[j + 1] >= 0 && coeffs[j + 2] >= 0 && + coeffs[j] + coeffs[j + 1] + coeffs[j + 2] < 1.5f*LabCbrtTabScale ); } } @@ -1379,24 +1387,39 @@ struct RGB2Lab_f C6 = coeffs[6], C7 = coeffs[7], C8 = coeffs[8]; n *= 3; - for( i = 0; i < n; i += 3, src += scn ) + static const float _1_3 = 1.0 / 3.0; + static const double _a = 16.0 / 116; + for (i = 0; i < n; i += 3, src += scn ) { - float R = src[0], G = src[1], B = src[2]; - if( gammaTab ) + float R = clip(src[0]); + float G = clip(src[1]); + float B = clip(src[2]); + +// CV_Assert(R >= 0.0f && R <= 1.0f); +// CV_Assert(G >= 0.0f && G <= 1.0f); +// CV_Assert(B >= 0.0f && B <= 1.0f); + + if (gammaTab) { - R = splineInterpolate(R*gscale, gammaTab, GAMMA_TAB_SIZE); - G = splineInterpolate(G*gscale, gammaTab, GAMMA_TAB_SIZE); - B = splineInterpolate(B*gscale, gammaTab, GAMMA_TAB_SIZE); + R = splineInterpolate(R * gscale, gammaTab, GAMMA_TAB_SIZE); + G = splineInterpolate(G * gscale, gammaTab, GAMMA_TAB_SIZE); + B = splineInterpolate(B * gscale, gammaTab, GAMMA_TAB_SIZE); } - float fX = splineInterpolate(R*C0 + G*C1 + B*C2, LabCbrtTab, LAB_CBRT_TAB_SIZE); - float fY = splineInterpolate(R*C3 + G*C4 + B*C5, LabCbrtTab, LAB_CBRT_TAB_SIZE); - float fZ = splineInterpolate(R*C6 + G*C7 + B*C8, LabCbrtTab, LAB_CBRT_TAB_SIZE); - - float L = 116.f*fY - 16.f; - float a = 500.f*(fX - fY); - float b = 200.f*(fY - fZ); - - dst[i] = L; dst[i+1] = a; dst[i+2] = b; + float X = R*C0 + G*C1 + B*C2; + float Y = R*C3 + G*C4 + B*C5; + float Z = R*C6 + G*C7 + B*C8; + + float FX = X > 0.008856 ? pow(X, _1_3) : (7.787f * X + _a); + float FY = Y > 0.008856 ? pow(Y, _1_3) : (7.787f * Y + _a); + float FZ = Z > 0.008856 ? pow(Z, _1_3) : (7.787f * Z + _a); + + float L = Y > 0.008856 ? (116.f * FY - 16.f) : (903.3 * Y); + float a = 500.f * (FX - FY); + float b = 200.f * (FY - FZ); + + dst[i] = L; + dst[i + 1] = a; + dst[i + 2] = b; } } @@ -1404,21 +1427,22 @@ struct RGB2Lab_f float coeffs[9]; bool srgb; }; - - + struct Lab2RGB_f { typedef float channel_type; - + Lab2RGB_f( int _dstcn, int blueIdx, const float* _coeffs, - const float* _whitept, bool _srgb ) - : dstcn(_dstcn), srgb(_srgb) + const float* _whitept, bool _srgb ) + : dstcn(_dstcn), srgb(_srgb), blueInd(blueIdx) { initLabTabs(); - - if(!_coeffs) _coeffs = XYZ2sRGB_D65; - if(!_whitept) _whitept = D65; - + + if(!_coeffs) + _coeffs = XYZ2sRGB_D65; + if(!_whitept) + _whitept = D65; + for( int i = 0; i < 3; i++ ) { coeffs[i+(blueIdx^2)*3] = _coeffs[i]*_whitept[i]; @@ -1426,50 +1450,76 @@ struct Lab2RGB_f coeffs[i+blueIdx*3] = _coeffs[i+6]*_whitept[i]; } } - + void operator()(const float* src, float* dst, int n) const { int i, dcn = dstcn; const float* gammaTab = srgb ? sRGBInvGammaTab : 0; float gscale = GammaTabScale; float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], - C3 = coeffs[3], C4 = coeffs[4], C5 = coeffs[5], - C6 = coeffs[6], C7 = coeffs[7], C8 = coeffs[8]; + C3 = coeffs[3], C4 = coeffs[4], C5 = coeffs[5], + C6 = coeffs[6], C7 = coeffs[7], C8 = coeffs[8]; float alpha = ColorChannel::max(); n *= 3; - - for( i = 0; i < n; i += 3, dst += dcn ) + + static const float lThresh = 0.008856f * 903.3f; + static const float fThresh = 7.787f * 0.008856f + 16.0f / 116.0f; + for (i = 0; i < n; i += 3, dst += dcn) { - float L = src[i], a = src[i+1], b = src[i+2]; - float Y = (L + 16.f)*(1.f/116.f); - float X = (Y + a*0.002f); - float Z = (Y - b*0.005f); - Y = Y*Y*Y; - X = X*X*X; - Z = Z*Z*Z; - - float R = X*C0 + Y*C1 + Z*C2; - float G = X*C3 + Y*C4 + Z*C5; - float B = X*C6 + Y*C7 + Z*C8; - - if( gammaTab ) + float li = src[i]; + float ai = src[i + 1]; + float bi = src[i + 2]; + + float y, fy; + if (li <= lThresh) { - R = splineInterpolate(R*gscale, gammaTab, GAMMA_TAB_SIZE); - G = splineInterpolate(G*gscale, gammaTab, GAMMA_TAB_SIZE); - B = splineInterpolate(B*gscale, gammaTab, GAMMA_TAB_SIZE); + y = li / 903.3f; + fy = 7.787f * y + 16.0f / 116.0f; } - - dst[0] = R; dst[1] = G; dst[2] = B; + else + { + fy = (li + 16.0f) / 116.0f; + y = fy * fy * fy; + } + + float fxz[] = { ai / 500.0f + fy, fy - bi / 200.0f }; + + for (int j = 0; j < 2; j++) + if (fxz[j] <= fThresh) + fxz[j] = (fxz[j] - 16.0f / 116.0f) / 7.787f; + else + fxz[j] = fxz[j] * fxz[j] * fxz[j]; + + + float x = fxz[0], z = fxz[1]; + float ro = clip(C0 * x + C1 * y + C2 * z); + float go = clip(C3 * x + C4 * y + C5 * z); + float bo = clip(C6 * x + C7 * y + C8 * z); + +// CV_Assert(ro >= 0.0f && ro <= 1.0f); +// CV_Assert(go >= 0.0f && go <= 1.0f); +// CV_Assert(bo >= 0.0f && bo <= 1.0f); + + if (gammaTab) + { + ro = splineInterpolate(ro * gscale, gammaTab, GAMMA_TAB_SIZE); + go = splineInterpolate(go * gscale, gammaTab, GAMMA_TAB_SIZE); + bo = splineInterpolate(bo * gscale, gammaTab, GAMMA_TAB_SIZE); + } + + dst[0] = ro, dst[1] = go, dst[2] = bo; if( dcn == 4 ) dst[3] = alpha; } } - + int dstcn; float coeffs[9]; bool srgb; + int blueInd; }; - + +#undef clip struct Lab2RGB_b {