How to achieve White Balance using OpenCV JS based on Python Reference

Hello!

I’m very new to OpenCV and currently using OpenCVJS in one of my projects.
So far, I am able to convert the python and c++ references I see online to JS. However, I am stuck with trying to apply white balance to an image.

For the C++ there is a white balancer method here but unfortunately there is none in JS.

I have used this reference in trying to replicate this to JS but I have no progress:
Reference 1

Here is my code:

let src = cv.imread(canvasId);
let imageRGB = new cv.MatVector();
let dst = new cv.Mat();

cv.split(src, imageRGB);

let b = imageRGB.get(0);
let g = imageRGB.get(1);
let r = imageRGB.get(2);

const b_avg = cv.mean(b)[0];
const g_avg = cv.mean(g)[0];
const r_avg = cv.mean(r)[0];

let k = (r_avg + g_avg + b_avg) / 3;
let kr = k / r_avg;
let kg = k / g_avg;
let kb = k / b_avg;

// for this part, i am not sure of. I do not know how to manipulate the channel data based 
// on the calculations made above
let row = 3, col = 4;
r.data[row * r.cols * r.channels() + col * r.channels() + kr];
g.data[row * g.cols * b.channels() + col * b.channels() + kg];
b.data[row * b.cols * b.channels() + col * b.channels() + kb];

// I am also not sure how to merge back the indivudual channels back into imageRGB 
// since calling cv.merge([b,g,r]) will result to an error based on the JS documentation. It 
// needs 2 parameters to work.
imageRGB.push_back(b);
imageRGB.push_back(g);
imageRGB.push_back(r);

cv.merge(imageRGB,src);

// throws an error since this needs a cv.Mat type, but I do not know how to utilize dst in this
cv.imshow('outputCanvas', imageRGB);

src.delete();
imageRGB.delete();
dst.delete();

Thank you for your patience. I would appreciate any help from this. JS related concerns are not as abundant as Python and C++ :slightly_frowning_face:

you really should use the “vectorized” version of that python code (see the edit to the answer there), not write loops at all !

let src = cv.imread('canvasInput');

let lab = new cv.Mat();
cv.cvtColor(src, lab, cv.COLOR_RGB2Lab);

let chan = new cv.MatVector();
cv.split(lab, chan);
let L = chan.get(0);
let A = chan.get(1);
let B = chan.get(2);

let ma = cv.mean(A)[0];
let mb = cv.mean(B)[0];
A = A - ((ma - 128.0) * (L / 255.0) * 1.1);
B = B - ((mb - 128.0) * (L / 255.0) * 1.1);
cv.merge(chan, lab);

let dst = new cv.Mat();
cv.cvtColor(lab, dst, cv.COLOR_Lab2RGB);
cv.imshow('canvasOutput', dst);

Hello!

Thank you very much for your response! I have made some progress with this!

Unfortunately, I am stuck at this part of the code:

A = A - ((ma - 128.0) * (L / 255.0) * 1.1);
B = B - ((mb - 128.0) * (L / 255.0) * 1.1);

I am not sure how to manipulate the values of the A and B Mats in Javascript since I get these errors.

“Type ‘number’ is not assignable to type ‘Mat’”
“The left-hand side of an arithmetic operation must be of type ‘any’, ‘number’, ‘bigint’ or an enum type”

I did try this, but it didn’t do anything:

chan.get(1).data[A.data - ((ma - 128.0) * (L.data / 255.0) * 1.1)]
chan.get(2).data[B.data - ((ma - 128.0) * (L.data / 255.0) * 1.1)]

I’ve checked the official docs on how to manipulate pixel values here but I’m finding it hard to understand as a beginner :disappointed:

Thank you again for your patience!

*Edit: It seems that regular operations are not applicable to OpenCV JS. I have found the following operations but they require 2 Mats for src1 and src2

cv.add( src1, src2, dst)
cv.multiply( src1, src2, dst)
cv.divide( src1, src2, dst)
cv.subtract( src1, src2, dst)