Saptarshi Saptarshi - 1 month ago 12
Python Question

Automatic White Balancing with Grayworld assumption

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?

Answer Source

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, but the actual sauce 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')
final = cv.cvtColor(img, 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, :]
        # fix for CV correction
        l *= 100 / 255.0
        final[x, y, 1] = a - ((avg_a - 128) * (l / 100.0) * 1.1)
        final[x, y, 2] = b - ((avg_b - 128) * (l / 100.0) * 1.1)

final = cv.cvtColor(final, cv.COLOR_LAB2BGR)
final = np.hstack((img, final))

show(final)
cv.imwrite('result.jpg', final)