Ask Your Question
5

How to make auto-adjustments(brightness and contrast) for image Android Opencv Image Correction

asked 2015-11-06 02:15:04 -0600

VeTaLio gravatar image

updated 2020-11-30 03:26:01 -0600

i'm using OpenCV for Android.
I would like to know,how to make image correction(auto adjustments of brightness/contrast) for image(bitmap) in android via OpenCV or that can be done by native ColorMatrixFilter from Android!??

I tried to google,but didn't found good tutorials/examples.
So how can i achieve my goal? Any ideas?
Thanks!

edit retag flag offensive close merge delete

Comments

1

Some easy techniques for auto contrast:

Eduardo gravatar imageEduardo ( 2015-11-07 15:48:54 -0600 )edit

3 answers

Sort by » oldest newest most voted
16

answered 2015-11-08 13:38:35 -0600

pklab gravatar image

updated 2015-11-17 04:43:28 -0600

Brightness and contrast is linear operator with parameter alpha and beta

O(x,y) = alpha * I(x,y) + beta

In OpenCV you can do this with convertTo.

The question here is how to calculate alpha and beta automatically ?

Looking at histogram, alpha operates as color range amplifier, beta operates as range shift.

Automatic brightness and contrast optimization calculates alpha and beta so that the output range is 0..255.

input range = max(I) - min(I)
wanted output range = 255;
alpha = output range / input range =  255 / ( max(I) - min(I) )

You can calculate beta so that min(O) = 0;

min(O) = alpha * min(I) + beta
beta = -min(I) * alpha

Histogram Wings Cut (clipping)

To maximize the result of it's useful to cut out some color with few pixels.

This is done cutting left right and wings of histogram where color frequency is less than a value (typically 1%). Calculating cumulative distribution from the histogram you can easly find where to cut.

may be sample chart helps to understand: image description

EDIT: Histogram Normalization vs Equalization

By the way BrightnessAndContrastAuto could be named normalizeHist because it works on BGR and gray images stretching the histogram to the full range without touching bins balance. If input image has range 0..255 BrightnessAndContrastAuto will do nothing.

Histogram equalization and CLAE works only on gray images and they change grays level balancing. look at the images below:

Normalization vs Equalization

EDIT2: Add support for BGRA images too

EDIT3: Correct error in "restore alpha channel from source "

however here is the code:

/**
 *  \brief Automatic brightness and contrast optimization with optional histogram clipping
 *  \param [in]src Input image GRAY or BGR or BGRA
 *  \param [out]dst Destination image 
 *  \param clipHistPercent cut wings of histogram at given percent tipical=>1, 0=>Disabled
 *  \note In case of BGRA image, we won't touch the transparency
*/
void BrightnessAndContrastAuto(const cv::Mat &src, cv::Mat &dst, float clipHistPercent=0)
{

    CV_Assert(clipHistPercent >= 0);
    CV_Assert((src.type() == CV_8UC1) || (src.type() == CV_8UC3) || (src.type() == CV_8UC4));

    int histSize = 256;
    float alpha, beta;
    double minGray = 0, maxGray = 0;

    //to calculate grayscale histogram
    cv::Mat gray;
    if (src.type() == CV_8UC1) gray = src;
    else if (src.type() == CV_8UC3) cvtColor(src, gray, CV_BGR2GRAY);
    else if (src.type() == CV_8UC4) cvtColor(src, gray, CV_BGRA2GRAY);
    if (clipHistPercent == 0)
    {
        // keep full available range
        cv::minMaxLoc(gray, &minGray, &maxGray);
    }
    else
    {
        cv::Mat hist; //the grayscale histogram

        float range[] = { 0, 256 };
        const float* histRange = { range };
        bool uniform = true;
        bool accumulate = false;
        calcHist(&gray, 1, 0, cv::Mat (), hist, 1, &histSize, &histRange, uniform, accumulate);

        // calculate cumulative distribution from the histogram
        std::vector<float> accumulator(histSize);
        accumulator[0] = hist.at<float>(0);
        for (int i = 1; i < histSize; i++)
        {
            accumulator[i] = accumulator[i - 1] + hist.at<float>(i);
        }

        // locate points that cuts at required value
        float max = accumulator.back();
        clipHistPercent *= (max / 100.0); //make percent as absolute
        clipHistPercent /= 2.0; // left and right wings
        // locate left cut
        minGray = 0;
        while (accumulator[minGray] < clipHistPercent)
            minGray++;

        // locate right cut
        maxGray = histSize - 1;
        while (accumulator[maxGray] >= (max - clipHistPercent))
            maxGray--;
    }

    // current range
    float inputRange = maxGray ...
(more)
edit flag offensive delete link more

Comments

1

Nice answer @pklab. Well done. +1 from me ☺

theodore gravatar imagetheodore ( 2015-11-08 14:40:29 -0600 )edit

Funny, it seems that the Gimp white balance command uses the same principle.

I also forgot to mention that the histogram equalization is a built-in functionnality in OpenCV...

There is also the CLAHE function (Contrast Limited Adaptive Histogram Equalization) that could be used but there is some parameters to tune to use it.

Eduardo gravatar imageEduardo ( 2015-11-09 04:57:24 -0600 )edit

@pklab Thanks for great answer,mate! But i have some problem with reproduce in Java version.

VeTaLio gravatar imageVeTaLio ( 2015-11-09 08:51:09 -0600 )edit

The code is plain... it's should be easy to translate in Java, may be you sould use ArrayList instead of std::vector@theodore , @VeTaLio thanks for apreciation ... if it works you could accept the answer ;=)

pklab gravatar imagepklab ( 2015-11-09 09:28:42 -0600 )edit

@pklab yes,that is not a big problem. Ill mark your question as solution,but little bit later,ok:) ? So have some questions about how to reproduce in java,because some stuff doesn't clear for me :(!

