[Solved] How do I increase the contrast of an image in Python OpenCV

I am new to Python OpenCV. I have read some documents and answers here but I am unable to figure out what the following code means:

if (self.array_alpha is None):
    self.array_alpha = np.array([1.25])
    self.array_beta = np.array([-100.0])

# add a beta value to every pixel 
cv2.add(new_img, self.array_beta, new_img)                    

# multiply every pixel value by alpha
cv2.multiply(new_img, self.array_alpha, new_img)  

I have come to know that Basically, every pixel can be transformed as X = aY + b where a and b are scalars.. Basically, I have understood this. However, I did not understand the code and how to increase contrast with this.

Till now, I have managed to simply read the image using img = cv2.imread('image.jpg',0)

Thanks for your help

Enquirer: tsaebeht


Solution #1:

I would like to suggest a method using the LAB color channel. Wikipedia has enough information regarding what the LAB color channel is about.

I have done the following using OpenCV 3.0.0 and python:

import cv2

#-----Reading the image-----------------------------------------------------
img = cv2.imread('Dog.jpg', 1)

#-----Converting image to LAB Color model----------------------------------- 
lab= cv2.cvtColor(img, cv2.COLOR_BGR2LAB)

#-----Splitting the LAB image to different channels-------------------------
l, a, b = cv2.split(lab)
cv2.imshow('l_channel', l)
cv2.imshow('a_channel', a)
cv2.imshow('b_channel', b)

#-----Applying CLAHE to L-channel-------------------------------------------
clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8))
cl = clahe.apply(l)
cv2.imshow('CLAHE output', cl)

#-----Merge the CLAHE enhanced L-channel with the a and b channel-----------
limg = cv2.merge((cl,a,b))
cv2.imshow('limg', limg)

#-----Converting image from LAB Color model to RGB model--------------------
final = cv2.cvtColor(limg, cv2.COLOR_LAB2BGR)
cv2.imshow('final', final)


You can run the code as it is.
To know what CLAHE (Contrast Limited Adaptive Histogram Equalization)is about, you can again check Wikipedia.

Respondent: Jeru Luke

Solution #2:

For Python, I haven’t found an OpenCV function that provides contrast. As others have suggested, there are some techniques to automatically increase contrast using a very simple formula.

In the official OpenCV docs, it is suggested that this equation can be used to apply both contrast and brightness at the same time:

new_img = alpha*old_img + beta

where alpha corresponds to a contrast and beta is brightness. Different cases

alpha 1  beta 0      --> no change  
0 < alpha < 1        --> lower contrast  
alpha > 1            --> higher contrast  
-127 < beta < +127   --> good range for brightness values

In C/C++, you can implement this equation using cv::Mat::convertTo, but we don’t have access to that part of the library from Python. To do it in Python, I would recommend using the cv::addWeighted function, because it is quick and it automatically forces the output to be in the range 0 to 255 (e.g. for a 24 bit color image, 8 bits per channel). You could also use convertScaleAbs as suggested by @nathancy.

import cv2
img = cv2.imread('input.png')
# call addWeighted function. use beta = 0 to effectively only operate one one image
out = cv2.addWeighted( img, contrast, img, 0, brightness)
output = cv2.addWeighted

The above formula and code is quick to write and will make changes to brightness and contrast. But they yield results that are significantly different than photo editing programs. The rest of this answer will yield a result that will reproduce the behavior in the GIMP and also LibreOffice brightness and contrast. It’s more lines of code, but it gives a nice result.


In the GIMP, contrast levels go from -127 to +127. I adapted the formulas from here to fit in that range.

f = 131*(contrast + 127)/(127*(131-contrast))
new_image = f*(old_image – 127) + 127 = f*(old_image) + 127*(1-f)

To figure out brightness, I figured out the relationship between brightness and levels and used information in this levels post to arrive at a solution.

#pseudo code
if brightness > 0
    shadow = brightness
    highlight = 255
    shadow = 0
    highlight = 255 + brightness
new_img = ((highlight - shadow)/255)*old_img + shadow

brightness and contrast in Python and OpenCV

