# Revision history [back]

### Mantiuk+equalizeHist doesn't depend on the passed scale

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

### Mantiuk+equalizeHist doesn't depend on the passed scale

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

### Mantiuk+equalizeHist doesn't depend on the passed scale

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.

### Mantiuk+equalizeHist doesn't depend on the passed scale

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()
{