mirror of
https://github.com/opencv/opencv_contrib.git
synced 2025-10-18 00:01:17 +08:00
Merge pull request #2263 from kqwyf:fix
This commit is contained in:
@@ -39,7 +39,6 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
#include "opencv2/core.hpp"
|
||||
@@ -59,73 +58,55 @@ 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;
|
||||
|
||||
// deal with cv::calcHist (exclusive upper bound)
|
||||
if (src[0].depth() == CV_32F || src[0].depth() == CV_64F) // floating
|
||||
{
|
||||
maxValue0 += MIN((inputMax - inputMin) / (nElements - 1), 1);
|
||||
if (inputMax == inputMin) // single value
|
||||
maxValue0 += 1;
|
||||
}
|
||||
else // integer
|
||||
{
|
||||
maxValue0 += 1;
|
||||
}
|
||||
|
||||
float interval = (maxValue0 - minValue0) / float(nElements);
|
||||
|
||||
for (size_t i = 0; i < src.size(); ++i)
|
||||
{
|
||||
std::vector<int> hist(nElements, 0);
|
||||
float minValue = minValue0;
|
||||
float maxValue = maxValue0;
|
||||
|
||||
typename Mat_<T>::iterator beginIt = src[i].begin();
|
||||
typename Mat_<T>::iterator endIt = src[i].end();
|
||||
Mat img = src[i].reshape(1);
|
||||
Mat hist;
|
||||
int channels[] = {0};
|
||||
int histSize[] = {nElements};
|
||||
float inputRange[] = {minValue, maxValue};
|
||||
const float *ranges[] = {inputRange};
|
||||
|
||||
for (typename Mat_<T>::iterator it = beginIt; it != endIt; ++it)
|
||||
// histogram filling
|
||||
{
|
||||
int pos = 0;
|
||||
float minValue = inputMin - 0.5f;
|
||||
float maxValue = inputMax + 0.5f;
|
||||
T val = *it;
|
||||
|
||||
float interval = float(maxValue - minValue) / bins;
|
||||
|
||||
for (int j = 0; j < depth; ++j)
|
||||
{
|
||||
int currentBin = int((val - minValue + 1e-4f) / interval);
|
||||
++hist[pos + currentBin];
|
||||
|
||||
pos = (pos + currentBin) * bins;
|
||||
|
||||
minValue = minValue + currentBin * interval;
|
||||
maxValue = minValue + interval;
|
||||
|
||||
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++];
|
||||
minValue += interval;
|
||||
}
|
||||
p1 *= bins;
|
||||
n1 += saturate_cast<int>(hist.at<float>(p1++));
|
||||
minValue += interval;
|
||||
}
|
||||
|
||||
while (n2 - hist[p2] > (100.0f - s2) * total / 100.0f)
|
||||
{
|
||||
n2 -= hist[p2--];
|
||||
maxValue -= interval;
|
||||
}
|
||||
p2 = (p2 + 1) * bins - 1;
|
||||
|
||||
interval /= bins;
|
||||
while (n2 - hist.at<float>(p2) > (100.0f - s2) * total / 100.0f)
|
||||
{
|
||||
n2 -= saturate_cast<int>(hist.at<float>(p2--));
|
||||
maxValue -= interval;
|
||||
}
|
||||
|
||||
src[i] = (outputMax - outputMin) * (src[i] - minValue) / (maxValue - minValue) + outputMin;
|
||||
|
@@ -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)
|
||||
{
|
||||
cv::String srcName = dir + cv::format( "sources/%02d.png", i + 1);
|
||||
cv::Mat src = cv::imread( srcName, 1 );
|
||||
ASSERT_TRUE(!src.empty());
|
||||
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::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(oldMax);
|
||||
wb->setOutputMin(0);
|
||||
wb->setOutputMax(newMax);
|
||||
|
||||
cv::Mat currentResult;
|
||||
wb->balanceWhite(src, currentResult);
|
||||
wb->balanceWhite(test, test);
|
||||
|
||||
double psnr = cv::PSNR(currentResult, previousResult);
|
||||
double minDst, maxDst;
|
||||
cv::minMaxIdx(test, &minDst, &maxDst);
|
||||
|
||||
EXPECT_GE( psnr, 30 );
|
||||
}
|
||||
ASSERT_NEAR(maxDst, newMax, 1e-4);
|
||||
}
|
||||
|
||||
TEST(xphoto_simplecolorbalance, max_value)
|
||||
TEST(xphoto_simplecolorbalance, uchar_min_value)
|
||||
{
|
||||
const float oldMax = 24000., newMax = 65536.;
|
||||
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)
|
||||
{
|
||||
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::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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
wb->balanceWhite(test, test);
|
||||
|
||||
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, uchar_c3)
|
||||
{
|
||||
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;
|
||||
@@ -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
|
||||
|
Reference in New Issue
Block a user