VeTaLio gravatar imageVeTaLio ( 2015-11-11 02:19:00 -0600 )edit

@VeTaLio you could do it yourself in Java... it's a simple exercise, feel free to ask about stuffs doesn't clear for you

pklab gravatar imagepklab ( 2015-11-11 06:15:46 -0600 )edit

@pklab as i understand you correct,that wingsCutPercent i need to put manually(as you said,1% => 0.01f value or i need to extract) ? Also,i got a problem,when i'm doing picture,converting via BitmapToMat,my source Mat have type CV_8UC4. So i didn't use your block of code if /else if(where you put CvtColor). I'm doing this directly => CvtColor(source,gray, CV_BGR2GRAY); and the problem occurs here: calcHist - first elemnt,in java there is arraylist of Mat. So via converters i'm trying to convert into ArrayList<mat> and i getting this exception :
java.lang.IllegalArgumentException: CvType.CV_32SC2 != m.type() || m.cols()!=1 I need to convert this for CvType.CV_32SC2?

VeTaLio gravatar imageVeTaLio ( 2015-11-13 08:47:13 -0600 )edit

@pklab once i ask this question and didn't get answer => my old post http://answers.opencv.org/question/74... is similiar problem with Converters! Thanks!!!

VeTaLio gravatar imageVeTaLio ( 2015-11-13 08:49:30 -0600 )edit

OK, 2nd edit...check new code, it supports BGRA images too. wingsCutPercent (now clipHistPercent) is a percent than if you want to cut 1% use 1.0. Howhever it's optional.

pklab gravatar imagepklab ( 2015-11-13 10:22:46 -0600 )edit

@pklab so i've translated to java and problem is that i'm getting too much brightness and contrast. I will upload some example to show you.

VeTaLio gravatar imageVeTaLio ( 2015-11-16 07:45:41 -0600 )edit
0

answered 2020-05-14 11:47:29 -0600

zgormez gravatar image

for python users, here two functions create the same result.

autoAdjustments_with_convertScaleAbs() works very, very fast

def autoAdjustments_with_convertScaleAbs(img):
alow = img.min()
ahigh = img.max()
amax = 255
amin = 0

# calculate alpha, beta
alpha = ((amax - amin) / (ahigh - alow))
beta = amin - alow * alpha
# perform the operation g(x,y)= α * f(x,y)+ β
new_img = cv2.convertScaleAbs(img, alpha=alpha, beta=beta)

return [new_img, alpha, beta]

def autoAdjustments(img):
    # create new image with the same size and type as the original image
    new_img = np.zeros(img.shape, img.dtype)

    # calculate stats
    alow = img.min()
    ahigh = img.max()
    amax = 255
    amin = 0

    # access each pixel, and auto adjust
    for x in range(img.shape[1]):
        for y in range(img.shape[0]):
            a = img[x, y]
            new_img[x, y] = amin + (a - alow) * ((amax - amin) / (ahigh - alow))

    return new_img

edit flag offensive delete link more
-1

answered 2017-03-28 07:10:06 -0600

WiVM gravatar image

Does anyone has been able to convert this to C# or VB.NET? I am having a hard time getting this converted.

edit flag offensive delete link more

Question Tools

8 followers

Stats

Asked: 2015-11-06 02:15:04 -0600

Seen: 55,751 times

Last updated: Nov 17 '15