I have been trying to implement the white balancing algorithms provided by: https://pippin.gimp.org/image-processing/chapter-automaticadjustments.html
I have used python and opencv to implement them. I am unable to produce the same results as in the website.
In grayworld assumption, for example, i use the following code:
import cv2 as cv
import numpy as np
def show(final):
print 'display'
cv.imshow("Temple", final)
cv.waitKey(0)
cv.destroyAllWindows()
def saveimg(final):
print 'saving'
cv.imwrite("result.jpg", final)
# Insert any filename with path
img = cv.imread("grayworld_assumption_0.png")
res = img
final = cv.cvtColor(res, cv.COLOR_BGR2LAB)
avg_a = -np.average(final[:,:,1])
avg_b = -np.average(final[:,:,2])
for x in range(final.shape[0]):
for y in range(final.shape[1]):
l,a,b = final[x][y]
shift_a = avg_a * (l/100.0) * 1.1
shift_b = avg_b * (l/100.0) * 1.1
final[x][y][1] = a + shift_a
final[x][y][2] = b + shift_b
final = cv.cvtColor(final, cv.COLOR_LAB2BGR)
final = np.hstack((res, final))
show(final)
saveimg(final)
I am getting the result
instead of
Where am I going wrong?
In auto white balance mode, your camera examines the scene you're trying to photograph and chooses a color temperature (in Kelvin) it thinks will work best. However, your camera can easily get confused if the scene: Doesn't contain any colors which are white, or close to white.
White balance (WB) is the process of removing unrealistic color casts, so that objects which appear white in person are rendered white in your photo. Proper camera white balance has to take into account the "color temperature" of a light source, which refers to the relative warmth or coolness of white light.
In film photography, color balance is typically achieved by using color correction filters over the lights or on the camera lens.
The goal of IRGB intensity balance is to correct the intensity of a color image without modifying the R/G/B ratio of the pixels. We first compute the gray level intensity (I = (R + G + B)/3), then this intensity is balanced and transformed into I by the affine transformation with saturation.
The document you are implementing is not aware of CV internal conventions for LAB definition in case of 8-bit color depth.
In particular:
L: L / 100 * 255
A: A + 128
B: B + 128
I believe this is done for improved accuracy, because then one could use unsigned int8
precision in full for the luminosity while keeping a consistent unsigned data type for the whole array.
The code below, adapted from yours should work.
Note that there are some minor fixes here and there (EDIT including wrapping up the interesting code in a function), but the actual sauce is within the nested for
loop.
from __future__ import (
division, absolute_import, print_function, unicode_literals)
import cv2 as cv
import numpy as np
def show(final):
print('display')
cv.imshow('Temple', final)
cv.waitKey(0)
cv.destroyAllWindows()
# Insert any filename with path
img = cv.imread('grayworld_assumption_0.png')
def white_balance_loops(img):
result = cv.cvtColor(img, cv.COLOR_BGR2LAB)
avg_a = np.average(result[:, :, 1])
avg_b = np.average(result[:, :, 2])
for x in range(result.shape[0]):
for y in range(result.shape[1]):
l, a, b = result[x, y, :]
# fix for CV correction
l *= 100 / 255.0
result[x, y, 1] = a - ((avg_a - 128) * (l / 100.0) * 1.1)
result[x, y, 2] = b - ((avg_b - 128) * (l / 100.0) * 1.1)
result = cv.cvtColor(result, cv.COLOR_LAB2BGR)
return result
final = np.hstack((img, white_balance_loops(img)))
show(final)
cv.imwrite('result.jpg', final)
The same result, but with much faster performances can be obtained by avoiding loops:
def white_balance(img):
result = cv.cvtColor(img, cv.COLOR_BGR2LAB)
avg_a = np.average(result[:, :, 1])
avg_b = np.average(result[:, :, 2])
result[:, :, 1] = result[:, :, 1] - ((avg_a - 128) * (result[:, :, 0] / 255.0) * 1.1)
result[:, :, 2] = result[:, :, 2] - ((avg_b - 128) * (result[:, :, 0] / 255.0) * 1.1)
result = cv.cvtColor(result, cv.COLOR_LAB2BGR)
return result
which obviously gives the same result:
print(np.all(white_balance(img) == white_balance_loops(img)))
True
but with very different timings:
%timeit white_balance(img)
100 loops, best of 3: 2 ms per loop
%timeit white_balance_loops(img)
1 loop, best of 3: 529 ms per loop
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With