I did this first:
auto mantiuk = cv::createTonemapMantiuk(1, scale);
mantiuk->process(inMat, outMat);
And when I ran it (with an UI slider for the value of scale
), it looked like changing scale
just produces a "gamma correction" effect. So it works like a "global tonemapping operator" rather than the local one it's supposed to be.
To test my theory, I called cv::equalizeHist on outMat
, and indeed, changing scale
no longer has any effect.
Any idea what's going on?
TIA :)
Stefan
Edit: This question seems to be related
Edit:
Let me explain.
A global tonemapping operator (TMO) chooses a curve, then applies that same curve to every pixel. Examples of global TMOs are gamma correction and histogram equalization.
A local TMO uses the neighbourhood of a pixel to decide what the output value (for that pixel) should be.
Mantiuk's paper (implemented in OCV) defines a local TMO. You can see that even just by reading the OCV documentation on it.
But the OCV implementation seems buggy, as it only does what a global TMO can do.
Informal proof:
An image A is global-tonemapped (using curve f
) into an image B if-and-only-if that tonemapping can be undone by using the inverse function of f.
And, as I wrote above, cv's mantiuk tonemapping can be "undone" by doing a histogram equalization, which simply applies a curve to the image.
Edit: Here's my testcase:
#include <opencv2/core.hpp>
#include <opencv2/photo.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;
const int alpha_slider_max = 100;
int alpha_slider;
Mat src;
static void on_trackbar(int, void*)
{
double scale = (double)alpha_slider / alpha_slider_max;
auto mantiuk = cv::createTonemapMantiuk(1, scale);
auto origLum = cv::Mat(); cv::cvtColor(src, origLum, COLOR_BGR2GRAY);
auto origLum_b = cv::Mat(); cv::cvtColor(origLum, origLum_b, COLOR_GRAY2BGR);
auto origLum2 = cv::Mat(); origLum_b.convertTo(origLum2, CV_32FC3);
auto dst1 = cv::Mat(); mantiuk->process(origLum2, dst1);
auto dst2 = cv::Mat(); cv::cvtColor(dst1, dst2, COLOR_BGR2GRAY);
auto dst3 = cv::Mat(); dst2.convertTo(dst3, CV_8UC3, 255.0f);
auto dst4 = cv::Mat(); cv::equalizeHist(dst3, dst4);
auto dst5 = cv::Mat(); cv::cvtColor(dst4, dst5, COLOR_GRAY2BGR);
auto dst6 = cv::Mat(); dst5.convertTo(dst6, CV_32FC3, 1.0f/255.0f);
Mat res = src.mul(dst6) / origLum2;
auto res2 = cv::Mat(); res.convertTo(res2, CV_8UC3, 255.0f);
imshow("_", res2);
}
int main()
{
src = imread("../../MantiukTestcase/1.hdr", IMREAD_ANYDEPTH);
auto matSize = src.size();
matSize.width *= .15f;
matSize.height *= .15f;
cv::resize(src, src, matSize);
alpha_slider = 50;
namedWindow("_", WINDOW_AUTOSIZE); // Create Window
char TrackbarName[50];
sprintf_s(TrackbarName, "Alpha x %d", alpha_slider_max);
createTrackbar(TrackbarName, "_", &alpha_slider, alpha_slider_max, on_trackbar);
on_trackbar(alpha_slider, 0);
waitKey(0);
}