Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I do the equivalent of Gimp's Colors, Auto, White Balance in Python-Fu?

the only function I can find is : gimp-color-balance, which takes the applicable parameters : preserve-lum(osity), cyan-red, magenta-green, and yellow-blue.

I'm not sure what values to pass for these parameters to duplicate the menu option in the title.

like image 461
Bryan Dunphy Avatar asked Jan 15 '18 17:01

Bryan Dunphy


2 Answers

To complete the answer of @banderlog013, I think the Gimp Doc specifies that the end pixels of each channel are first discarded, then the remaining ranges are stretched. I believe the right code is :

img = cv2.imread('test.jpg')
balanced_img = np.zeros_like(img) #Initialize final image

for i in range(3): #i stands for the channel index 
    hist, bins = np.histogram(img[..., i].ravel(), 256, (0, 256))
    bmin = np.min(np.where(hist>(hist.sum()*0.0005)))
    bmax = np.max(np.where(hist>(hist.sum()*0.0005)))
    balanced_img[...,i] = np.clip(img[...,i], bmin, bmax)
    balanced_img[...,i] = (balanced_img[...,i]-bmin) / (bmax - bmin) * 255

I obtain good results with it, try it out !

like image 79
Canette Ouverture Avatar answered Nov 02 '22 06:11

Canette Ouverture


According to GIMP doc, we need to discard pixel colors at each end of the Red, Green and Blue histograms which are used by only 0.05% of the pixels in the image and stretch the remaining range as much as possible (Python code):

import numpy as np
import cv2  # opencv-python
import matplotlib.pyplot as plt


img = cv2.imread('test.jpg')
x = []
# get histogram for each channel
for i in cv2.split(img):
    hist, bins = np.histogram(i, 256, (0, 256))
    # discard colors at each end of the histogram which are used by only 0.05% 
    tmp = np.where(hist > hist.sum() * 0.0005)[0]
    i_min = tmp.min()
    i_max = tmp.max()
    # stretch hist
    tmp = (i.astype(np.int32) - i_min) / (i_max - i_min) * 255
    tmp = np.clip(tmp, 0, 255)
    x.append(tmp.astype(np.uint8))

# combine image back and show it
s = np.dstack(x)
plt.imshow(s[::,::,::-1])

The result is pretty the same as after GIMP's 'Colors -> Auto -> White Balance'

UPD: we need np.clip() because OpenCV and numpy differently casts int32 to uint8:

# Numpy
np.array([-10, 260]).astype(np.uint8)
>>> array([246,   4], dtype=uint8)
# but we need just [0, 255]
like image 38
banderlog013 Avatar answered Nov 02 '22 07:11

banderlog013