function [im, map] = vmquantc( r, g, b, k, Q, dith, Qe )
%VMQUANTC Variance Minimization Color Quantization (MEX file)
%	VMQUANTC implements the color quantization algorithm for
%	the function VMQUANT.  It has the same syntax as VMQUANT.
%
%	Don't use this function directly, use VMQUANT or RGB2IND
%	instead.

%	Joseph M. Winograd 6-93
%	Copyright (c) 1993 by The MathWorks, Inc.
%	$Revision: 1.3 $  $Date: 1993/10/21 12:59:32 $

%	Reference: Xiaolin Wu, "Efficient Statistical Computation for
%	Optimal Color QUantization," Graphics Gems II, (ed. James
%	Arvo).  Academic Press: Boston. 1991.

%	 Data Structures:
%	P, M0, M1r, M1g, M1b, M2 are 3d matrices packed into 2d
%	form.  They are all three maps of the r, g, b color cube
%	where the i=1, j=1, k=1 planes are all outside the color
%	space (color population=0) to allow direct calculation
%	of statistics for r=0, g=0, b=0 planes.  Then, r,g,b=0:1
%	are mapped into i,j,k=2:Qx+1.

%	
%	 Inefficiencies:
%	Mean of each box is calculated during scan as well as for color mapping

%    Issues:
%	All colors in image are quantized to [Qr Qg Qb] bins and
%	color distortion is thereby introduced.  Turn the below
%	flag realmap on, and an unquantized color map will be generated
%	by calculating the mean of the population of each box,
%	at appreciable computational cost.
%
	realmap = 1;
%

error( nargchk( 3, 7, nargin ) );

if nargin < 6
    dith = 0;
end

if nargin < 5
    Qr = 33;
    Qg = 33;
    Qb = 33;
else
    Qr = 2^Q(1)+1;
    Qg = 2^Q(2)+1;
    Qb = 2^Q(3)+1;    
end

if nargin < 4
    k = 256;
else
    k = fix(k);
end

%    Quantize [R G B] to [Qr Qg Qb] levels.

bar = waitbar( 0, 'Performing color conversion...' );
rgbsize = [Qr Qg Qb];
rq = round( r * (Qr-2) + 2 );		% Map 0:1 onto 2:Qx+1
gq = round( g * (Qg-2) + 2 );
bq = round( b * (Qb-2) + 2 );
waitbar( 0.01 );

%    Calculate P(c).

[row col] = elem3d( rgbsize, rq, gq, bq );
P = sparse( row, col, 1, Qr*Qg, Qb );		
waitbar( .025 );

%    Calculate zeroth moment of P(c).

M0 = cumsum3d( rgbsize, P );

%    Calculate first moment of P(c). 
%    (Use three 3D vectors r, g, b to simulate a 4 dimensional space).

M1r = cumsum3d( rgbsize, reshape( cumsum( ones( Qr, Qg*Qb ) ), ...
	Qr*Qg, Qb ) .* P );

