]> Creatis software - CreaPhase.git/blob - octave_packages/image-1.0.15/stretchlim.m
Add a useful package (from Source forge) for octave
[CreaPhase.git] / octave_packages / image-1.0.15 / stretchlim.m
1 ## Copyright (C) 2004 Josep Mones i Teixidor
2 ##
3 ## This program is free software; you can redistribute it and/or modify
4 ## it under the terms of the GNU General Public License as published by
5 ## the Free Software Foundation; either version 2 of the License, or
6 ## (at your option) any later version.
7 ##
8 ## This program is distributed in the hope that it will be useful,
9 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
10 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 ## GNU General Public License for more details.
12 ##
13 ## You should have received a copy of the GNU General Public License
14 ## along with this program; If not, see <http://www.gnu.org/licenses/>.
15
16 ## -*- texinfo -*-
17 ## @deftypefn {Function File} {@var{LOW_HIGH} = } stretchlim (@var{I},@var{TOL})
18 ## @deftypefnx {Function File} {@var{LOW_HIGH} = } stretchlim (@var{I})
19 ## @deftypefnx {Function File} {@var{LOW_HIGH} = } stretchlim (@var{RGB},@var{TOL})
20 ## @deftypefnx {Function File} {@var{LOW_HIGH} = } stretchlim (@var{RGB})
21 ## Finds limits to contrast stretch an image
22 ##
23 ## @code{LOW_HIGH=stretchlim(I,TOL)} returns a vector @var{LOW_HIGH}
24 ## which contains a pair of intensities which can be used in
25 ## @code{imadjust} to stretch the contrast of an image, first of them
26 ## will be lower value (@code{imadjust} would assign 0 to it) and second
27 ## is the upper bound. @var{TOL} specifies the fraction of the image to
28 ## saturate at lower and upper limits. It can be a vector of length 2:
29 ## @code{[LOW_FRACT, HIGH_FRACT]}, or it can be a scalar, in that case
30 ## @code{[LOW_FRACT, HIGH_FRACT]=[TOL, 1-TOL]}.
31 ##
32 ## @var{TOL} can't be larger than 0.50 and for TOL=0 then
33 ## @code{LOW_HIGH=[min(I(:)), max(I(:))]}.
34 ##
35 ## @code{LOW_HIGH=stretchlim(I)} behaves as described but defaults
36 ## @var{TOL} to @code{[0.01, 0.99]}.
37 ##
38 ## @code{LOW_HIGH=stretchlim(RGB,TOL)} returns a 2-by-3 matrix in
39 ## @var{LOW_HIGH} of lower and upper values to saturate for each plane
40 ## of the RGB image in M-by-N-by-3 array @var{RGB}. @var{TOL} is a
41 ## vector or a scalar, as described above, and the same fractions are
42 ## applied for each plane.
43 ##
44 ## @code{LOW_HIGH=stretchlim(RGB)} uses @code{[0.01, 0.99]} as default
45 ## value for @var{TOL}.
46 ##
47 ## @strong{Notes:}
48 ##
49 ## Values in @var{LOW_HIGH} are of type double and comprised between 0
50 ## and 1 regardless class of input image.
51 ##
52 ## @strong{Compatibility notes:}
53 ##
54 ## @itemize @bullet
55 ## @item
56 ## int* and uint* types are still not implemented (waiting for support
57 ## in Octave 2.1.58).
58 ## @item
59 ## This function tries to find limits that are nearer to saturate
60 ## requested interval. So, for instance, if you requested a 5% and it
61 ## has to choose between discarding a 1% and a 7%, it will choose the
62 ## later despite being more than requested. This should be test against
63 ## MATLAB behaviour.
64 ## @end itemize
65 ##
66 ## @seealso{imadjust}
67 ## @end deftypefn
68
69 ## Author:  Josep Mones i Teixidor <jmones@puntbarra.com>
70
71 function LOW_HIGH = stretchlim(image, TOL)
72   if (nargin<1 || nargin>2)
73     usage("LOW_HIGH=stretchlim(I [, TOL]), LOW_HIGH=stretchlim(RGB [, TOL])");
74   endif
75   
76   if(!ismatrix(image) || ischar(image))
77     error("stretchlim: image should be a matrix");
78   endif
79   
80   ## Prepare limits
81   if(nargin==1)
82     low_count=0.01;
83     high_count=0.01;                ## we use this definition in __stretchlim_plane__
84   else
85     if(isscalar(TOL))
86       if(TOL<0 || TOL>=0.5)
87         error("stretchlim: TOL out of bounds. Expected: 0<=TOL<0.5");
88       endif
89       low_count=TOL;
90       high_count=TOL;               ## as before...
91     elseif(isvector(TOL))
92       if(length(TOL)!=2)
93         error("stretchlim: TOL length must be 2.");
94       endif
95       low_count=TOL(1);
96       high_count=1-TOL(2);          ## as before...
97     else
98       error("stretchlim: TOL contains an invalid value.");
99     endif
100   endif
101
102   ## well use size of image several times...
103   simage=size(image);
104
105   ## Convert fractions to pixels
106   psimage=prod(simage(1:2));
107   low_count*=psimage;
108   high_count*=psimage;
109          
110   if(length(simage)<=2)
111     ## intensity
112     LOW_HIGH=__stretchlim_plane__(image, low_count, high_count);
113   elseif(length(simage)==3 && simage(3)==3)
114     ## RGB
115     LOW_HIGH=zeros(2,3);
116     for i=1:3
117       LOW_HIGH(:,i)=__stretchlim_plane__(image(:,:,i), low_count, \
118                                          high_count);
119     endfor
120   else
121     error("stretchlim: invalid image.");
122   endif
123 endfunction
124
125
126 ## Processes a plane
127 ## high_count is defined so that high_count=elements is the same as
128 ## low_count=elements (and not total_elements-elements)
129 function LOW_HIGH = __stretchlim_plane__(plane, low_count, high_count)
130   ## check exceptions
131   if(low_count==0 && high_count==0)
132     LOW_HIGH=[min(plane(:)); max(plane(:))];
133   else
134
135     ## we sort values
136     sorted=sort(plane(:));
137     
138     low=sorted(round(low_count+1));
139     pos=find(sorted>low);
140     if(length(pos)>0)
141       low2=sorted(pos(1));
142       d1=low_count-sum(sorted<low);
143       d2=sum(sorted<low2)-low_count;
144       if(d2<d1)
145         low=low2;
146       endif
147     endif
148       
149     high=sorted(end-round(high_count));
150     pos=find(sorted<high);
151     if(length(pos)>0)
152       high2=sorted(pos(end));
153       d1=high_count-sum(sorted>high);
154       d2=sum(sorted>high2)-high_count;
155       if(d2<d1)
156         high=high2;
157       endif
158     endif
159
160     ## set result variable
161     LOW_HIGH=[low;high];
162   endif
163 endfunction
164
165 %!demo
166 %! stretchlim([1:100])
167 %! # This discards 1% of data from each end, 1 and 100.
168 %! # So result should be [2;99]
169
170 %!# some invalid params
171 %!error(stretchlim());
172 %!error(stretchlim("bad parameter"));
173 %!error(stretchlim(zeros(10,10,4)));
174 %!error(stretchlim(zeros(10,10,3,2)));
175 %!error(stretchlim(zeros(10,10),"bad parameter"));
176 %!error(stretchlim(zeros(10,10),0.01,2));
177
178
179 %!# default param
180 %!assert(stretchlim([1:100]),[2;99]);
181
182 %!# scalar TOL
183 %!assert(stretchlim([1:100],0.01),[2;99]);
184
185 %!# vector TOL
186 %!assert(stretchlim([1:100],[0.01,0.98]),[2;98]);
187
188 %!# TOL=0
189 %!assert(stretchlim([1:100],0),[1;100]);
190
191 %!# non uniform histogram tests
192 %!assert(stretchlim([1,ones(1,90)*2,92:100],0.05),[2;95]);
193 %!assert(stretchlim([1,ones(1,4)*2,6:100],0.05),[6;95]);
194
195 %!# test limit rounding...
196 %!assert(stretchlim([1,ones(1,5)*2,7:100],0.05),[7;95]); # 6% lost 
197 %!assert(stretchlim([1,ones(1,6)*2,8:100],0.05),[8;95]); # 7% lost
198 %!assert(stretchlim([1,ones(1,7)*2,9:100],0.05),[9;95]); # 8% lost
199 %!assert(stretchlim([1,ones(1,8)*2,10:100],0.05),[2;95]); # now he limit at 2 => 1% lost
200
201 %!# test RGB
202 %!test
203 %! RGB=zeros(100,1,3);
204 %! RGB(:,:,1)=[1:100];
205 %! RGB(:,:,2)=[2:2:200];
206 %! RGB(:,:,3)=[4:4:400];
207 %! assert(stretchlim(RGB),[2,4,8;99,198,396]);
208