% TERNARYIMAGE  Perceptualy uniform ternary image from 3 bands of data
%
% Usage: rgbim = ternaryimage(im, bands, histcut, Rmap, Gmap, Bmap)
%
% Arguments
%              im - Multiband image with at least 3 bands, or a cell array of
%                   at least 3 images.
%           bands - Array of 3 values indicating the bands, to be assigned to
%                   the red, green and blue basis colour maps.  If omitted, or
%                   empty, bands defaults to [1 2 3].
%         histcut - Percentage of image band histograms to clip.  It can be
%                   useful to clip 1-2%. If you see lots of white in your
%                   ternary image you have clipped too much. Defaults to 0.
%        R/G/Bmap - Three basis colourmaps to be applied to the specified
%                   bands of the input image which are then summed to form
%                   the ternary image.  If omitted the colour maps default to
%                   those generated by TERNARYMAPS.  
%                   If Rmap is the string 'RGB' then the RGB primaries are
%                   used. This creates a 'classical' ternary image. (Though not
%                   very efficiently).
%
% Returns:  
%            rgbim - RGB ternary image
%
% The default colour maps obtained from TERNARYMAPS result in colours that are
% not as vivid as the RGB primaries but they produce perceptually uniform
% ternary images with consistent feature salience no matter what permutation of
% channel-colour assignement is used.
%
% For the derivation of the three primary colours used by TERNARYMAPS see:
%
% Peter Kovesi. Good Colour Maps: How to Design Them.
% arXiv:1509.03700 [cs.GR] 2015
% https://arxiv.org/abs/1509.03700
%
% See also: TERNARYMAPS, APPLYCOLOURMAP, LINEARRGBMAP

% Copyright (c) 2014 Peter Kovesi
% Centre for Exploration Targeting
% The University of Western Australia
% peter.kovesi at uwa edu au
% 
% Permission is hereby granted, free of charge, to any person obtaining a copy
% of this software and associated documentation files (the "Software"), to deal
% in the Software without restriction, subject to the following conditions:
% 
% The above copyright notice and this permission notice shall be included in 
% all copies or substantial portions of the Software.
%
% The Software is provided "as is", without warranty of any kind.

function rgbim = ternaryimage(im, bands, histcut, Rmap, Gmap, Bmap)
    
    if ~exist('bands', 'var') || isempty(bands), bands = [1 2 3]; end
    if ~exist('histcut', 'var'), histcut = 0; end    
    if ~exist('Rmap', 'var'), [Rmap, Gmap, Bmap] = ternarymaps;   end
    if strcmpi(Rmap, 'RGB')
        Rmap = linearrgbmap([1 0 0]);
        Gmap = linearrgbmap([0 1 0]);
        Bmap = linearrgbmap([0 0 1]);
    end

    if iscell(im)
    
        if max(bands) > length(im)
            error('Band specification outside image range');
        end
        
        if histcut
            rgbim = applycolourmap(histtruncate(im{bands(1)}, histcut), Rmap) + ...
                    applycolourmap(histtruncate(im{bands(2)}, histcut), Gmap) + ...
                    applycolourmap(histtruncate(im{bands(3)}, histcut), Bmap);
        else
            rgbim = applycolourmap(im{bands(1)}, Rmap) + ...
                    applycolourmap(im{bands(2)}, Gmap) + ...
                    applycolourmap(im{bands(3)}, Bmap); 
        end
    else
        
        if max(bands) > size(im,3)
            error('Band specification outside image range');
        end
        
        if histcut
            rgbim = applycolourmap(histtruncate(im(:,:,bands(1)), histcut), Rmap) + ...
                    applycolourmap(histtruncate(im(:,:,bands(2)), histcut), Gmap) + ...
                    applycolourmap(histtruncate(im(:,:,bands(3)), histcut), Bmap);
        else
            rgbim = applycolourmap(im(:,:,bands(1)), Rmap) + ...
                    applycolourmap(im(:,:,bands(2)), Gmap) + ...
                    applycolourmap(im(:,:,bands(3)), Bmap);
        end
    end