I am looking for the formula (and its explanation) that gives the perceived color resulting from a quincunx arrangement of two other colors. The result is obviously not linear, because if I create an image with alternated RGB colors #E00000 (red) and #0000E0 (blue), and compare it with the mathematical average #700070, I see a big difference on the rendering.
On the image below, the left part is composed with #E00000 and #0000E0 colors, while the right is only #700070:
I know there is a solution, because when I use GIMP to unzoom the dithered part, it magically continues to show the exact color I feel, but this time with an effective RGB code, which is #980098. This conversion is also made by the scaling feature when I select the "linear" algorithm... (Well, am I wrong, or despite its name it does not produces linearity at all?)
On the image below, the left part has still no purple in its pixels, whereas the right part is the #980098 purple:
At least under my screen, if I don't look too carefully this image, it looks like a single purple band with no variation.
So what is the formula, and why? How to mathematically get this #980098 from #E00000 and #0000E0?
It looks like the following conversion procedure is applied:
Computing the average in Linear RGB color space gives better perceived output, compared to computing the average in sRGB color space.
That is because the gamma correction (used with sRGB) makes sRGB color space non-linear.
I thought that computing the average in LAB color space supposed to give better results, but at least for the given example, Linear RGB result looks better.
MATLAB code sample (note that your input sample is #0000D0
and not #0000E0
):
% Create the dithering sample - used as reference
I = zeros(100, 100, 3, 'uint8');
I(1:2:end, 1:2:end, 1) = hex2dec('D0'); % Red
I(2:2:end, 2:2:end, 1) = hex2dec('D0'); % Red
I(1:2:end, 2:2:end, 3) = hex2dec('D0'); % Blue
I(2:2:end, 1:2:end, 3) = hex2dec('D0'); % Blue
figure;imshow(I);impixelinfo % Show I for testing
% Convert the red and blue values from sRGB to linear RGB
lin_red = rgb2lin(im2double(uint8([hex2dec('D0'), 0, 0]))); % #D00000
lin_blue = rgb2lin(im2double(uint8([0, 0, hex2dec('D0')]))); % #0000D0
% Compute the average in Linear RGB color space
average_lin_lab = (lin_red + lin_blue) / 2;
% Convert from Linear RGB to sRGB
average_rgb = im2uint8(lin2rgb(average_lin_lab)); % [152 0 152] = #980098
% Fill J matrix with the average color in sRGB color space
J = zeros(100, 100, 3, 'uint8');
J(:, :, 1) = average_rgb(1); % Red color channel
J(:, :, 2) = average_rgb(2); % Green color channel
J(:, :, 3) = average_rgb(3); % Blue color channel
figure;imshow(J);impixelinfo % Show the result for testing
The RGB values of J
are exactly #980098.