Putting it all together and adding using the reference “mandrill” image from USC SIPI:

import cv2
import numpy as np

# Open a typical 24 bit color image. For this kind of image there are
# 8 bits (0 to 255) per color channel
img = cv2.imread('mandrill.png')  # mandrill reference image from USC SIPI

s = 128
img = cv2.resize(img, (s,s), 0, 0, cv2.INTER_AREA)

def apply_brightness_contrast(input_img, brightness = 0, contrast = 0):
    if brightness != 0:
        if brightness > 0:
            shadow = brightness
            highlight = 255
            shadow = 0
            highlight = 255 + brightness
        alpha_b = (highlight - shadow)/255
        gamma_b = shadow
        buf = cv2.addWeighted(input_img, alpha_b, input_img, 0, gamma_b)
        buf = input_img.copy()
    if contrast != 0:
        f = 131*(contrast + 127)/(127*(131-contrast))
        alpha_c = f
        gamma_c = 127*(1-f)
        buf = cv2.addWeighted(buf, alpha_c, buf, 0, gamma_c)

    return buf

fcolor = (0,0,0)

blist = [0, -127, 127,   0,  0, 64] # list of brightness values
clist = [0,    0,   0, -64, 64, 64] # list of contrast values

out = np.zeros((s*2, s*3, 3), dtype = np.uint8)

for i, b in enumerate(blist):
    c = clist[i]
    print('b, c:  ', b,', ',c)
    row = s*int(i/3)
    col = s*(i%3)
    print('row, col:   ', row, ', ', col)
    out[row:row+s, col:col+s] = apply_brightness_contrast(img, b, c)
    msg = 'b %d' % b
    cv2.putText(out,msg,(col,row+s-22), font, .7, fcolor,1,cv2.LINE_AA)
    msg = 'c %d' % c
    cv2.putText(out,msg,(col,row+s-4), font, .7, fcolor,1,cv2.LINE_AA)
    cv2.putText(out, 'OpenCV',(260,30), font, 1.0, fcolor,2,cv2.LINE_AA)

cv2.imwrite('out.png', out)

enter image description here

I manually processed the images in the GIMP and added text tags in Python/OpenCV:
enter image description here

Note: @UtkarshBhardwaj has suggested that Python 2.x users must cast the contrast correction calculation code into float for getting floating result, like so:

if contrast != 0:
        f = float(131*(contrast + 127))/(127*(131-contrast))
Respondent: bfris

Solution #3:

Brightness and contrast can be adjusted using alpha (?) and beta (?), respectively. The expression can be written as

enter image description here

OpenCV already implements this as cv2.convertScaleAbs(), just provide user defined alpha and beta values

import cv2

image = cv2.imread('1.jpg')

alpha = 1.5 # Contrast control (1.0-3.0)
beta = 0 # Brightness control (0-100)

adjusted = cv2.convertScaleAbs(image, alpha=alpha, beta=beta)

cv2.imshow('original', image)
cv2.imshow('adjusted', adjusted)

Before -> After

enter image description here
enter image description here

Note: For automatic brightness/contrast adjustment take a look at automatic contrast and brightness adjustment of a color photo

Respondent: nathancy

Solution #4:

Best explanation for X = aY + b (in fact it f(x) = ax + b)) is provided at https://math.stackexchange.com/a/906280/357701

A Simpler one by just adjusting lightness/luma/brightness for contrast as is below:

import cv2

img = cv2.imread('test.jpg')
cv2.imshow('test', img)
imghsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

imghsv[:,:,2] = [[max(pixel - 25, 0) if pixel < 190 else min(pixel + 25, 255) for pixel in row] for row in imghsv[:,:,2]]
cv2.imshow('contrast', cv2.cvtColor(imghsv, cv2.COLOR_HSV2BGR))
Respondent: be_good_do_good

Solution #5:

img = cv2.imread("/x2.jpeg")

image = cv2.resize(img, (1800, 1800))


new_image=cv2.addWeighted(image,alpha,np.zeros(image.shape, image.dtype),0,beta)

Respondent: Coder

The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .

Leave a Reply

Your email address will not be published.