fixed cvtColor (RGB <-> Lab) tests and created another one

This commit is contained in:
Ilya Lavrenov 2012-10-15 12:22:36 +04:00
parent 5f9aedbe01
commit 2cda65a782

View File

@ -1009,93 +1009,105 @@ double CV_ColorLabTest::get_success_error_level( int /*test_case_idx*/, int i, i
static const double _1_3 = 0.333333333333; static const double _1_3 = 0.333333333333;
const static float _1_3f = static_cast<float>(_1_3);
void CV_ColorLabTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n )
void CV_ColorLabTest::convert_row_bgr2abc_32f_c3(const float* src_row, float* dst_row, int n)
{ {
int depth = test_mat[INPUT][0].depth(); int depth = test_mat[INPUT][0].depth();
float Lscale = depth == CV_8U ? 255.f/100.f : depth == CV_16U ? 65535.f/100.f : 1.f; float Lscale = depth == CV_8U ? 255.f/100.f : depth == CV_16U ? 65535.f/100.f : 1.f;
float ab_bias = depth == CV_8U ? 128.f : depth == CV_16U ? 32768.f : 0.f; float ab_bias = depth == CV_8U ? 128.f : depth == CV_16U ? 32768.f : 0.f;
int j;
float M[9]; float M[9];
for( j = 0; j < 9; j++ ) for (int j = 0; j < 9; j++ )
M[j] = (float)RGB2XYZ[j]; M[j] = (float)RGB2XYZ[j];
for( j = 0; j < n*3; j += 3 ) for (int x = 0; x < n*3; x += 3)
{ {
float r = src_row[j+2]; float R = src_row[x + 2];
float g = src_row[j+1]; float G = src_row[x + 1];
float b = src_row[j]; float B = src_row[x];
float X = (r*M[0] + g*M[1] + b*M[2])*(1.f/Xn); float X = (R * M[0] + G * M[1] + B * M[2]) / Xn;
float Y = r*M[3] + g*M[4] + b*M[5]; float Y = R * M[3] + G * M[4] + B * M[5];
float Z = (r*M[6] + g*M[7] + b*M[8])*(1.f/Zn); float Z = (R * M[6] + G * M[7] + B * M[8]) / Zn;
float fX, fY, fZ; float fX = X > 0.008856f ? pow(X, _1_3f) :
(7.787f * X + 16.f / 116.f);
float L, a; float fZ = Z > 0.008856f ? pow(Z, _1_3f):
(7.787f * Z + 16.f / 116.f);
if( Y > 0.008856 )
float L = 0.0f, fY = 0.0f;
if (Y > 0.008856f)
{ {
fY = (float)pow((double)Y,_1_3); fY = pow(Y, _1_3f);
L = 116.f*fY - 16.f; L = 116.f * fY - 16.f;
} }
else else
{ {
fY = 7.787f*Y + 16.f/116.f; fY = 7.787f * Y + 16.f / 116.f;
L = 903.3f*Y; L = 903.3f * Y;
} }
if( X > 0.008856 ) float a = 500.f * (fX - fY);
fX = (float)pow((double)X,_1_3); float b = 200.f * (fY - fZ);
else
fX = 7.787f*X + 16.f/116.f; dst_row[x] = L * Lscale;
dst_row[x + 1] = a + ab_bias;
if( Z > 0.008856 ) dst_row[x + 2] = b + ab_bias;
fZ = (float)pow((double)Z,_1_3);
else
fZ = 7.787f*Z + 16.f/116.f;
a = 500.f*(fX - fY);
b = 200.f*(fY - fZ);
dst_row[j] = L*Lscale;
dst_row[j+1] = a + ab_bias;
dst_row[j+2] = b + ab_bias;
} }
} }
void CV_ColorLabTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ) void CV_ColorLabTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n )
{ {
int depth = test_mat[INPUT][0].depth(); int depth = test_mat[INPUT][0].depth();
float Lscale = depth == CV_8U ? 100.f/255.f : depth == CV_16U ? 100.f/65535.f : 1.f; float Lscale = depth == CV_8U ? 100.f/255.f : depth == CV_16U ? 100.f/65535.f : 1.f;
float ab_bias = depth == CV_8U ? 128.f : depth == CV_16U ? 32768.f : 0.f; float ab_bias = depth == CV_8U ? 128.f : depth == CV_16U ? 32768.f : 0.f;
int j;
float M[9]; float M[9];
for( j = 0; j < 9; j++ ) for(int j = 0; j < 9; j++ )
M[j] = (float)XYZ2RGB[j]; M[j] = (float)XYZ2RGB[j];
for( j = 0; j < n*3; j += 3 ) static const float lthresh = 903.3f * 0.008856f;
static const float thresh = 7.787f * 0.008856f + 16.0f / 116.0f;
for (int x = 0, end = n * 3; x < end; x += 3)
{ {
float L = src_row[j]*Lscale; float L = src_row[x] * Lscale;
float a = src_row[j+1] - ab_bias; float a = src_row[x + 1] - ab_bias;
float b = src_row[j+2] - ab_bias; float b = src_row[x + 2] - ab_bias;
float P = (L + 16.f)*(1.f/116.f); float FY = 0.0f, Y = 0.0f;
float X = (P + a*0.002f); if (L <= lthresh)
float Z = (P - b*0.005f); {
float Y = P*P*P; Y = L / 903.3f;
X = Xn*X*X*X; FY = 7.787f * Y + 16.0f / 116.0f;
Z = Zn*Z*Z*Z; }
else
float r = M[0]*X + M[1]*Y + M[2]*Z; {
float g = M[3]*X + M[4]*Y + M[5]*Z; FY = (L + 16.0f) / 116.0f;
b = M[6]*X + M[7]*Y + M[8]*Z; Y = FY * FY * FY;
}
dst_row[j] = b;
dst_row[j+1] = g; float FX = a / 500.0f + FY;
dst_row[j+2] = r; float FZ = FY - b / 200.0f;
float FXZ[] = { FX, FZ };
for (int k = 0; k < 2; ++k)
{
if (FXZ[k] <= thresh)
FXZ[k] = (FXZ[k] - 16.0f / 116.0f) / 7.787f;
else
FXZ[k] = FXZ[k] * FXZ[k] * FXZ[k];
}
float X = FXZ[0] * Xn;
float Z = FXZ[1] * Zn;
float R = M[0] * X + M[1] * Y + M[2] * Z;
float G = M[3] * X + M[4] * Y + M[5] * Z;
float B = M[6] * X + M[7] * Y + M[8] * Z;
dst_row[x] = B;
dst_row[x + 1] = G;
dst_row[x + 2] = R;
} }
} }
@ -1869,3 +1881,98 @@ TEST(Imgproc_ColorBayerVNG_Strict, regression)
} }
} }
} }
void GetTestMatrix(Mat& src)
{
Size ssize(1000, 1000);
src.create(ssize, CV_32FC3);
int szm = ssize.width - 1;
float pi2 = 2 * 3.1415f;
// Generate a pretty test image
for (int i = 0; i < ssize.height; i++)
{
for (int j = 0; j < ssize.width; j++)
{
float b = (1 + cos((szm - i) * (szm - j) * pi2 / (10 * float(szm)))) / 2;
float g = (1 + cos((szm - i) * j * pi2 / (10 * float(szm)))) / 2;
float r = (1 + sin(i * j * pi2 / (10 * float(szm)))) / 2;
// The following lines aren't necessary, but just to prove that
// the BGR values all lie in [0,1]...
if (b < 0) b = 0; else if (b > 1) b = 1;
if (g < 0) g = 0; else if (g > 1) g = 1;
if (r < 0) r = 0; else if (r > 1) r = 1;
src.at<cv::Vec3f>(i, j) = cv::Vec3f(b, g, r);
}
}
}
void validate_result(const Mat& reference, const Mat& actual, const Mat& src = Mat(), int mode = -1)
{
cvtest::TS* ts = cvtest::TS::ptr();
Size ssize = reference.size();
int cn = reference.channels();
ssize.width *= cn;
bool next = true;
for (int y = 0; y < ssize.height && next; ++y)
{
const float* rD = reference.ptr<float>(y);
const float* D = actual.ptr<float>(y);
for (int x = 0; x < ssize.width && next; ++x)
if (fabs(rD[x] - D[x]) > 0.0001f)
{
next = false;
ts->printf(cvtest::TS::SUMMARY, "Error in: (%d, %d)\n", x / cn, y);
ts->printf(cvtest::TS::SUMMARY, "Reference value: %f\n", rD[x]);
ts->printf(cvtest::TS::SUMMARY, "Actual value: %f\n", D[x]);
if (!src.empty())
ts->printf(cvtest::TS::SUMMARY, "Src value: %f\n", src.ptr<float>(y)[x]);
ts->printf(cvtest::TS::SUMMARY, "Size: (%d, %d)\n", reference.rows, reference.cols);
if (mode >= 0)
{
cv::Mat lab;
cv::cvtColor(src, lab, mode);
std::cout << "lab: " << lab(cv::Rect(y, x / cn, 1, 1)) << std::endl;
}
std::cout << "src: " << src(cv::Rect(y, x / cn, 1, 1)) << std::endl;
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
ts->set_gtest_status();
}
}
}
TEST(Imgproc_ColorLab_Full, accuracy)
{
Mat src;
GetTestMatrix(src);
Mat reference(src.size(), CV_32FC3);
Size ssize = src.size();
CV_Assert(ssize.width == ssize.height);
RNG& rng = cvtest::TS::ptr()->get_rng();
int blueInd = rng.uniform(0., 1.) > 0.5 ? 0 : 2;
bool srgb = rng.uniform(0., 1.) > 0.5;
// Convert test image to LAB
cv::Mat lab;
int forward_code = blueInd ? srgb ? CV_BGR2Lab : CV_LBGR2Lab : srgb ? CV_RGB2Lab : CV_LRGB2Lab;
int inverse_code = blueInd ? srgb ? CV_Lab2BGR : CV_Lab2LBGR : srgb ? CV_Lab2RGB : CV_Lab2LRGB;
cv::cvtColor(src, lab, forward_code);
// Convert LAB image back to BGR(RGB)
cv::Mat recons;
cv::cvtColor(lab, recons, inverse_code);
validate_result(src, recons, src, forward_code);
// src *= 255.0f;
// recons *= 255.0f;
// imshow("Test", src);
// imshow("OpenCV", recons);
// waitKey();
}