'normalize histogram in c++ - function normalize in openCV

I need to normalize the histogram of an image f which mean to applicated an transformation of histogram from image in order to extend the range of value of f to all available values. the norm(fmin) = Vmin ( minimal value we want to reach) and normal(fmin) = Vmax ( maximal value we want to reach)

I have this formula too

the goal is to have the same result that the function normalize which openCV gives.

Mat normalize(Mat image, float minValue, float maxValue)
{
  Mat res = image.clone();
  assert(minValue <= maxValue);
 float Fmax = 0; 
 float Fmin = 0;

for(int i = 0; i < res.rows; i++)
{
    for(int j = 0; j < res.cols; j++)
    {
        float x = res.at<float>(i,j);
        if(i < minValue)
        {
            Fmin = i;
        }
        if( i > maxValue)
        {
            Fmax = i;
        }
        res.at<float>(i,j) = (x - Fmin) * ((maxValue - minValue) / (Fmax - Fmin)) + minValue; 

    }
}
     return res;
}

I have this error : !!! Warning, saved image values not between 0 and 1. !!! Warning, saved image values not between 0 and 1.

I think I didn't understand how to calculate fmin/ fmax



Solution 1:[1]

So, as I explained in my comment, there are some mistakes, here's the corrected version. You need to run the double loop twice, once to find the min-max, and a second time to apply the formula. There were also errors in the comparisons:

cv::Mat normalize(cv::Mat image, float minValue, float maxValue)
{
    cv::Mat res = image.clone();
    assert(minValue <= maxValue);

    // 1) find min and max values
    float Fmax = 0.0f;
    float Fmin = 1.0f; // set it to 1, not 0

    for (int i = 0; i < res.rows; i++)
    {
        float* pixels = res.ptr<float>(i); // this is quicker
        for (int j = 0; j < res.cols; j++)
        {
            float x = pixels[j];
            if (x < Fmin) // compare x and Fmin, not i and minValue
            {
                Fmin = x;
            }
            if (x > Fmax) // compare x and Fmax, not i and maxValue
            {
                Fmax = x;
            }
        }
    }

    // 1 color image => don't normalize + avoid crash
    if (Fmin >= Fmax)
        return res;

    // 2) normalize using your formula
    for (int i = 0; i < res.rows; i++)
    {
        float* pixels = res.ptr<float>(i);
        for (int j = 0; j < res.cols; j++)
        {
            pixels[j] = (pixels[j] - Fmin) * ((maxValue - minValue) / (Fmax - Fmin)) + minValue;
        }
    }
    return res;
}

If your source image is a grayscale image in 8 bit, you can convert it like that:

cv::Mat floatImage;
grayImage.convertTo(floatImage, CV_32F, 1.0 / 255, 0);
floatImage = normalize(floatImage, 0, 1.0f);
floatImage.convertTo(grayImage, CV_8UC1, 255.0, 0);

Also, if you use cv::minMaxLoc, your normalize function can be made shorter =>

cv::Mat normalize(cv::Mat image, float minValue, float maxValue)
{
    cv::Mat res = image.clone();
    assert(minValue <= maxValue);

    // 1) find min and max values
    double Fmax;
    double Fmin;
    cv::minMaxLoc(image, &Fmin, &Fmax);

    if (Fmin >= Fmax)
        return res;

    // 2) normalize using your formula
    for (int i = 0; i < res.rows; i++)
    {
        float* pixels = res.ptr<float>(i);
        for (int j = 0; j < res.cols; j++)
        {
            pixels[j] = (pixels[j] - Fmin) * ((maxValue - minValue) / (Fmax - Fmin)) + minValue;
        }
    }
    return res;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1