Loading modules/xphoto/src/simple_color_balance.cpp +35 −54 Original line number Diff line number Diff line Loading @@ -39,7 +39,6 @@ #include <algorithm> #include <iostream> #include <iterator> #include <vector> #include "opencv2/core.hpp" Loading @@ -59,74 +58,56 @@ void balanceWhiteSimple(std::vector<Mat_<T> > &src, Mat &dst, const float inputM const float s1 = p; // low quantile const float s2 = p; // high quantile int depth = 2; // depth of histogram tree if (src[0].depth() != CV_8U) ++depth; int bins = 16; // number of bins at each histogram level int nElements = src[0].depth() == CV_8U ? 256 : 4096; int nElements = int(pow((float)bins, (float)depth)); // number of elements in histogram tree float minValue0 = inputMin; float maxValue0 = inputMax; for (size_t i = 0; i < src.size(); ++i) // deal with cv::calcHist (exclusive upper bound) if (src[0].depth() == CV_32F || src[0].depth() == CV_64F) // floating { std::vector<int> hist(nElements, 0); typename Mat_<T>::iterator beginIt = src[i].begin(); typename Mat_<T>::iterator endIt = src[i].end(); for (typename Mat_<T>::iterator it = beginIt; it != endIt; ++it) // histogram filling maxValue0 += MIN((inputMax - inputMin) / (nElements - 1), 1); if (inputMax == inputMin) // single value maxValue0 += 1; } else // integer { int pos = 0; float minValue = inputMin - 0.5f; float maxValue = inputMax + 0.5f; T val = *it; maxValue0 += 1; } float interval = float(maxValue - minValue) / bins; float interval = (maxValue0 - minValue0) / float(nElements); for (int j = 0; j < depth; ++j) for (size_t i = 0; i < src.size(); ++i) { int currentBin = int((val - minValue + 1e-4f) / interval); ++hist[pos + currentBin]; pos = (pos + currentBin) * bins; float minValue = minValue0; float maxValue = maxValue0; minValue = minValue + currentBin * interval; maxValue = minValue + interval; Mat img = src[i].reshape(1); Mat hist; int channels[] = {0}; int histSize[] = {nElements}; float inputRange[] = {minValue, maxValue}; const float *ranges[] = {inputRange}; interval /= bins; } } calcHist(&img, 1, channels, Mat(), hist, 1, histSize, ranges, true, false); int total = int(src[i].total()); int p1 = 0, p2 = bins - 1; int p1 = 0, p2 = nElements - 1; int n1 = 0, n2 = total; float minValue = inputMin - 0.5f; float maxValue = inputMax + 0.5f; float interval = (maxValue - minValue) / float(bins); for (int j = 0; j < depth; ++j) // searching for s1 and s2 while (n1 + hist.at<float>(p1) < s1 * total / 100.0f) { while (n1 + hist[p1] < s1 * total / 100.0f) { n1 += hist[p1++]; n1 += saturate_cast<int>(hist.at<float>(p1++)); minValue += interval; } p1 *= bins; while (n2 - hist[p2] > (100.0f - s2) * total / 100.0f) while (n2 - hist.at<float>(p2) > (100.0f - s2) * total / 100.0f) { n2 -= hist[p2--]; n2 -= saturate_cast<int>(hist.at<float>(p2--)); maxValue -= interval; } p2 = (p2 + 1) * bins - 1; interval /= bins; } src[i] = (outputMax - outputMin) * (src[i] - minValue) / (maxValue - minValue) + outputMin; } Loading modules/xphoto/test/simple_color_balance.cpp +232 −18 Original line number Diff line number Diff line Loading @@ -5,33 +5,140 @@ namespace opencv_test { namespace { TEST(xphoto_simplecolorbalance, regression) TEST(xphoto_simplecolorbalance, uchar_max_value) { cv::String dir = cvtest::TS::ptr()->get_data_path() + "cv/xphoto/simple_white_balance/"; int nTests = 8; cv::Ptr<cv::xphoto::WhiteBalancer> wb = cv::xphoto::createSimpleWB(); const uchar oldMax = 120, newMax = 255; for (int i = 0; i < nTests; ++i) Mat test = Mat::zeros(3,3,CV_8UC1); test.at<uchar>(0, 0) = oldMax; test.at<uchar>(0, 1) = oldMax / 2; test.at<uchar>(0, 2) = oldMax / 4; cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB(); wb->setInputMin(0); wb->setInputMax(oldMax); wb->setOutputMin(0); wb->setOutputMax(newMax); wb->balanceWhite(test, test); double minDst, maxDst; cv::minMaxIdx(test, &minDst, &maxDst); ASSERT_NEAR(maxDst, newMax, 1e-4); } TEST(xphoto_simplecolorbalance, uchar_min_value) { const uchar oldMin = 120, newMin = 0; Mat test = Mat::zeros(1,3,CV_8UC1); test.at<uchar>(0, 0) = oldMin; test.at<uchar>(0, 1) = (256 + oldMin) / 2; test.at<uchar>(0, 2) = 255; cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB(); wb->setInputMin(oldMin); wb->setInputMax(255); wb->setOutputMin(newMin); wb->setOutputMax(255); wb->balanceWhite(test, test); double minDst, maxDst; cv::minMaxIdx(test, &minDst, &maxDst); ASSERT_NEAR(minDst, newMin, 1e-4); } TEST(xphoto_simplecolorbalance, uchar_equal_range) { cv::String srcName = dir + cv::format( "sources/%02d.png", i + 1); cv::Mat src = cv::imread( srcName, 1 ); ASSERT_TRUE(!src.empty()); const int N = 4; uchar data[N] = {0, 1, 16, 255}; Mat test = Mat(1, N, CV_8UC1, data); Mat result = Mat(1, N, CV_8UC1, data); cv::String previousResultName = dir + cv::format( "results/%02d.jpg", i + 1 ); cv::Mat previousResult = cv::imread( previousResultName, 1 ); cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB(); wb->setInputMin(0); wb->setInputMax(255); wb->setOutputMin(0); wb->setOutputMax(255); wb->balanceWhite(test, test); double err; cv::minMaxIdx(cv::abs(test - result), NULL, &err); ASSERT_LE(err, 1e-4); } cv::Mat currentResult; wb->balanceWhite(src, currentResult); TEST(xphoto_simplecolorbalance, uchar_single_value) { const int N = 4; uchar data0[N] = {51, 51, 51, 51}; uchar data1[N] = {33, 33, 33, 33}; Mat test = Mat(1, N, CV_8UC1, data0); Mat result = Mat(1, N, CV_8UC1, data1); cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB(); wb->setInputMin(51); wb->setInputMax(51); wb->setOutputMin(33); wb->setOutputMax(200); double psnr = cv::PSNR(currentResult, previousResult); wb->balanceWhite(test, test); EXPECT_GE( psnr, 30 ); double err; cv::minMaxIdx(cv::abs(test - result), NULL, &err); ASSERT_LE(err, 1e-4); } TEST(xphoto_simplecolorbalance, uchar_p) { const int N = 5; uchar data0[N] = {10, 55, 102, 188, 233}; uchar data1[N] = {0, 1, 90, 254, 255}; Mat test = Mat(1, N, CV_8UC1, data0); Mat result = Mat(1, N, CV_8UC1, data1); cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB(); wb->setInputMin(10); wb->setInputMax(233); wb->setOutputMin(0); wb->setOutputMax(255); wb->setP(21); wb->balanceWhite(test, test); double err; cv::minMaxIdx(cv::abs(test - result), NULL, &err); ASSERT_LE(err, 1e-4); } TEST(xphoto_simplecolorbalance, max_value) TEST(xphoto_simplecolorbalance, uchar_c3) { const float oldMax = 24000., newMax = 65536.; const int N = 15; uchar data0[N] = {10, 55, 102, 55, 102, 188, 102, 188, 233, 188, 233, 10, 233, 10, 55}; uchar data1[N] = {0, 1, 90, 1, 90, 254, 90, 254, 255, 254, 255, 0, 255, 0, 1}; Mat test = Mat(1, N / 3, CV_8UC3, data0); Mat result = Mat(1, N / 3, CV_8UC3, data1); cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB(); wb->setInputMin(10); wb->setInputMax(233); wb->setOutputMin(0); wb->setOutputMax(255); wb->setP(21); wb->balanceWhite(test, test); double err; cv::minMaxIdx(cv::abs(test - result), NULL, &err); ASSERT_LE(err, 1e-4); } TEST(xphoto_simplecolorbalance, float_max_value) { const float oldMax = 24000.f, newMax = 65536.f; Mat test = Mat::zeros(3,3,CV_32FC1); test.at<float>(0, 0) = oldMax; Loading @@ -55,5 +162,112 @@ namespace opencv_test { namespace { ASSERT_NEAR(maxDst, newMax, newMax*1e-4); } TEST(xphoto_simplecolorbalance, float_min_value) { const float oldMin = 24000.f, newMin = 0.f; Mat test = Mat::zeros(1,3,CV_32FC1); test.at<float>(0, 0) = oldMin; test.at<float>(0, 1) = (65536.f + oldMin) / 2; test.at<float>(0, 2) = 65536.f; cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB(); wb->setInputMin(oldMin); wb->setInputMax(65536.f); wb->setOutputMin(newMin); wb->setOutputMax(65536.f); wb->balanceWhite(test, test); double minDst, maxDst; cv::minMaxIdx(test, &minDst, &maxDst); ASSERT_NEAR(minDst, newMin, 65536*1e-4); } TEST(xphoto_simplecolorbalance, float_equal_range) { const int N = 5; float data[N] = {0.f, 1.f, 16.2f, 256.3f, 4096.f}; Mat test = Mat(1, N, CV_32FC1, data); Mat result = Mat(1, N, CV_32FC1, data); cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB(); wb->setInputMin(0); wb->setInputMax(4096); wb->setOutputMin(0); wb->setOutputMax(4096); wb->balanceWhite(test, test); double err; cv::minMaxIdx(cv::abs(test - result), NULL, &err); ASSERT_LE(err, 1e-4); } TEST(xphoto_simplecolorbalance, float_single_value) { const int N = 4; float data0[N] = {24000.5f, 24000.5f, 24000.5f, 24000.5f}; float data1[N] = {52000.25f, 52000.25f, 52000.25f, 52000.25f}; Mat test = Mat(1, N, CV_32FC1, data0); Mat result = Mat(1, N, CV_32FC1, data1); cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB(); wb->setInputMin(24000.5f); wb->setInputMax(24000.5f); wb->setOutputMin(52000.25f); wb->setOutputMax(65536.f); wb->balanceWhite(test, test); double err; cv::minMaxIdx(cv::abs(test - result), NULL, &err); ASSERT_LE(err, 65536*1e-4); } TEST(xphoto_simplecolorbalance, float_p) { const int N = 5; float data0[N] = {16000.f, 20000.5f, 24000.f, 36000.5f, 48000.f}; float data1[N] = {-16381.952f, 0.f, 16381.952f, 65536.f, 114685.952f}; Mat test = Mat(1, N, CV_32FC1, data0); Mat result = Mat(1, N, CV_32FC1, data1); cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB(); wb->setInputMin(16000.f); wb->setInputMax(48000.f); wb->setOutputMin(0.f); wb->setOutputMax(65536.f); wb->setP(21); wb->balanceWhite(test, test); double err; cv::minMaxIdx(cv::abs(test - result), NULL, &err); ASSERT_LE(err, 65536*1e-4); } TEST(xphoto_simplecolorbalance, float_c3) { const int N = 15; float data0[N] = {16000.f, 20000.5f, 24000.f, 20000.5f, 24000.f, 36000.5f, 24000.f, 36000.5f, 48000.f, 36000.5f, 48000.f, 16000.f, 48000.f, 16000.f, 20000.5f}; float data1[N] = {-16381.952f, 0.f, 16381.952f, 0.f, 16381.952f, 65536.f, 16381.952f, 65536.f, 114685.952f, 65536.f, 114685.952f, -16381.952f, 114685.952f, -16381.952f, 0.f}; Mat test = Mat(1, N / 3, CV_32FC3, data0); Mat result = Mat(1, N / 3, CV_32FC3, data1); cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB(); wb->setInputMin(16000.f); wb->setInputMax(48000.f); wb->setOutputMin(0.f); wb->setOutputMax(65536.f); wb->setP(21); wb->balanceWhite(test, test); double err; cv::minMaxIdx(cv::abs(test - result), NULL, &err); ASSERT_LE(err, 65536*1e-4); } }} // namespace Loading
modules/xphoto/src/simple_color_balance.cpp +35 −54 Original line number Diff line number Diff line Loading @@ -39,7 +39,6 @@ #include <algorithm> #include <iostream> #include <iterator> #include <vector> #include "opencv2/core.hpp" Loading @@ -59,74 +58,56 @@ void balanceWhiteSimple(std::vector<Mat_<T> > &src, Mat &dst, const float inputM const float s1 = p; // low quantile const float s2 = p; // high quantile int depth = 2; // depth of histogram tree if (src[0].depth() != CV_8U) ++depth; int bins = 16; // number of bins at each histogram level int nElements = src[0].depth() == CV_8U ? 256 : 4096; int nElements = int(pow((float)bins, (float)depth)); // number of elements in histogram tree float minValue0 = inputMin; float maxValue0 = inputMax; for (size_t i = 0; i < src.size(); ++i) // deal with cv::calcHist (exclusive upper bound) if (src[0].depth() == CV_32F || src[0].depth() == CV_64F) // floating { std::vector<int> hist(nElements, 0); typename Mat_<T>::iterator beginIt = src[i].begin(); typename Mat_<T>::iterator endIt = src[i].end(); for (typename Mat_<T>::iterator it = beginIt; it != endIt; ++it) // histogram filling maxValue0 += MIN((inputMax - inputMin) / (nElements - 1), 1); if (inputMax == inputMin) // single value maxValue0 += 1; } else // integer { int pos = 0; float minValue = inputMin - 0.5f; float maxValue = inputMax + 0.5f; T val = *it; maxValue0 += 1; } float interval = float(maxValue - minValue) / bins; float interval = (maxValue0 - minValue0) / float(nElements); for (int j = 0; j < depth; ++j) for (size_t i = 0; i < src.size(); ++i) { int currentBin = int((val - minValue + 1e-4f) / interval); ++hist[pos + currentBin]; pos = (pos + currentBin) * bins; float minValue = minValue0; float maxValue = maxValue0; minValue = minValue + currentBin * interval; maxValue = minValue + interval; Mat img = src[i].reshape(1); Mat hist; int channels[] = {0}; int histSize[] = {nElements}; float inputRange[] = {minValue, maxValue}; const float *ranges[] = {inputRange}; interval /= bins; } } calcHist(&img, 1, channels, Mat(), hist, 1, histSize, ranges, true, false); int total = int(src[i].total()); int p1 = 0, p2 = bins - 1; int p1 = 0, p2 = nElements - 1; int n1 = 0, n2 = total; float minValue = inputMin - 0.5f; float maxValue = inputMax + 0.5f; float interval = (maxValue - minValue) / float(bins); for (int j = 0; j < depth; ++j) // searching for s1 and s2 while (n1 + hist.at<float>(p1) < s1 * total / 100.0f) { while (n1 + hist[p1] < s1 * total / 100.0f) { n1 += hist[p1++]; n1 += saturate_cast<int>(hist.at<float>(p1++)); minValue += interval; } p1 *= bins; while (n2 - hist[p2] > (100.0f - s2) * total / 100.0f) while (n2 - hist.at<float>(p2) > (100.0f - s2) * total / 100.0f) { n2 -= hist[p2--]; n2 -= saturate_cast<int>(hist.at<float>(p2--)); maxValue -= interval; } p2 = (p2 + 1) * bins - 1; interval /= bins; } src[i] = (outputMax - outputMin) * (src[i] - minValue) / (maxValue - minValue) + outputMin; } Loading
modules/xphoto/test/simple_color_balance.cpp +232 −18 Original line number Diff line number Diff line Loading @@ -5,33 +5,140 @@ namespace opencv_test { namespace { TEST(xphoto_simplecolorbalance, regression) TEST(xphoto_simplecolorbalance, uchar_max_value) { cv::String dir = cvtest::TS::ptr()->get_data_path() + "cv/xphoto/simple_white_balance/"; int nTests = 8; cv::Ptr<cv::xphoto::WhiteBalancer> wb = cv::xphoto::createSimpleWB(); const uchar oldMax = 120, newMax = 255; for (int i = 0; i < nTests; ++i) Mat test = Mat::zeros(3,3,CV_8UC1); test.at<uchar>(0, 0) = oldMax; test.at<uchar>(0, 1) = oldMax / 2; test.at<uchar>(0, 2) = oldMax / 4; cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB(); wb->setInputMin(0); wb->setInputMax(oldMax); wb->setOutputMin(0); wb->setOutputMax(newMax); wb->balanceWhite(test, test); double minDst, maxDst; cv::minMaxIdx(test, &minDst, &maxDst); ASSERT_NEAR(maxDst, newMax, 1e-4); } TEST(xphoto_simplecolorbalance, uchar_min_value) { const uchar oldMin = 120, newMin = 0; Mat test = Mat::zeros(1,3,CV_8UC1); test.at<uchar>(0, 0) = oldMin; test.at<uchar>(0, 1) = (256 + oldMin) / 2; test.at<uchar>(0, 2) = 255; cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB(); wb->setInputMin(oldMin); wb->setInputMax(255); wb->setOutputMin(newMin); wb->setOutputMax(255); wb->balanceWhite(test, test); double minDst, maxDst; cv::minMaxIdx(test, &minDst, &maxDst); ASSERT_NEAR(minDst, newMin, 1e-4); } TEST(xphoto_simplecolorbalance, uchar_equal_range) { cv::String srcName = dir + cv::format( "sources/%02d.png", i + 1); cv::Mat src = cv::imread( srcName, 1 ); ASSERT_TRUE(!src.empty()); const int N = 4; uchar data[N] = {0, 1, 16, 255}; Mat test = Mat(1, N, CV_8UC1, data); Mat result = Mat(1, N, CV_8UC1, data); cv::String previousResultName = dir + cv::format( "results/%02d.jpg", i + 1 ); cv::Mat previousResult = cv::imread( previousResultName, 1 ); cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB(); wb->setInputMin(0); wb->setInputMax(255); wb->setOutputMin(0); wb->setOutputMax(255); wb->balanceWhite(test, test); double err; cv::minMaxIdx(cv::abs(test - result), NULL, &err); ASSERT_LE(err, 1e-4); } cv::Mat currentResult; wb->balanceWhite(src, currentResult); TEST(xphoto_simplecolorbalance, uchar_single_value) { const int N = 4; uchar data0[N] = {51, 51, 51, 51}; uchar data1[N] = {33, 33, 33, 33}; Mat test = Mat(1, N, CV_8UC1, data0); Mat result = Mat(1, N, CV_8UC1, data1); cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB(); wb->setInputMin(51); wb->setInputMax(51); wb->setOutputMin(33); wb->setOutputMax(200); double psnr = cv::PSNR(currentResult, previousResult); wb->balanceWhite(test, test); EXPECT_GE( psnr, 30 ); double err; cv::minMaxIdx(cv::abs(test - result), NULL, &err); ASSERT_LE(err, 1e-4); } TEST(xphoto_simplecolorbalance, uchar_p) { const int N = 5; uchar data0[N] = {10, 55, 102, 188, 233}; uchar data1[N] = {0, 1, 90, 254, 255}; Mat test = Mat(1, N, CV_8UC1, data0); Mat result = Mat(1, N, CV_8UC1, data1); cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB(); wb->setInputMin(10); wb->setInputMax(233); wb->setOutputMin(0); wb->setOutputMax(255); wb->setP(21); wb->balanceWhite(test, test); double err; cv::minMaxIdx(cv::abs(test - result), NULL, &err); ASSERT_LE(err, 1e-4); } TEST(xphoto_simplecolorbalance, max_value) TEST(xphoto_simplecolorbalance, uchar_c3) { const float oldMax = 24000., newMax = 65536.; const int N = 15; uchar data0[N] = {10, 55, 102, 55, 102, 188, 102, 188, 233, 188, 233, 10, 233, 10, 55}; uchar data1[N] = {0, 1, 90, 1, 90, 254, 90, 254, 255, 254, 255, 0, 255, 0, 1}; Mat test = Mat(1, N / 3, CV_8UC3, data0); Mat result = Mat(1, N / 3, CV_8UC3, data1); cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB(); wb->setInputMin(10); wb->setInputMax(233); wb->setOutputMin(0); wb->setOutputMax(255); wb->setP(21); wb->balanceWhite(test, test); double err; cv::minMaxIdx(cv::abs(test - result), NULL, &err); ASSERT_LE(err, 1e-4); } TEST(xphoto_simplecolorbalance, float_max_value) { const float oldMax = 24000.f, newMax = 65536.f; Mat test = Mat::zeros(3,3,CV_32FC1); test.at<float>(0, 0) = oldMax; Loading @@ -55,5 +162,112 @@ namespace opencv_test { namespace { ASSERT_NEAR(maxDst, newMax, newMax*1e-4); } TEST(xphoto_simplecolorbalance, float_min_value) { const float oldMin = 24000.f, newMin = 0.f; Mat test = Mat::zeros(1,3,CV_32FC1); test.at<float>(0, 0) = oldMin; test.at<float>(0, 1) = (65536.f + oldMin) / 2; test.at<float>(0, 2) = 65536.f; cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB(); wb->setInputMin(oldMin); wb->setInputMax(65536.f); wb->setOutputMin(newMin); wb->setOutputMax(65536.f); wb->balanceWhite(test, test); double minDst, maxDst; cv::minMaxIdx(test, &minDst, &maxDst); ASSERT_NEAR(minDst, newMin, 65536*1e-4); } TEST(xphoto_simplecolorbalance, float_equal_range) { const int N = 5; float data[N] = {0.f, 1.f, 16.2f, 256.3f, 4096.f}; Mat test = Mat(1, N, CV_32FC1, data); Mat result = Mat(1, N, CV_32FC1, data); cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB(); wb->setInputMin(0); wb->setInputMax(4096); wb->setOutputMin(0); wb->setOutputMax(4096); wb->balanceWhite(test, test); double err; cv::minMaxIdx(cv::abs(test - result), NULL, &err); ASSERT_LE(err, 1e-4); } TEST(xphoto_simplecolorbalance, float_single_value) { const int N = 4; float data0[N] = {24000.5f, 24000.5f, 24000.5f, 24000.5f}; float data1[N] = {52000.25f, 52000.25f, 52000.25f, 52000.25f}; Mat test = Mat(1, N, CV_32FC1, data0); Mat result = Mat(1, N, CV_32FC1, data1); cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB(); wb->setInputMin(24000.5f); wb->setInputMax(24000.5f); wb->setOutputMin(52000.25f); wb->setOutputMax(65536.f); wb->balanceWhite(test, test); double err; cv::minMaxIdx(cv::abs(test - result), NULL, &err); ASSERT_LE(err, 65536*1e-4); } TEST(xphoto_simplecolorbalance, float_p) { const int N = 5; float data0[N] = {16000.f, 20000.5f, 24000.f, 36000.5f, 48000.f}; float data1[N] = {-16381.952f, 0.f, 16381.952f, 65536.f, 114685.952f}; Mat test = Mat(1, N, CV_32FC1, data0); Mat result = Mat(1, N, CV_32FC1, data1); cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB(); wb->setInputMin(16000.f); wb->setInputMax(48000.f); wb->setOutputMin(0.f); wb->setOutputMax(65536.f); wb->setP(21); wb->balanceWhite(test, test); double err; cv::minMaxIdx(cv::abs(test - result), NULL, &err); ASSERT_LE(err, 65536*1e-4); } TEST(xphoto_simplecolorbalance, float_c3) { const int N = 15; float data0[N] = {16000.f, 20000.5f, 24000.f, 20000.5f, 24000.f, 36000.5f, 24000.f, 36000.5f, 48000.f, 36000.5f, 48000.f, 16000.f, 48000.f, 16000.f, 20000.5f}; float data1[N] = {-16381.952f, 0.f, 16381.952f, 0.f, 16381.952f, 65536.f, 16381.952f, 65536.f, 114685.952f, 65536.f, 114685.952f, -16381.952f, 114685.952f, -16381.952f, 0.f}; Mat test = Mat(1, N / 3, CV_32FC3, data0); Mat result = Mat(1, N / 3, CV_32FC3, data1); cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB(); wb->setInputMin(16000.f); wb->setInputMax(48000.f); wb->setOutputMin(0.f); wb->setOutputMax(65536.f); wb->setP(21); wb->balanceWhite(test, test); double err; cv::minMaxIdx(cv::abs(test - result), NULL, &err); ASSERT_LE(err, 65536*1e-4); } }} // namespace