Code covered by the BSD License  

Highlights from
Mat2gray variant with dimension option

image thumbnail

Mat2gray variant with dimension option

by

 

27 Nov 2012 (Updated )

Normalizes sections of an N-D matrix divided along DIM to the 0.0-1.0 range.

dim2gray(A,DIM,LIMS)
function B = dim2gray(A,DIM,LIMS)
%DIM2GRAY - Normalize N-dimensional array along a specified dimension.
%  B = DIM2GRAY(A,DIM,[LIMS])
%  Normalizes (i.e. scales values) in matrix A along the dimension DIM.
%  B has type double or single in the 0-1 range, and is the same size as A. 
%  DIM is an integer scalar--A is 'sliced' along DIM.
%  LIMS, optional, is a Nx2 vector of limits--where N == size(A,DIM). 
%  It specifies limits per dimensional slice, similar to mat2gray(A,LIMS).
%  Usage without LIMS defaults to min-max, like mat2gray(A), only  
%  dim2gray uses min-max limits per slice/chunk. Use NaN to specify a
%  min or max limit.
% 
%  Example: an HSV image
%  A = imread('peppers.png');
%  A = rgb2hsv(A);
%  B = dim2gray(A,3)
% 
%  Will linearly normalize every color plane to 0.0 & 1.0 based on the min
%  and max *per channel*. Equivalent to:
%  B = cat(3,mat2gray(A(:,:,1)),mat2gray(A(:,:,2)),mat2gray(A(:,:,3)));
% 
%  %This clips range at .1 and .9:
%  C = dim2gray(A,3,[0.1 0.9;0.1 0.9;0.1 0.9]) 
% 
%  Example 2: Multiple measurements of signal(e.g. voltage) over time
%  Let every row be a measurement(5) and every column a timepoint(32). 
%  DATA = rand(5,32);
%  dim2gray(DATA,2); %normalize every measurement to 0-1 range
%  dim2gray(DATA,1); %normalize every unique timepoint to 0-1 range

%~~~~Jurgen


%% Argument handling:
iptchecknargin(2,3,nargin,mfilename);
iptcheckinput(A,{'numeric'},{},mfilename,'A',1);
assert(DIM<=ndims(A),['Dimension ' DIM ' does not exist in A']);
assert(isscalar(DIM) && ~mod(DIM,1),'Incorrect input for DIM');
if strcmp(class(A),'single')
    type = 'single'; 
else
    type = 'double';
end

LDIM          = size(A,DIM); 

if (nargin==3)
    try
        assert(ndims(LIMS)==2 && isnumeric(LIMS)); %proper dims & type
        assert(all((size(LIMS) == [LDIM 2])));     %proper size
    catch
        error('Incorrect input for LIMS');
    end       
end


%% DIM2GRAY
%Slice A along DIM into submatrices:
B = slices(A,DIM); 
clear A

%Normalize chunks:
%(remember: imlincomb works with inf (1/0) inputs)
if nargin == 3; %use LIMS
    
    %replace NaNs
    idx = find(isnan(LIMS));    
    if ~isempty(idx) 
        cols  = logical(mod(idx,2));
        mindx = idx(cols); %1st col use min
        maxdx = idx(~cols);%2nd col use max   
        if any(mindx)
        for ii = mindx
            LIMS(ii) = min(B{round(ii/2)}(:));
        end
        end
        if any(maxdx)
        for ii = maxdx
            LIMS(ii) = max(B{round(ii/2)}(:));
        end
        end
    end
    
    delta = 1 ./ (LIMS(:,2) -  LIMS(:,1));   
    B     = arrayfun(@(X,Y,Z) imlincomb(X,Y{1},Z,type),delta,B(:),(-LIMS(:,1).*delta),'UniformOutput',false);
else
    lowlims = double(arrayfun(@(X) min(X{1}(:)),B));
    uplims  = double(arrayfun(@(X) max(X{1}(:)),B)); 
    delta   = 1 ./ (uplims -  lowlims);
    B       = arrayfun(@(X,Y,Z) imlincomb(X,Y{1},Z,type),delta,B,(-lowlims.*delta),'UniformOutput',false);
    %Hardly any speed gain when replacing arrayfuns with a for loop
    %Tested with tic/toc ii=100; dim2gray(peppers,3)
end

%Glue pieces back together:
B = cat(DIM,B{:});

%Make sure all values in B are between 0 and 1:
B = max(0,min(B,1));   


function cells = slices(A,DIM)
argument      = mat2cell(size(A),1,ones(1,ndims(A)));
argument{DIM} = ones(1,argument{DIM});
cells         = mat2cell(A,argument{:});       
%See also JEREMY R. MANNING's FEX submission (File ID: #35439)
%Uses eval based indexing to slice, same result, similar speed.

Contact us