M1g = cumsum3d( rgbsize, reshape( cumsum( ones( Qg, Qr*Qb ) )', ...
	Qb, Qr*Qg )' .* P );

M1b = cumsum3d( rgbsize, cumsum( ones( Qb, Qr*Qg ) )' .* P );
waitbar( .05 );

%    Calculate second moment of P(c).

M2 = cumsum3d( rgbsize, (reshape( cumsum( ones( Qr, Qg*Qb ) ), ...
        Qr*Qg, Qb ) .^ 2 + reshape( cumsum( ones( Qg, ...
	Qr*Qb ) )', Qb, Qr*Qg )' .^ 2 + cumsum( ones( ...
	Qb, Qr*Qg ) )' .^ 2) .* P );
waitbar( .1 );

%    Find k-1 partition locations.

%	Initialize variables for first pass.

box = 1;
boxll = [1 1 1];
boxur = rgbsize;
E = zeros(k,1);
E(box) = sum( M2( elem3d( rgbsize, ...
            [boxll(box,1) boxll(box,1) boxur(box,1) boxur(box,1)], ...
            [boxll(box,2) boxur(box,2) boxll(box,2) boxur(box,2)], ...
            [boxur(box,3) boxll(box,3) boxll(box,3) boxur(box,3)] ) ) - ...
            M2( elem3d( rgbsize, ...
            [boxll(box,1) boxll(box,1) boxur(box,1) boxur(box,1)], ...
            [boxll(box,2) boxur(box,2) boxll(box,2) boxur(box,2)], ...
            [boxll(box,3) boxur(box,3) boxur(box,3) boxll(box,3)] ) ) );
wbox = sum( M0( elem3d( rgbsize, ...
            [boxll(box,1) boxll(box,1) boxur(box,1) boxur(box,1)], ...
            [boxll(box,2) boxur(box,2) boxll(box,2) boxur(box,2)], ...
            [boxur(box,3) boxll(box,3) boxll(box,3) boxur(box,3)] ) ) - ...
            M0( elem3d( rgbsize, ...
            [boxll(box,1) boxur(box,1) boxll(box,1) boxur(box,1)], ...
            [boxll(box,2) boxll(box,2) boxur(box,2) boxur(box,2)], ...
            [boxll(box,3) boxur(box,3) boxur(box,3) boxll(box,3)] ) ) );
M1box = [sum( M1r( elem3d( rgbsize, ...
                [boxll(box,1) boxur(box,1) boxll(box,1) boxur(box,1)], ...
                [boxur(box,2) boxll(box,2) boxll(box,2) boxur(box,2)], ...
                [boxll(box,3) boxll(box,3) boxur(box,3) boxur(box,3)] ) ) - ...
                M1r( elem3d( rgbsize, ...
                [boxll(box,1) boxur(box,1) boxll(box,1) boxur(box,1)], ...
                [boxll(box,2) boxur(box,2) boxur(box,2) boxll(box,2)], ...
                [boxll(box,3) boxll(box,3) boxur(box,3) boxur(box,3)] ) ) ) ...
                sum( M1g( elem3d( rgbsize, ...
                [boxll(box,1) boxur(box,1) boxll(box,1) boxur(box,1)], ...
                [boxur(box,2) boxll(box,2) boxll(box,2) boxur(box,2)], ...
                [boxll(box,3) boxll(box,3) boxur(box,3) boxur(box,3)] ) ) - ...
                M1g( elem3d( rgbsize, ...
                [boxll(box,1) boxur(box,1) boxll(box,1) boxur(box,1)], ...
                [boxll(box,2) boxur(box,2) boxur(box,2) boxll(box,2)], ...
                [boxll(box,3) boxll(box,3) boxur(box,3) boxur(box,3)] ) ) ) ...
                sum( M1b( elem3d( rgbsize, ...
                [boxll(box,1) boxur(box,1) boxll(box,1) boxur(box,1)], ...
                [boxur(box,2) boxll(box,2) boxll(box,2) boxur(box,2)], ...
                [boxll(box,3) boxll(box,3) boxur(box,3) boxur(box,3)] ) ) - ...
                M1b( elem3d( rgbsize, ...
                [boxll(box,1) boxur(box,1) boxll(box,1) boxur(box,1)], ...
                [boxll(box,2) boxur(box,2) boxur(box,2) boxll(box,2)], ...
                [boxll(box,3) boxll(box,3) boxur(box,3) boxur(box,3)] ) ) )];
E(box) = E(box) - (M1box * M1box') / wbox;

for color=1:k-1

%	Find the box with the greatest variance.

    [maxvar box] = max( E );

    if ~maxvar		% 	If no boxes have any variance than we're
	waitbar( .7 );	%	done.  (Thanks, Clay!)
	break;
    end

%	Find point of minimum variance in r dimension of box.

    M0base = sum( M0( elem3d( rgbsize, [boxll(box,1) boxll(box,1)], ...
	[boxll(box,2) boxur(box,2)], [boxur(box,3) boxll(box,3)] ) ) - ...
	M0( elem3d( rgbsize, [boxll(box,1) boxll(box,1)], ...
	[boxll(box,2) boxur(box,2)], [boxll(box,3) boxur(box,3)] ) ) );
    M1base = [sum( M1r( elem3d( rgbsize, [boxll(box,1) boxll(box,1)], ...
	    [boxll(box,2) boxur(box,2)], [boxur(box,3) boxll(box,3)] ) ) - ...
	    M1r( elem3d( rgbsize, [boxll(box,1) boxll(box,1)], ...
	    [boxll(box,2) boxur(box,2)], [boxll(box,3) boxur(box,3)] ) ) ) ...
	sum( M1g( elem3d( rgbsize, [boxll(box,1) boxll(box,1)], ...
	    [boxll(box,2) boxur(box,2)], [boxur(box,3) boxll(box,3)] ) ) - ...
	    M1g( elem3d( rgbsize, [boxll(box,1) boxll(box,1)], ...
	    [boxll(box,2) boxur(box,2)], [boxll(box,3) boxur(box,3)] ) ) ) ...
	sum( M1b( elem3d( rgbsize, [boxll(box,1) boxll(box,1)], ...
	    [boxll(box,2) boxur(box,2)], [boxur(box,3) boxll(box,3)] ) ) - ...
	    M1b( elem3d( rgbsize, [boxll(box,1) boxll(box,1)], ...
	    [boxll(box,2) boxur(box,2)], [boxll(box,3) boxur(box,3)] ) ) )];
    wbox = M0base + sum( M0( elem3d( rgbsize, [boxur(box,1) boxur(box,1)], ...
	[boxll(box,2) boxur(box,2)], [boxll(box,3) boxur(box,3)] ) ) - ...
	M0( elem3d( rgbsize, [boxur(box,1) boxur(box,1)], ...
	[boxll(box,2) boxur(box,2)], [boxur(box,3) boxll(box,3)] ) ) );
    M1box = M1base + ...
	[sum( M1r( elem3d( rgbsize, [boxur(box,1) boxur(box,1)], ...
            [boxll(box,2) boxur(box,2)], [boxll(box,3) boxur(box,3)] ) ) - ...
	    M1r( elem3d( rgbsize, [boxur(box,1) boxur(box,1)], ...
	    [boxll(box,2) boxur(box,2)], [boxur(box,3) boxll(box,3)] ) ) ) ...
	sum( M1g( elem3d( rgbsize, [boxur(box,1) boxur(box,1)], ...
	    [boxll(box,2) boxur(box,2)], [boxll(box,3) boxur(box,3)] ) ) - ...
	    M1g( elem3d( rgbsize, [boxur(box,1) boxur(box,1)], ...
	    [boxll(box,2) boxur(box,2)], [boxur(box,3) boxll(box,3)] ) ) ) ...
	sum( M1b( elem3d( rgbsize, [boxur(box,1) boxur(box,1)], ...
	    [boxll(box,2) boxur(box,2)], [boxll(box,3) boxur(box,3)] ) ) - ...
	    M1b( elem3d( rgbsize, [boxur(box,1) boxur(box,1)], ...
	    [boxll(box,2) boxur(box,2)], [boxur(box,3) boxll(box,3)] ) ) )];

    varr = zeros(1,boxur(box,1)-boxll(box,1)-1); % Allocate space for the array.
    for i=boxll(box,1)+1:boxur(box,1)-1
	wi = M0base + sum( M0( elem3d( rgbsize, [i i], ...
	    [boxll(box,2) boxur(box,2)], [boxll(box,3) boxur(box,3)] ) ) - ...
	    M0( elem3d( rgbsize, [i i], ...
	    [boxll(box,2) boxur(box,2)], [boxur(box,3) boxll(box,3)] ) ) );
	M1i = M1base + [sum( M1r( elem3d( rgbsize, [i i], ...
            [boxll(box,2) boxur(box,2)], [boxll(box,3) boxur(box,3)] ) ) - ...
            M1r( elem3d( rgbsize, [i i], ...
            [boxll(box,2) boxur(box,2)], [boxur(box,3) boxll(box,3)] ) ) ) ...
            sum( M1g( elem3d( rgbsize, [i i], ...
            [boxll(box,2) boxur(box,2)], [boxll(box,3) boxur(box,3)] ) ) - ...
            M1g( elem3d( rgbsize, [i i], ...
            [boxll(box,2) boxur(box,2)], [boxur(box,3) boxll(box,3)] ) ) ) ...
            sum( M1b( elem3d( rgbsize, [i i], ...
            [boxll(box,2) boxur(box,2)], [boxll(box,3) boxur(box,3)] ) ) - ...
            M1b( elem3d( rgbsize, [i i], ...
            [boxll(box,2) boxur(box,2)], [boxur(box,3) boxll(box,3)] ) ) )];
	vind = i - boxll(box,1);	% Inefficient to calc each time.
	if wi
	    varr(vind) = (M1i * M1i') / wi;
	end
	M1diff = M1box - M1i;
	wdiff = wbox - wi;
	if wdiff
	    varr(vind) = varr(vind) + (M1diff * M1diff') / wdiff;
	end
    end	% for i (red)
    if isempty(varr)
	varr = -1;
    end

%       Find point of minimum variance in g dimension of box.
 
    M0base = sum( M0( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
        [boxll(box,2) boxll(box,2)], [boxur(box,3) boxll(box,3)] ) ) - ...
        M0( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
        [boxll(box,2) boxll(box,2)], [boxll(box,3) boxur(box,3)] ) ) );
    M1base = [sum( M1r( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [boxll(box,2) boxll(box,2)], [boxur(box,3) boxll(box,3)] ) ) - ...
            M1r( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [boxll(box,2) boxll(box,2)], [boxll(box,3) boxur(box,3)] ) ) ) ...
        sum( M1g( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [boxll(box,2) boxll(box,2)], [boxur(box,3) boxll(box,3)] ) ) - ...
            M1g( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [boxll(box,2) boxll(box,2)], [boxll(box,3) boxur(box,3)] ) ) ) ...
        sum( M1b( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [boxll(box,2) boxll(box,2)], [boxur(box,3) boxll(box,3)] ) ) - ...
            M1b( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [boxll(box,2) boxll(box,2)], [boxll(box,3) boxur(box,3)] ) ) )];
 
    varg = zeros(1,boxur(box,2)-boxll(box,2)-1); % Allocate space for the array.
    for i=boxll(box,2)+1:boxur(box,2)-1
        wi = M0base + ...
	    sum( M0( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [i i], [boxll(box,3) boxur(box,3)] ) ) - ...
            M0( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [i i], [boxur(box,3) boxll(box,3)] ) ) );
        M1i = M1base + ...
	    [sum( M1r( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [i i], [boxll(box,3) boxur(box,3)] ) ) - ...
            M1r( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [i i], [boxur(box,3) boxll(box,3)] ) ) ) ...
            sum( M1g( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [i i], [boxll(box,3) boxur(box,3)] ) ) - ...
            M1g( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [i i], [boxur(box,3) boxll(box,3)] ) ) ) ...
            sum( M1b( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [i i], [boxll(box,3) boxur(box,3)] ) ) - ...
            M1b( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [i i], [boxur(box,3) boxll(box,3)] ) ) )];
	vind = i - boxll(box,2);	% Could just be updated...
	if wi
	    varg(vind) = (M1i * M1i') / wi;
	end
        M1diff = M1box - M1i;
	wdiff = wbox - wi;
	if wdiff
	    varg(vind) = varg(vind) + (M1diff * M1diff') / wdiff;
	end
    end % for i (green)
    if isempty(varg)
	varg = -1;
    end
 
%       Find point of minimum variance in b dimension of box.
 
    M0base = sum( M0( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
        [boxur(box,2) boxll(box,2)], [boxll(box,3) boxll(box,3)] ) ) - ...
        M0( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
        [boxll(box,2) boxur(box,2)], [boxll(box,3) boxll(box,3)] ) ) );
    M1base = [sum( M1r( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [boxur(box,2) boxll(box,2)], [boxll(box,3) boxll(box,3)] ) ) - ...
            M1r( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [boxll(box,2) boxur(box,2)], [boxll(box,3) boxll(box,3)] ) ) ) ...
        sum( M1g( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [boxur(box,2) boxll(box,2)], [boxll(box,3) boxll(box,3)] ) ) - ...
            M1g( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [boxll(box,2) boxur(box,2)], [boxll(box,3) boxll(box,3)] ) ) ) ...
        sum( M1b( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [boxur(box,2) boxll(box,2)], [boxll(box,3) boxll(box,3)] ) ) - ...
            M1b( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [boxll(box,2) boxur(box,2)], [boxll(box,3) boxll(box,3)] ) ) )];
 
    varb = zeros(1,boxur(box,3)-boxll(box,3)-1); % Allocate space for the array.
    for i=boxll(box,3)+1:boxur(box,3)-1
        wi = M0base + ...
	    sum( M0( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [boxll(box,2) boxur(box,2)], [i i] ) ) - ...
            M0( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [boxur(box,2) boxll(box,2)], [i i] ) ) );
        M1i = M1base + ...
	    [sum( M1r( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [boxll(box,2) boxur(box,2)], [i i] ) ) - ...
            M1r( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [boxur(box,2) boxll(box,2)], [i i] ) ) ) ...
            sum( M1g( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [boxll(box,2) boxur(box,2)], [i i] ) ) - ...
            M1g( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [boxur(box,2) boxll(box,2)], [i i] ) ) ) ...
            sum( M1b( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [boxll(box,2) boxur(box,2)], [i i] ) ) - ...
            M1b( elem3d( rgbsize, [boxll(box,1) boxur(box,1)], ...
            [boxur(box,2) boxll(box,2)], [i i] ) ) )];
	vind = i - boxll(box,3);	% Inefficient.
	if wi
	    varb(vind) = (M1i * M1i') / wi;
	end
        M1diff = M1box - M1i;
	wdiff = wbox - wi;
	if wdiff
	    varb(vind) = varb(vind) + (M1diff * M1diff') / wdiff;
	end
    end % for i (blue)
    if isempty(varb)
	varb = -1;
    end
 
%	Find the partition point with the minimum variance.

    [minvarr minindr] = max(varr);
    [minvarg minindg] = max(varg);
    [minvarb minindb] = max(varb);
    [minvar mindim] = max([minvarr minvarg minvarb]);

    boxr = size( boxll, 1 );
    if mindim == 1	% Cut in red dimension.
	minindr = minindr + boxll(box,1);
        if box == boxr
            boxll = [boxll(1:box,:); minindr boxll(box,2) boxll(box,3)];
	else
	    boxll = [boxll(1:box,:); minindr boxll(box,2) boxll(box,3); ...
		boxll(box+1:boxr,:)];
	    E(box+2:boxr+1) = E(box+1:boxr);	% Make space in E.
	end % if box == boxr
	boxur = [boxur(1:box-1,:); minindr boxur(box,2) boxur(box,3); ...
	    boxur(box:boxr,:)];
    elseif mindim == 2	% Cut in green dimension.
	minindg = minindg + boxll(box,2);
	if box == boxr
	    boxll = [boxll(1:box,:); boxll(box,1) minindg boxll(box,3)];
	else
	    boxll = [boxll(1:box,:); boxll(box,1) minindg boxll(box,3); ...
		boxll(box+1:boxr,:)];
	    E(box+2:boxr+1) = E(box+1:boxr);	% Make space in E.
	end % if box == boxr
	boxur = [boxur(1:box-1,:); boxur(box,1) minindg boxur(box,3); ...
	    boxur(box:boxr,:)];
    else 		% Cut in blue dimension.
	minindb = minindb + boxll(box,3);
	if box == boxr
	    boxll = [boxll(1:box,:); boxll(box,1) boxll(box,2) minindb];
	else
	    boxll = [boxll(1:box,:); boxll(box,1) boxll(box,2) minindb; ...
		boxll(box+1:boxr,:)];
	    E(box+2:boxr+1) = E(box+1:boxr);	% Make space in E.
	end % if box == boxr
	boxur = [boxur(1:box-1,:); boxur(box,1) boxur(box,2) minindb; ...
	    boxur(box:boxr,:)];
    end % if mindim

%       Compute variance of two new boxes.

    boxr = box;
    for box=boxr:boxr+1
      if sum(boxur(box,:)-boxll(box,:)) > 3     % Box can be subdivided.
        E(box) = sum( M2( elem3d( rgbsize, ...
            [boxll(box,1) boxll(box,1) boxur(box,1) boxur(box,1)], ...
            [boxll(box,2) boxur(box,2) boxll(box,2) boxur(box,2)], ...
            [boxur(box,3) boxll(box,3) boxll(box,3) boxur(box,3)] ) ) - ...
            M2( elem3d( rgbsize, ...
            [boxll(box,1) boxll(box,1) boxur(box,1) boxur(box,1)], ...
            [boxll(box,2) boxur(box,2) boxll(box,2) boxur(box,2)], ...
            [boxll(box,3) boxur(box,3) boxur(box,3) boxll(box,3)] ) ) );
        wbox = sum( M0( elem3d( rgbsize, ...
            [boxll(box,1) boxll(box,1) boxur(box,1) boxur(box,1)], ...
            [boxll(box,2) boxur(box,2) boxll(box,2) boxur(box,2)], ...
            [boxur(box,3) boxll(box,3) boxll(box,3) boxur(box,3)] ) ) - ...
            M0( elem3d( rgbsize, ...
            [boxll(box,1) boxur(box,1) boxll(box,1) boxur(box,1)], ...
            [boxll(box,2) boxll(box,2) boxur(box,2) boxur(box,2)], ...
            [boxll(box,3) boxur(box,3) boxur(box,3) boxll(box,3)] ) ) );
        if wbox
            M1box = [sum( M1r( elem3d( rgbsize, ...
                [boxll(box,1) boxur(box,1) boxll(box,1) boxur(box,1)], ...
                [boxur(box,2) boxll(box,2) boxll(box,2) boxur(box,2)], ...
                [boxll(box,3) boxll(box,3) boxur(box,3) boxur(box,3)] ) ) - ...
                M1r( elem3d( rgbsize, ...
                [boxll(box,1) boxur(box,1) boxll(box,1) boxur(box,1)], ...
                [boxll(box,2) boxur(box,2) boxur(box,2) boxll(box,2)], ...
                [boxll(box,3) boxll(box,3) boxur(box,3) boxur(box,3)] ) ) ) ...
                sum( M1g( elem3d( rgbsize, ...
                [boxll(box,1) boxur(box,1) boxll(box,1) boxur(box,1)], ...
                [boxur(box,2) boxll(box,2) boxll(box,2) boxur(box,2)], ...
                [boxll(box,3) boxll(box,3) boxur(box,3) boxur(box,3)] ) ) - ...
                M1g( elem3d( rgbsize, ...
                [boxll(box,1) boxur(box,1) boxll(box,1) boxur(box,1)], ...
                [boxll(box,2) boxur(box,2) boxur(box,2) boxll(box,2)], ...
                [boxll(box,3) boxll(box,3) boxur(box,3) boxur(box,3)] ) ) ) ...
                sum( M1b( elem3d( rgbsize, ...
                [boxll(box,1) boxur(box,1) boxll(box,1) boxur(box,1)], ...
                [boxur(box,2) boxll(box,2) boxll(box,2) boxur(box,2)], ...
                [boxll(box,3) boxll(box,3) boxur(box,3) boxur(box,3)] ) ) - ...
                M1b( elem3d( rgbsize, ...
                [boxll(box,1) boxur(box,1) boxll(box,1) boxur(box,1)], ...
                [boxll(box,2) boxur(box,2) boxur(box,2) boxll(box,2)], ...
                [boxll(box,3) boxll(box,3) boxur(box,3) boxur(box,3)] ) ) )];
            E(box) = E(box) - (M1box * M1box') / wbox;
        else
	    disp(['Warning(2): Box with no population was created.']);
	    E(box) = 0;
	end
      else      % Box cannot be subdivided.
        E(box) = 0;
      end
    end    % for box
    waitbar( .1 + .6 * color / (k-1) );
end 	% for color

%    Place each point in image into proper box.

%	Build map of color values on top of M2.
%	    and
%	Build matrix mapping rgb combo into boxes.

boxr = size( boxll, 1 );
map = zeros( boxr, 3 );
for box=1:boxr
  if ~realmap
    map(box,:) = [sum( M1r( elem3d( rgbsize, ...
	    [boxll(box,1) boxur(box,1) boxll(box,1) boxur(box,1)], ...
            [boxur(box,2) boxll(box,2) boxll(box,2) boxur(box,2)], ...
	    [boxll(box,3) boxll(box,3) boxur(box,3) boxur(box,3)] ) ) - ...
            M1r( elem3d( rgbsize, ...
	    [boxll(box,1) boxur(box,1) boxll(box,1) boxur(box,1)], ...
            [boxll(box,2) boxur(box,2) boxur(box,2) boxll(box,2)], ...
	    [boxll(box,3) boxll(box,3) boxur(box,3) boxur(box,3)] ) ) ) ...
        sum( M1g( elem3d( rgbsize, ...
	    [boxll(box,1) boxur(box,1) boxll(box,1) boxur(box,1)], ...
            [boxur(box,2) boxll(box,2) boxll(box,2) boxur(box,2)], ...
	    [boxll(box,3) boxll(box,3) boxur(box,3) boxur(box,3)] ) ) - ...
            M1g( elem3d( rgbsize, ...
	    [boxll(box,1) boxur(box,1) boxll(box,1) boxur(box,1)], ...
            [boxll(box,2) boxur(box,2) boxur(box,2) boxll(box,2)], ...
	    [boxll(box,3) boxll(box,3) boxur(box,3) boxur(box,3)] ) ) ) ...
        sum( M1b( elem3d( rgbsize, ...
	    [boxll(box,1) boxur(box,1) boxll(box,1) boxur(box,1)], ...
            [boxur(box,2) boxll(box,2) boxll(box,2) boxur(box,2)], ...
	    [boxll(box,3) boxll(box,3) boxur(box,3) boxur(box,3)] ) ) - ...
            M1b( elem3d( rgbsize, ...
	    [boxll(box,1) boxur(box,1) boxll(box,1) boxur(box,1)], ...
            [boxll(box,2) boxur(box,2) boxur(box,2) boxll(box,2)], ...
	    [boxll(box,3) boxll(box,3) boxur(box,3) boxur(box,3)] ) ) )] / ...
	sum( M0( elem3d( rgbsize, ...
            [boxll(box,1) boxll(box,1) boxur(box,1) boxur(box,1)], ...
            [boxll(box,2) boxur(box,2) boxll(box,2) boxur(box,2)], ...
            [boxur(box,3) boxll(box,3) boxll(box,3) boxur(box,3)] ) ) - ...
            M0( elem3d( rgbsize, ...
            [boxll(box,1) boxur(box,1) boxll(box,1) boxur(box,1)], ...
            [boxll(box,2) boxll(box,2) boxur(box,2) boxur(box,2)], ...
            [boxll(box,3) boxur(box,3) boxur(box,3) boxll(box,3)] ) ) );
  end
    indices = ndx3d( rgbsize, boxll(box,1)+1:boxur(box,1), ...
        boxll(box,2)+1:boxur(box,2), boxll(box,3)+1:boxur(box,3) );
    M2( indices ) =  box .* ones( size(indices) );
%   for gi=boxll(box,2)+1:boxur(box,2)
%	for bi=boxll(box,3)+1:boxur(box,3)
%	    [row col] = elem3d(rgbsize,boxll(box,1)+1:boxur(box,1),gi,bi);
%	    M2(row,col) = box .* ones(size(row))';
%	end
%   end
    waitbar( .7 + .35 * box / boxr );
end

%	Map each rgb triple into image.

if ~dith | realmap
   im = M2( elem3d( rgbsize, rq, gq, bq ) );
end

%	Rescale color map to 0-1 or calculate means of boxes for real colormap.

waitbar( 1 );

if ~realmap
    mapscale = rgbsize - 2; 	% Map 0 onto 1 for 1d or 2d color space.
    mapscale = mapscale + (mapscale == 0);	
    map = (map - 2) ./ mapscale(ones(boxr,1),:);	% Map 2:Qx+1 to 0:1
else
    for box=1:boxr
	indices = find( im == box );
	map(box,1) = sum( r( indices ) ) / length( indices );
	map(box,2) = sum( g( indices ) ) / length( indices );
	map(box,3) = sum( b( indices ) ) / length( indices );
    end % for box
end

if dith
    im = dither( r, g, b, map, max(Q), Qe );
end

close( bar );

