Home > database >  Brighten only dark areas of image in python
Brighten only dark areas of image in python

Time:05-20

I am trying to process images and I would like to brighten the dark areas of my image. I tried Histogram Equalization, however as there are also some bright areas in the image, the result is not satisfying. This is why I am looking for a way to brighten only the dark areas of the image.

As an example, Input image is on the left and the expected result is on the right, the hair and face of the girl are brightened

Input Image Brightened Image

ImageMagick seems to offer some possibilities to achieve this, however, I would like to do it using python

CodePudding user response:

If you want to avoid colour distortions, you could:

  • convert to HSV colourspace,
  • split the channels,
  • bump up the V (Value) channel
  • recombine the channels
  • save

That might go something like this:

from PIL import Image

# Open the image
im = Image.open('hEHxh.jpg')

# Convert to HSV colourspace and split channels for ease of separate processing
H, S, V = im.convert('HSV').split()

# Increase the brightness, or Value channel
# Change 30 to 50 for bigger effect, or 10 for smaller effect
newV = V.point(lambda i: i   int(30*(255-i)/255))

# Recombine channels and convert back to RGB
res = Image.merge(mode="HSV", bands=(H,S,newV)).convert('RGB')

res.save('result.jpg')

enter image description here

Essentially, I am changing the brightness from the black mapping to the green mapping:

enter image description here


Reminder to forgetful self... "you made the plot like this, Mark":

import matplotlib.pyplot as plt
import numpy as np

# Generate some straight-line data
xdata = np.arange(0,256)
# And the new mapping
ydata = xdata   30*(255-xdata)/255

# Plot
plt.plot(xdata,xdata,'.k')
plt.plot(xdata,ydata,'g^')
plt.title('Adjustment of V')
plt.xlabel('Input V')
plt.ylabel('Output V')
plt.grid(True)
plt.show()

CodePudding user response:

Here is one way to do that in Imagemagick and Python/OpenCV. Threshold the L channel of LAB colorspace using triangle method. Then brighten the whole image. Then merge the original and brightened image using the threshold as a mask.

Imagemagick:

magick girl_on_chair.jpg \
\( -clone 0 -colorspace LAB -channel 0 -separate  channel \
-auto-threshold triangle -negate  write thresh.png \) \
\( -clone 0 -evaluate multiply 4 \) \
 swap -compose over -composite \
girl_on_chair_processed.jpg

Threshold:

enter image description here

Result:

enter image description here

Python/OpenCV:

import cv2
import numpy as np

# read image
img = cv2.imread("girl_on_chair.jpg")

# convert to LAB and extract L  channel
LAB = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
L = LAB[:,:,0]

# threshold L channel with triangle method
value, thresh = cv2.threshold(L, 0, 255, cv2.THRESH_BINARY cv2.THRESH_TRIANGLE)
print(value)

# threshold with adjusted value
value = value   10
thresh = cv2.threshold(L, value, 255, cv2.THRESH_BINARY)[1]

# invert threshold and make 3 channels
thresh = 255 - thresh
thresh = cv2.merge([thresh, thresh, thresh])

gain = 3
blue = cv2.multiply(img[:,:,0], gain)
green = cv2.multiply(img[:,:,1], gain)
red = cv2.multiply(img[:,:,2], gain)
img_bright = cv2.merge([blue, green, red])

# blend original and brightened using thresh as mask
result = np.where(thresh==255, img_bright, img)

# save result
cv2.imwrite('girl_on_chair_thresh.jpg', thresh)
cv2.imwrite('girl_on_chair_brighten.jpg', result)

cv2.imshow('img', img)
cv2.imshow('L', L)
cv2.imshow('thresh', thresh)
cv2.imshow('img_bright', img_bright)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

Threshold:

enter image description here

Result:

enter image description here

CodePudding user response:

Here is how you can accomplish that with just the cv2 module:

import cv2

def lighten(img, value=30):
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    v = hsv[..., 2]
    v[:] = cv2.add(v, value)
    return cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)

img = cv2.imread("image.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
mask = cv2.threshold(gray, 175, 255, cv2.THRESH_BINARY)[1] == 0
img[mask] = lighten(img)[mask]
cv2.imshow("result", img)
cv2.waitKey(0)

Input Image and Output Image:

enter image description here enter image description here

CodePudding user response:

An alternate way to do this in Imagemagick is to use -fx to threshold and increase brightness using the L channel of LAB or the Y channel of YCbCr or the V channel of HSV by adding a constant value where that channel is less than some threshold.

(Note: In -fx, images such asu vary from 0 to 1 in range.)

magick girl_on_chair.jpg \
-colorspace LAB -separate \
\( -clone 0 -fx "u<0.15?u 0.15:u" \) \
-swap 0,3  delete \
-set colorspace LAB -combine -colorspace sRGB \
girl_on_chair_proc2.jpg

magick girl_on_chair.jpg \
-colorspace YCBCR -separate \
\( -clone 0 -fx "u<0.15?u 0.15:u" \) \
-swap 0,3  delete \
-set colorspace YCBCR -combine -colorspace sRGB \
girl_on_chair_proc3.jpg

magick girl_on_chair.jpg \
-colorspace HSV -separate \
\( -clone 2 -fx "u<0.15?u 0.15:u" \) \
 swap  delete \
-set colorspace HSV -combine -colorspace sRGB \
girl_on_chair_proc4.jpg

LAB Result:

enter image description here

YCbCr Result:

enter image description here

HSV Result:

enter image description here

Similar processing can be done using Python/OpenCV.

  • Related