Commit 80063fd4 authored by Maksim Shabunin's avatar Maksim Shabunin

Merge pull request #736 from sbokov:color_constancy

parents 159534a2 5fbc7daf
......@@ -6,3 +6,11 @@
year={2012},
publisher={Springer}
}
@inproceedings{Cheng2015,
title={Effective learning-based illuminant estimation using simple features},
author={Cheng, Dongliang and Price, Brian and Cohen, Scott and Brown, Michael S},
booktitle={Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition},
pages={1000--1008},
year={2015}
}
......@@ -105,7 +105,7 @@ namespace xphoto
threshold of 0 means no pixels are used. Lower thresholds are useful in
white-balancing saturated images.
Currently only works on images of type @ref CV_8UC3.
Currently only works on images of type @ref CV_8UC3 and @ref CV_16UC3.
@param src Input array.
@param dst Output array of the same size and type as src.
......@@ -117,7 +117,69 @@ namespace xphoto
CV_EXPORTS_W void autowbGrayworld(InputArray src, OutputArray dst,
float thresh = 0.5f);
//! @}
/** @brief Implements a more sophisticated learning-based automatic color balance algorithm.
As autowbGrayworld, this function works by applying different gains to the input
image channels, but their computation is a bit more involved compared to the
simple grayworld assumption. More details about the algorithm can be found in
@cite Cheng2015 .
To mask out saturated pixels this function uses only pixels that satisfy the
following condition:
\f[ \frac{\textrm{max}(R,G,B)}{\texttt{range_max_val}} < \texttt{saturation_thresh} \f]
Currently supports images of type @ref CV_8UC3 and @ref CV_16UC3.
@param src Input three-channel image in the BGR color space.
@param dst Output image of the same size and type as src.
@param range_max_val Maximum possible value of the input image (e.g. 255 for 8 bit images, 4095 for 12 bit images)
@param saturation_thresh Threshold that is used to determine saturated pixels
@param hist_bin_num Defines the size of one dimension of a three-dimensional RGB histogram that is used internally by
the algorithm. It often makes sense to increase the number of bins for images with higher bit depth (e.g. 256 bins
for a 12 bit image)
@sa autowbGrayworld
*/
CV_EXPORTS_W void autowbLearningBased(InputArray src, OutputArray dst, int range_max_val = 255,
float saturation_thresh = 0.98f, int hist_bin_num = 64);
/** @brief Implements the feature extraction part of the learning-based color balance algorithm.
In accordance with @cite Cheng2015 , computes the following features for the input image:
1. Chromaticity of an average (R,G,B) tuple
2. Chromaticity of the brightest (R,G,B) tuple (while ignoring saturated pixels)
3. Chromaticity of the dominant (R,G,B) tuple (the one that has the highest value in the RGB histogram)
4. Mode of the chromaticity pallete, that is constructed by taking 300 most common colors according to
the RGB histogram and projecting them on the chromaticity plane. Mode is the most high-density point
of the pallete, which is computed by a straightforward fixed-bandwidth kernel density estimator with
a Epanechnikov kernel function.
@param src Input three-channel image in the BGR color space.
@param dst An array of four (r,g) chromaticity tuples corresponding to the features listed above.
@param range_max_val Maximum possible value of the input image (e.g. 255 for 8 bit images, 4095 for 12 bit images)
@param saturation_thresh Threshold that is used to determine saturated pixels
@param hist_bin_num Defines the size of one dimension of a three-dimensional RGB histogram that is used internally by
the algorithm. It often makes sense to increase the number of bins for images with higher bit depth (e.g. 256 bins
for a 12 bit image)
@sa autowbLearningBased
*/
CV_EXPORTS_W void extractSimpleFeatures(InputArray src, OutputArray dst, int range_max_val = 255,
float saturation_thresh = 0.98f, int hist_bin_num = 64);
/** @brief Implements an efficient fixed-point approximation for applying channel gains.
@param src Input three-channel image in the BGR color space (either CV_8UC3 or CV_16UC3)
@param dst Output image of the same size and type as src.
@param gainB gain for the B channel
@param gainG gain for the G channel
@param gainR gain for the R channel
@sa autowbGrayworld, autowbLearningBased
*/
CV_EXPORTS_W void applyChannelGains(InputArray src, OutputArray dst, float gainB, float gainG, float gainR);
//! @}
}
}
......
/*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
*
* License Agreement
* For Open Source Computer Vision Library
* (3 - clause BSD License)
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met :
*
* *Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and / or other materials provided with the distribution.
*
* * Neither the names of the copyright holders nor the names of the contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* This software is provided by the copyright holders and contributors "as is" and
* any express or implied warranties, including, but not limited to, the implied
* warranties of merchantability and fitness for a particular purpose are disclaimed.
* In no event shall copyright holders or contributors be liable for any direct,
* indirect, incidental, special, exemplary, or consequential damages
* (including, but not limited to, procurement of substitute goods or services;
* loss of use, data, or profits; or business interruption) however caused
* and on any theory of liability, whether in contract, strict liability,
* or tort(including negligence or otherwise) arising in any way out of
* the use of this software, even if advised of the possibility of such damage.
*/
#include "perf_precomp.hpp"
#include "opencv2/imgproc.hpp"
using std::tr1::tuple;
using std::tr1::get;
using namespace std;
using namespace cv;
using namespace perf;
using namespace testing;
typedef tuple<Size, MatType> learningBasedWBParams;
typedef TestBaseWithParam<learningBasedWBParams> learningBasedWBPerfTest;
PERF_TEST_P(learningBasedWBPerfTest, perf, Combine(SZ_ALL_HD, Values(CV_8UC3, CV_16UC3)))
{
Size size = get<0>(GetParam());
MatType t = get<1>(GetParam());
Mat src(size, t);
Mat dst(size, t);
int range_max_val = 255, hist_bin_num = 64;
if (t == CV_16UC3)
{
range_max_val = 65535;
hist_bin_num = 256;
}
Mat src_dscl(Size(size.width / 16, size.height / 16), t);
RNG rng(1234);
rng.fill(src_dscl, RNG::UNIFORM, 0, range_max_val);
resize(src_dscl, src, src.size());
TEST_CYCLE() xphoto::autowbLearningBased(src, dst, range_max_val, 0.98f, hist_bin_num);
SANITY_CHECK_NOTHING();
}
This diff is collapsed.
#include "opencv2/xphoto.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;
using namespace std;
const char *keys = {"{help h usage ? | | print this message}"
"{i | | input image name }"
"{o | | output image name }"};
int main(int argc, const char **argv)
{
CommandLineParser parser(argc, argv, keys);
parser.about("OpenCV learning-based color balance demonstration sample");
if (parser.has("help") || argc < 2)
{
parser.printMessage();
return 0;
}
string inFilename = parser.get<string>("i");
string outFilename = parser.get<string>("o");
if (!parser.check())
{
parser.printErrors();
return -1;
}
Mat src = imread(inFilename, 1);
if (src.empty())
{
printf("Cannot read image file: %s\n", inFilename.c_str());
return -1;
}
Mat res;
xphoto::autowbLearningBased(src, res);
if (outFilename == "")
{
namedWindow("after white balance", 1);
imshow("after white balance", res);
waitKey(0);
}
else
imwrite(outFilename, res);
return 0;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -81,7 +81,13 @@ namespace cvtest {
Mat currentResult;
xphoto::autowbGrayworld(src, currentResult, wb_thresh);
ASSERT_LE(cv::norm(currentResult, referenceResult, NORM_INF), acc_thresh);
// test the 16-bit depth:
Mat currentResult_16U, src_16U;
src.convertTo(src_16U, CV_16UC3, 256.0);
xphoto::autowbGrayworld(src_16U, currentResult_16U, wb_thresh);
currentResult_16U.convertTo(currentResult, CV_8UC3, 1/256.0);
ASSERT_LE(cv::norm(currentResult, referenceResult, NORM_INF), acc_thresh);
}
}
......
#include "test_precomp.hpp"
using namespace cv;
namespace cvtest
{
TEST(xphoto_simplefeatures, regression)
{
float acc_thresh = 0.01f;
// Generate a test image:
Mat test_im(1000, 1000, CV_8UC3);
RNG rng(1234);
rng.fill(test_im, RNG::NORMAL, Scalar(64, 100, 128), Scalar(10, 10, 10));
threshold(test_im, test_im, 200.0, 255.0, THRESH_TRUNC);
test_im.at<Vec3b>(0, 0) = Vec3b(240, 220, 200);
// Which should have the following features:
Vec2f ref1(128.0f / (64 + 100 + 128), 100.0f / (64 + 100 + 128));
Vec2f ref2(200.0f / (240 + 220 + 200), 220.0f / (240 + 220 + 200));
vector<Vec2f> dst_features;
xphoto::extractSimpleFeatures(test_im, dst_features, 255, 0.98f, 64);
ASSERT_LE(cv::norm(dst_features[0], ref1, NORM_INF), acc_thresh);
ASSERT_LE(cv::norm(dst_features[1], ref2, NORM_INF), acc_thresh);
ASSERT_LE(cv::norm(dst_features[2], ref1, NORM_INF), acc_thresh);
ASSERT_LE(cv::norm(dst_features[3], ref1, NORM_INF), acc_thresh);
// check 16 bit depth:
test_im.convertTo(test_im, CV_16U, 256.0);
xphoto::extractSimpleFeatures(test_im, dst_features, 65535, 0.98f, 64);
ASSERT_LE(cv::norm(dst_features[0], ref1, NORM_INF), acc_thresh);
ASSERT_LE(cv::norm(dst_features[1], ref2, NORM_INF), acc_thresh);
ASSERT_LE(cv::norm(dst_features[2], ref1, NORM_INF), acc_thresh);
ASSERT_LE(cv::norm(dst_features[3], ref1, NORM_INF), acc_thresh);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment