## Copyright (C) 2004 Josep Mones i Teixidor ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## ## ## Based on old imadjust.m (GPL): ## Copyright (C) 1999,2000 Kai Habel ## -*- texinfo -*- ## @deftypefn {Function File} @var{J}= imadjust (@var{I}) ## @deftypefnx {Function File} @var{J}= imadjust (@var{I},[@var{low_in};@var{high_in}]) ## @deftypefnx {Function File} @var{J}= imadjust (@var{I},[@var{low_in};@var{high_in}],[@var{low_out};@var{high_out}]) ## @deftypefnx {Function File} @var{J}= imadjust (..., @var{gamma}) ## @deftypefnx {Function File} @var{newmap}= imadjust (@var{map}, ...) ## @deftypefnx {Function File} @var{RGB_out}= imadjust (@var{RGB}, ...) ## Adjust image or colormap values to a specified range ## ## @code{J=imadjust(I)} adjusts intensity image @var{I} values so that ## 1% of data on lower and higher values (2% in total) of the image is ## saturated; choosing for that the corresponding lower and higher ## bounds (using @code{stretchlim}) and mapping them to 0 and 1. @var{J} ## is an image of the same size as @var{I} which contains mapped values. ## This is equivalent to @code{imadjust(I,stretchlim(I))}. ## ## @code{J=imadjust(I,[low_in;high_in])} behaves as described but uses ## @var{low_in} and @var{high_in} values instead of calculating them. It ## maps those values to 0 and 1; saturates values lower than first limit ## to 0 and values higher than second to 1; and finally maps all values ## between limits linearly to a value between 0 and 1. If @code{[]} is ## passes as @code{[low_in;high_in]} value, then @code{[0;1]} is taken ## as a default value. ## ## @code{J=imadjust(I,[low_in;high_in],[low_out;high_out])} behaves as ## described but maps output values between @var{low_out} and ## @var{high_out} instead of 0 and 1. A default value @code{[]} can also ## be used for this parameter, which is taken as @code{[0;1]}. ## ## @code{J=imadjust(...,gamma)} takes, in addition of 3 parameters ## explained above, an extra parameter @var{gamma}, which specifies the ## shape of the mapping curve between input elements and output ## elements, which is linear (as taken if this parameter is omitted). If ## @var{gamma} is above 1, then function is weighted towards lower ## values, and if below 1, towards higher values. ## ## @code{newmap=imadjust(map,...)} applies a transformation to a ## colormap @var{map}, which output is @var{newmap}. This transformation ## is the same as explained above, just using a map instead of an image. ## @var{low_in}, @var{high_in}, @var{low_out}, @var{high_out} and ## @var{gamma} can be scalars, in which case the same values are applied ## for all three color components of a map; or it can be 1-by-3 ## vectors, to define unique mappings for each component. ## ## @code{RGB_out=imadjust(RGB,...)} adjust RGB image @var{RGB} (a ## M-by-N-by-3 array) the same way as specified in images and colormaps. ## Here too @var{low_in}, @var{high_in}, @var{low_out}, @var{high_out} and ## @var{gamma} can be scalars or 1-by-3 matrices, to specify the same ## mapping for all planes, or unique mappings for each. ## ## The formula used to realize the mapping (if we omit saturation) is: ## ## @code{J = low_out + (high_out - low_out) .* ((I - low_in) / (high_in - low_in)) .^ gamma;} ## ## @strong{Compatibility notes:} ## ## @itemize @bullet ## @item ## Prior versions of imadjust allowed @code{[low_in; high_in]} and ## @code{[low_out; high_out]} to be row vectors. Compatibility with this ## behaviour has been keeped, although preferred form is vertical vector ## (since it extends nicely to 2-by-3 matrices for RGB images and ## colormaps). ## @item ## Previous version of imadjust, if @code{low_in>high_in} it "negated" output. ## Now it is negated if @code{low_out>high_out}, for compatibility with ## MATLAB. ## @item ## Class of @var{I} is not considered, so limit values are not ## modified depending on class of the image, just treated "as is". When ## Octave 2.1.58 is out, limits will be multiplied by 255 for uint8 ## images and by 65535 for uint16 as in MATLAB. ## @end itemize ## ## @end deftypefn ## @seealso{stretchlim, brighten} ## Author: Josep Mones i Teixidor ## TODO: When Octave 2.1.58 is out multiply indices if input argument is ## TODO: of class int* or uint*. function ret = imadjust (image, in, out, gamma) if (nargin < 1 || nargin > 4) usage ("imadjust(...) number of arguments must be between 1 and 4"); endif if (nargin < 4) gamma = 1; ## default gamma endif if !(ismatrix(image)) error ("imadjust(image,...) first parameter must be a image matrix or colormap"); endif if (nargin==1) in=stretchlim(image); ## this saturates 1% on lower and 1% on out=[0;1]; ## higher values endif if (nargin==2) out=[0;1]; ## default out endif if !((ismatrix(in) || isempty(in)) && (ismatrix(out) || isempty(out)) ) usage("imadjust(image,[low high],[bottom top],gamma)"); endif if (isempty(in)) in=[0;1]; ## default in endif if (isempty(out)) out=[0;1]; ## default out endif simage=size(image); if (length(simage)==3 && simage(3)==3) ## image is rgb [in, out, gamma]=__imadjust_check_3d_args__(in, out, gamma); ## make room ret=zeros(size(image)); ## process each plane for i=1:3 ret(:,:,i)=__imadjust_plane__(image(:,:,i),in(1,i),in(2,i),out(1,i),out(2,i),gamma(1,i)); endfor elseif (length(simage)==2) if(simage(2)==3 && \ (size(in)==[2,3] || size(out)==[2,3] || size(gamma)==[1,3]) ) ## image is a colormap [in, out, gamma]=__imadjust_check_3d_args__(in, out, gamma); ret=[]; ## process each color for i=1:3 ret=horzcat(ret,__imadjust_plane__(image(:,i),in(1,i),in(2,i),out(1,i),out(2,i),gamma(i))); endfor else ## image is a intensity image if( !isvector(in) || length(in)!=2 || !isvector(out) || length(out)!=2 || !isscalar(gamma) || (gamma<0) || (gamma==Inf) ) error("imadjust: on an intensity image, in and out must be 2-by-1 and gamma a positive scalar."); endif ret=__imadjust_plane__(image,in(1),in(2),out(1),out(2),gamma); endif else error("imadjust: first parameter must be a colormap, an intensity image or a RGB image"); endif endfunction ## This does all the work. I has a plane; li and hi input low and high ## values; and lo and ho, output bottom and top values. ## Image negative is computed if ho= li & I < hi) .* (lo + (ho - lo) .* ((I - li) / (hi - li)) .^ gamma); ret = ret + (I >= hi) .* ho; endfunction ## Checks in, out and gamma to see if they are ok for colormap and RGB ## cases. function [in, out, gamma]=__imadjust_check_3d_args__(in, out, gamma) switch(size(in)) case([2,3]) ## ok! case([2,1]) in=repmat(in,1,3); case([1,2]) ## Compatibility behaviour! in=repmat(in',1,3); otherwise error("imadjust: in must be 2-by-3 or 2-by-1."); endswitch switch(size(out)) case([2,3]) ## ok! case([2,1]) out=repmat(out,1,3); case([1,2]) ## Compatibility behaviour! out=repmat(out',1,3); otherwise error("imadjust: out must be 2-by-3 or 2-by-1."); endswitch switch(size(gamma)) case([1,3]) ## ok! case([1,1]) gamma=repmat(gamma,1,3); otherwise error("imadjust: gamma must be a scalar or a 1-by-3 matrix."); endswitch ## check gamma allowed range if(!all((gamma>=0)&(gamma