|
|
|
@ -47,20 +47,58 @@ |
|
|
|
|
namespace cv |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
static float getParam(const std::vector<float>& params, size_t i, float defval)
|
|
|
|
|
Tonemap::Tonemap(float gamma) : gamma(gamma) |
|
|
|
|
{ |
|
|
|
|
if(params.size() > i) { |
|
|
|
|
return params[i]; |
|
|
|
|
} else { |
|
|
|
|
return defval; |
|
|
|
|
}
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void DragoMap(Mat& src_img, Mat &dst_img, const std::vector<float>& params) |
|
|
|
|
Tonemap::~Tonemap() |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void Tonemap::process(InputArray src, OutputArray dst) |
|
|
|
|
{ |
|
|
|
|
Mat srcMat = src.getMat(); |
|
|
|
|
CV_Assert(!srcMat.empty()); |
|
|
|
|
dst.create(srcMat.size(), CV_32FC3); |
|
|
|
|
img = dst.getMat(); |
|
|
|
|
srcMat.copyTo(img); |
|
|
|
|
linearMap(); |
|
|
|
|
tonemap(); |
|
|
|
|
gammaCorrection(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void Tonemap::linearMap() |
|
|
|
|
{ |
|
|
|
|
double min, max; |
|
|
|
|
minMaxLoc(img, &min, &max); |
|
|
|
|
if(max - min > DBL_EPSILON) { |
|
|
|
|
img = (img - min) / (max - min); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void Tonemap::gammaCorrection() |
|
|
|
|
{ |
|
|
|
|
pow(img, 1.0f / gamma, img); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void TonemapLinear::tonemap() |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TonemapLinear::TonemapLinear(float gamma) : Tonemap(gamma) |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TonemapDrago::TonemapDrago(float gamma, float bias) : |
|
|
|
|
Tonemap(gamma), |
|
|
|
|
bias(bias) |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void TonemapDrago::tonemap()
|
|
|
|
|
{ |
|
|
|
|
float bias_value = getParam(params, 1, 0.85f); |
|
|
|
|
Mat gray_img; |
|
|
|
|
cvtColor(src_img, gray_img, COLOR_RGB2GRAY); |
|
|
|
|
cvtColor(img, gray_img, COLOR_RGB2GRAY); |
|
|
|
|
Mat log_img; |
|
|
|
|
log(gray_img, log_img); |
|
|
|
|
float mean = expf(static_cast<float>(sum(log_img)[0]) / log_img.total()); |
|
|
|
@ -73,7 +111,7 @@ static void DragoMap(Mat& src_img, Mat &dst_img, const std::vector<float>& param |
|
|
|
|
Mat map; |
|
|
|
|
log(gray_img + 1.0f, map); |
|
|
|
|
Mat div; |
|
|
|
|
pow(gray_img / (float)max, logf(bias_value) / logf(0.5f), div); |
|
|
|
|
pow(gray_img / (float)max, logf(bias) / logf(0.5f), div); |
|
|
|
|
log(2.0f + 8.0f * div, div); |
|
|
|
|
map = map.mul(1.0f / div); |
|
|
|
|
map = map.mul(1.0f / gray_img); |
|
|
|
@ -81,22 +119,61 @@ static void DragoMap(Mat& src_img, Mat &dst_img, const std::vector<float>& param |
|
|
|
|
gray_img.release(); |
|
|
|
|
|
|
|
|
|
std::vector<Mat> channels(3); |
|
|
|
|
split(src_img, channels); |
|
|
|
|
split(img, channels); |
|
|
|
|
for(int i = 0; i < 3; i++) { |
|
|
|
|
channels[i] = channels[i].mul(map); |
|
|
|
|
} |
|
|
|
|
map.release(); |
|
|
|
|
merge(channels, dst_img); |
|
|
|
|
merge(channels, img); |
|
|
|
|
linearMap(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void ReinhardDevlinMap(Mat& src_img, Mat &dst_img, const std::vector<float>& params) |
|
|
|
|
TonemapDurand::TonemapDurand(float gamma, float contrast, float sigma_color, float sigma_space) :
|
|
|
|
|
Tonemap(gamma),
|
|
|
|
|
contrast(contrast), |
|
|
|
|
sigma_color(sigma_color), |
|
|
|
|
sigma_space(sigma_space) |
|
|
|
|
{ |
|
|
|
|
float intensity = getParam(params, 1, 0.0f); |
|
|
|
|
float color_adapt = getParam(params, 2, 0.0f); |
|
|
|
|
float light_adapt = getParam(params, 3, 1.0f); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Mat gray_img; |
|
|
|
|
cvtColor(src_img, gray_img, COLOR_RGB2GRAY); |
|
|
|
|
void TonemapDurand::tonemap() |
|
|
|
|
{ |
|
|
|
|
Mat gray_img; |
|
|
|
|
cvtColor(img, gray_img, COLOR_RGB2GRAY); |
|
|
|
|
Mat log_img; |
|
|
|
|
log(gray_img, log_img); |
|
|
|
|
Mat map_img; |
|
|
|
|
bilateralFilter(log_img, map_img, -1, sigma_color, sigma_space); |
|
|
|
|
|
|
|
|
|
double min, max; |
|
|
|
|
minMaxLoc(map_img, &min, &max); |
|
|
|
|
float scale = contrast / (float)(max - min); |
|
|
|
|
|
|
|
|
|
exp(map_img * (scale - 1.0f) + log_img, map_img); |
|
|
|
|
log_img.release(); |
|
|
|
|
map_img = map_img.mul(1.0f / gray_img); |
|
|
|
|
gray_img.release(); |
|
|
|
|
|
|
|
|
|
std::vector<Mat> channels(3); |
|
|
|
|
split(img, channels); |
|
|
|
|
for(int i = 0; i < 3; i++) { |
|
|
|
|
channels[i] = channels[i].mul(map_img); |
|
|
|
|
} |
|
|
|
|
merge(channels, img); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TonemapReinhardDevlin::TonemapReinhardDevlin(float gamma, float intensity, float color_adapt, float light_adapt) :
|
|
|
|
|
Tonemap(gamma),
|
|
|
|
|
intensity(intensity), |
|
|
|
|
color_adapt(color_adapt), |
|
|
|
|
light_adapt(light_adapt) |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void TonemapReinhardDevlin::tonemap() |
|
|
|
|
{ |
|
|
|
|
Mat gray_img; |
|
|
|
|
cvtColor(img, gray_img, COLOR_RGB2GRAY); |
|
|
|
|
Mat log_img; |
|
|
|
|
log(gray_img, log_img); |
|
|
|
|
|
|
|
|
@ -108,11 +185,11 @@ static void ReinhardDevlinMap(Mat& src_img, Mat &dst_img, const std::vector<floa |
|
|
|
|
double key = (float)((log_max - log_mean) / (log_max - log_min)); |
|
|
|
|
float map_key = 0.3f + 0.7f * pow((float)key, 1.4f); |
|
|
|
|
intensity = exp(-intensity); |
|
|
|
|
Scalar chan_mean = mean(src_img); |
|
|
|
|
Scalar chan_mean = mean(img); |
|
|
|
|
float gray_mean = (float)mean(gray_img)[0]; |
|
|
|
|
|
|
|
|
|
std::vector<Mat> channels(3); |
|
|
|
|
split(src_img, channels); |
|
|
|
|
split(img, channels); |
|
|
|
|
|
|
|
|
|
for(int i = 0; i < 3; i++) { |
|
|
|
|
float global = color_adapt * (float)chan_mean[i] + (1.0f - color_adapt) * gray_mean; |
|
|
|
@ -122,65 +199,31 @@ static void ReinhardDevlinMap(Mat& src_img, Mat &dst_img, const std::vector<floa |
|
|
|
|
channels[i] = channels[i].mul(1.0f / (adapt + channels[i]));
|
|
|
|
|
} |
|
|
|
|
gray_img.release(); |
|
|
|
|
merge(channels, dst_img); |
|
|
|
|
merge(channels, img); |
|
|
|
|
linearMap(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void DurandMap(Mat& src_img, Mat& dst_img, const std::vector<float>& params) |
|
|
|
|
Ptr<Tonemap> Tonemap::create(const String& TonemapType) |
|
|
|
|
{ |
|
|
|
|
float contrast = getParam(params, 1, 4.0f); |
|
|
|
|
float sigma_color = getParam(params, 2, 2.0f); |
|
|
|
|
float sigma_space = getParam(params, 3, 2.0f); |
|
|
|
|
|
|
|
|
|
Mat gray_img; |
|
|
|
|
cvtColor(src_img, gray_img, COLOR_RGB2GRAY); |
|
|
|
|
Mat log_img; |
|
|
|
|
log(gray_img, log_img); |
|
|
|
|
Mat map_img; |
|
|
|
|
bilateralFilter(log_img, map_img, -1, sigma_color, sigma_space); |
|
|
|
|
|
|
|
|
|
double min, max; |
|
|
|
|
minMaxLoc(map_img, &min, &max); |
|
|
|
|
float scale = contrast / (float)(max - min); |
|
|
|
|
|
|
|
|
|
exp(map_img * (scale - 1.0f) + log_img, map_img); |
|
|
|
|
log_img.release(); |
|
|
|
|
map_img = map_img.mul(1.0f / gray_img); |
|
|
|
|
gray_img.release(); |
|
|
|
|
|
|
|
|
|
std::vector<Mat> channels(3); |
|
|
|
|
split(src_img, channels); |
|
|
|
|
for(int i = 0; i < 3; i++) { |
|
|
|
|
channels[i] = channels[i].mul(map_img); |
|
|
|
|
} |
|
|
|
|
merge(channels, dst_img); |
|
|
|
|
return Algorithm::create<Tonemap>("Tonemap." + TonemapType); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void tonemap(InputArray _src, OutputArray _dst, int algorithm, |
|
|
|
|
const std::vector<float>& params) |
|
|
|
|
{ |
|
|
|
|
typedef void (*tonemap_func)(Mat&, Mat&, const std::vector<float>&); |
|
|
|
|
tonemap_func functions[TONEMAP_COUNT] = { |
|
|
|
|
NULL, DragoMap, ReinhardDevlinMap, DurandMap}; |
|
|
|
|
CV_INIT_ALGORITHM(TonemapLinear, "Tonemap.Linear", |
|
|
|
|
obj.info()->addParam(obj, "gamma", obj.gamma)); |
|
|
|
|
|
|
|
|
|
Mat src = _src.getMat(); |
|
|
|
|
CV_Assert(!src.empty()); |
|
|
|
|
CV_Assert(0 <= algorithm && algorithm < TONEMAP_COUNT); |
|
|
|
|
_dst.create(src.size(), CV_32FC3); |
|
|
|
|
Mat dst = _dst.getMat(); |
|
|
|
|
src.copyTo(dst); |
|
|
|
|
CV_INIT_ALGORITHM(TonemapDrago, "Tonemap.Drago", |
|
|
|
|
obj.info()->addParam(obj, "gamma", obj.gamma); |
|
|
|
|
obj.info()->addParam(obj, "bias", obj.bias)); |
|
|
|
|
|
|
|
|
|
double min, max; |
|
|
|
|
minMaxLoc(dst, &min, &max); |
|
|
|
|
if(max - min < DBL_EPSILON) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
dst = (dst - min) / (max - min); |
|
|
|
|
if(functions[algorithm]) { |
|
|
|
|
functions[algorithm](dst, dst, params); |
|
|
|
|
} |
|
|
|
|
minMaxLoc(dst, &min, &max); |
|
|
|
|
dst = (dst - min) / (max - min); |
|
|
|
|
float gamma = getParam(params, 0, 1.0f);
|
|
|
|
|
pow(dst, 1.0f / gamma, dst);
|
|
|
|
|
} |
|
|
|
|
CV_INIT_ALGORITHM(TonemapDurand, "Tonemap.Durand", |
|
|
|
|
obj.info()->addParam(obj, "gamma", obj.gamma); |
|
|
|
|
obj.info()->addParam(obj, "contrast", obj.contrast); |
|
|
|
|
obj.info()->addParam(obj, "sigma_color", obj.sigma_color); |
|
|
|
|
obj.info()->addParam(obj, "sigma_space", obj.sigma_space)); |
|
|
|
|
|
|
|
|
|
CV_INIT_ALGORITHM(TonemapReinhardDevlin, "Tonemap.ReinhardDevlin", |
|
|
|
|
obj.info()->addParam(obj, "gamma", obj.gamma); |
|
|
|
|
obj.info()->addParam(obj, "intensity", obj.intensity); |
|
|
|
|
obj.info()->addParam(obj, "color_adapt", obj.color_adapt); |
|
|
|
|
obj.info()->addParam(obj, "light_adapt", obj.light_adapt)); |
|
|
|
|
} |
|
|
|
|