Mantiuk+equalizeHist doesn't depend on the passed scale

asked 2019-02-18 05:10:38 -0600

Stefan Monov gravatar image

updated 2019-02-20 09:30:36 -0600

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 :)

Edit: This question seems to be related


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);
edit retag flag offensive close merge delete


So it works like a "global tonemapping operator" rather than the local one it's supposed to be.

Can you give a reference I tried this (divide by 10 to get good scale)

LBerger gravatar imageLBerger ( 2019-02-18 06:45:19 -0600 )edit

@LBerger: Thanks for replying! Please see the edit to my question. :)

Stefan Monov gravatar imageStefan Monov ( 2019-02-19 07:31:32 -0600 )edit

" cv's mantiuk tonemapping can be "undone" by doing a histogram equalization"

can you give code ?

LBerger gravatar imageLBerger ( 2019-02-19 08:46:13 -0600 )edit

@LBerger: Sure. Edited again. :)

Stefan Monov gravatar imageStefan Monov ( 2019-02-20 09:31:23 -0600 )edit