Code covered by the BSD License  

Highlights from
Colormix

image thumbnail

Colormix

by

 

Combine basic colors with string syntax to create any RGB color.

colormix(CLRSTR,MODE)
function CLR = colormix(CLRSTR,MODE)
% COLORMIX - Combine basic colors with string syntax to create an RGB color 
% 
% CLR = colormix(CLRSTR)
% Convert string CLRSTR with standard MATLAB RGB shorthands to
% an RGB vector. Combines multiple colors, defaults to linear combination.
% I.e returns the mathematical 'average' color.
% 
% CLR = colormix(CLRSTR,MODE)
% Combines colors based on mixing mode MODE. MODE can be 'lincomb' for 
% linear combination, 'add' for additive light mixing (normalized), or 
% 'sub' for subtractive "paint" colormixing.
% See note below.
%
% Available colors: r,g,b,c,m,y,k,w  (Caps insensitive)
%
%--- Usage Example:
% CLR = colormix('ckkr')
% Creates a 1x3 vector CLR describing a color that is one part cyan, 
% two parts black and one part red.
% Alternatively put an integer before the color to specify the amount.
% CLR = colormix('c2kr') is equivalent to the above example.
%
%--- Example 2:
% CLR = colormix('by','sub')
% Produces black: [0 0 0] in the subtractive model, because blue and yellow 
% are compliments of eachother. 
% Similarly, CLR = colormix('by','add') produces white [1 1 1].
%
%------
% Note: Linear is distinct from additve or subtractive color mixing.
% It is similar to subtractive in that adding blacks and low intensity 
% colors lowers total luminosity. It is similar to additive in how 
% combining colors can never make blacks, only desaturating grays.
%
% E.g. 'rc' would be [1 0 0] + [0 1 1] = [1 1 1] for additive
% and [0 0 0] for subtractive. Linear combination gives [0.5 0.5 0.5].
%
% 'rrc' would be [2 1 1] (or [1 0.5 0.5] when normalized) for additive.
% Subtractive gives [0.33 0 0], linear is [0.66 0.33 0.33].
%
% 'rrgb' = [2 1 1] or [0.25 0 0], linear is [0.5 0.25 0.25].


assert(ischar(CLRSTR),...
    'Incorrect input, require a character array as first argument')

CLRSTR = lower(CLRSTR);

%--- Check if CLRSTR contains other characters
if ~all(ismember(CLRSTR,'1234567890rgbcmykw'))
    error('Input string CLRSTR contains illegal character(s)');
end

if nargin >1
    assert(ischar(MODE),...
         'Incorrect input, MODE must be lincomb, add or sub. See help.');
    MODE = lower(MODE);
else
    MODE = 'lincomb'; %default mode
end

%--- Check if using numbers:
if any(ismember(CLRSTR,'1234567890'))
    numbers = true;
else
    numbers = false;
end

%--- Count rgbcmykw occurences
R = 0+sum(ismember(CLRSTR,'r'));
G = 0+sum(ismember(CLRSTR,'g'));
B = 0+sum(ismember(CLRSTR,'b'));
C = 0+sum(ismember(CLRSTR,'c'));
M = 0+sum(ismember(CLRSTR,'m'));
Y = 0+sum(ismember(CLRSTR,'y'));
K = 0+sum(ismember(CLRSTR,'k'));
W = 0+sum(ismember(CLRSTR,'w'));

%--- Parse numbers
if numbers
    count   = zeros(8,1);
    values  = regexp(CLRSTR,'\d+.?','match'); %returns {'44k','2b','9r'} form
    for ii = 1:numel(values)
        input = values{ii};
        switch input(end)
            case 'r'
                count(1) = count(1)-1+ str2double(input(1:end-1));
            case 'g'
                count(2) = count(2)-1+str2double(input(1:end-1));
            case 'b'
                count(3) = count(3)-1+str2double(input(1:end-1));
            case 'c'
                count(4) = count(4)-1+str2double(input(1:end-1));
            case 'm'
                count(5) = count(5)-1+str2double(input(1:end-1));
            case 'y'
                count(6) = count(6)-1+str2double(input(1:end-1));
            case 'k'
                count(7) = count(7)-1+str2double(input(1:end-1));
            case 'w'
                count(8) = count(8)-1+str2double(input(1:end-1));
            otherwise
            error(['Number on the last position of CLRSTR?'...
                ' Or there is a bug in parsing numbers. Sorry!']);
        end
    end        
    R = R + count(1);
    G = G + count(2);
    B = B + count(3);
    C = C + count(4);
    M = M + count(5);
    Y = Y + count(6);
    K = K + count(7);
    W = W + count(8); 
end

%--- Calculate CLR
N   = sum([R G B C M Y K W]); %no. of mix components
CLR = cat(1,R*[1 0 0],...
    G*[0 1 0],...
    B*[0 0 1],...
    C*[0 1 1],...
    Y*[1 1 0],...
    M*[1 0 1],...
    K*[0 0 0],...
    W*[1 1 1]);

if strcmp(MODE,'lincomb')
    CLR = sum(CLR,1)/N;
elseif strcmp(MODE,'add')    
    CLR = sum(CLR,1);    
    CLR = CLR/max(CLR);
elseif strcmp(MODE,'sub')
    CLR = sum(CLR,1);
    CLR = (CLR - min(CLR))/N;      %basic color
    CLR = CLR + ([1 1 1] * W / N); %add whites
else
    error(['Unrecognized input for MODE,'...
        ' expect ''lincomb'', ''add'' or ''sub''.']);
end


%--- uint16 codes
%Numbers 0-9 are: 48-57 
%characters rgbcmykw are: 114,103,98,99,109,121,107,119

%--- Calculation examples
% subtractive mixing: I separate black first.
% 'rrg' = [0 -1 -1][0 -1 -1][-1 0 -1]
%       = [1 0 0][1 1 0][-1 -1 -1]
%       = [0.66 .33.0]
% 'yr'  = [0 0 -1][0 -1 -1] = [1 0.5 0]
%  Notice how mixing green and red produces a darker yellow, compared to 
%  using a pure yellow pigment.

% Additive mixing uses normalization to screen intensity (0-1).
% 'rrg' = [1 0 0][1 0 0][0 1 0] = [2 1 0] = [1 0.5 0]
% 'yr'  = [1 1 0][1 0 0] = [2 1 0] = [1 0.5 0]

% Linear workout:
% 'rrg' = [2 1 0]/3 = [0.66 0.33 0]
% 'yr'  = [2 1 0]/2 = [1 0.5 0]
% Distinct from subtractive in that lower luminosity is not due to 
% inclusion of blacks, but because of averaging over more colors.

Contact us