fixed bug in cvtColor RGB(BGR) <-> Lab conversion

This commit is contained in:
Ilya Lavrenov 2012-10-15 12:21:16 +04:00
parent f9ac5e2404
commit 5f9aedbe01

View File

@ -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<float>::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
{