Switch to unified view

a b/combinedDeepLearningActiveContour/functions/otsu.m
1
function [IDX,sep] = otsu(I,n)
2
3
%OTSU Global image thresholding/segmentation using Otsu's method.
4
%   IDX = OTSU(I,N) segments the image I into N classes by means of Otsu's
5
%   N-thresholding method. OTSU returns an array IDX containing the cluster
6
%   indices (from 1 to N) of each point. Zero values are assigned to
7
%   non-finite (NaN or Inf) pixels.
8
%
9
%   IDX = OTSU(I) uses two classes (N=2, default value).
10
%
11
%   [IDX,sep] = OTSU(...) also returns the value (sep) of the separability
12
%   criterion within the range [0 1]. Zero is obtained only with data
13
%   having less than N values, whereas one (optimal value) is obtained only
14
%   with N-valued arrays.
15
%
16
%   Notes:
17
%   -----
18
%   It should be noticed that the thresholds generally become less credible
19
%   as the number of classes (N) to be separated increases (see Otsu's
20
%   paper for more details).
21
%
22
%   If I is an RGB image, a Karhunen-Loeve transform is first performed on
23
%   the three R,G,B channels. The segmentation is then carried out on the
24
%   image component that contains most of the energy.
25
%
26
%   Example:
27
%   -------
28
%   load clown
29
%   subplot(221)
30
%   X = ind2rgb(X,map);
31
%   imshow(X)
32
%   title('Original','FontWeight','bold')
33
%   for n = 2:4
34
%     IDX = otsu(X,n);
35
%     subplot(2,2,n)
36
%     imagesc(IDX), axis image off
37
%     title(['n = ' int2str(n)],'FontWeight','bold')
38
%   end
39
%   colormap(gray)
40
%
41
%   Reference:
42
%   ---------
43
%   Otsu N, <a href="matlab:web('http://dx.doi.org/doi:10.1109/TSMC.1979.4310076')">A Threshold Selection Method from Gray-Level Histograms</a>,
44
%   IEEE Trans. Syst. Man Cybern. 9:62-66;1979
45
%
46
%   See also GRAYTHRESH, IM2BW
47
%
48
%   -- Damien Garcia -- 2007/08, revised 2010/03
49
%   Visit my <a
50
%   href="matlab:web('http://www.biomecardio.com/matlab/otsu.html')">website</a> for more details about OTSU
51
52
error(nargchk(1,2,nargin))
53
54
% Check if is the input is an RGB image
55
isRGB = isrgb(I);
56
57
assert(isRGB | ndims(I)==2,...
58
    'The input must be a 2-D array or an RGB image.')
59
60
%% Checking n (number of classes)
61
if nargin==1
62
    n = 2;
63
elseif n==1;
64
    IDX = NaN(size(I));
65
    sep = 0;
66
    return
67
elseif n~=abs(round(n)) || n==0
68
    error('MATLAB:otsu:WrongNValue',...
69
        'n must be a strictly positive integer!')
70
elseif n>255
71
    n = 255;
72
    warning('MATLAB:otsu:TooHighN',...
73
        'n is too high. n value has been changed to 255.')
74
end
75
76
I = single(I);
77
78
%% Perform a KLT if isRGB, and keep the component of highest energy
79
if isRGB
80
    sizI = size(I);
81
    I = reshape(I,[],3);
82
    [V,D] = eig(cov(I));
83
    [tmp,c] = max(diag(D));
84
    I = reshape(I*V(:,c),sizI(1:2)); % component with the highest energy
85
end
86
87
%% Convert to 256 levels
88
I = I-min(I(:));
89
I = round(I/max(I(:))*255);
90
91
%% Probability distribution
92
unI = sort(unique(I));
93
nbins = min(length(unI),256);
94
if nbins==n
95
    IDX = ones(size(I));
96
    for i = 1:n, IDX(I==unI(i)) = i; end
97
    sep = 1;
98
    return
99
elseif nbins<n
100
    IDX = NaN(size(I));
101
    sep = 0;
102
    return
103
elseif nbins<256
104
    [histo,pixval] = hist(I(:),unI);
105
else
106
    [histo,pixval] = hist(I(:),256);
107
end
108
P = histo/sum(histo);
109
clear unI
110
111
%% Zeroth- and first-order cumulative moments
112
w = cumsum(P);
113
mu = cumsum((1:nbins).*P);
114
115
%% Maximal sigmaB^2 and Segmented image
116
if n==2
117
    sigma2B =...
118
        (mu(end)*w(2:end-1)-mu(2:end-1)).^2./w(2:end-1)./(1-w(2:end-1));
119
    [maxsig,k] = max(sigma2B);
120
    
121
    % segmented image
122
    IDX = ones(size(I));
123
    IDX(I>pixval(k+1)) = 2;
124
    
125
    % separability criterion
126
    sep = maxsig/sum(((1:nbins)-mu(end)).^2.*P);
127
    
128
elseif n==3
129
    w0 = w;
130
    w2 = fliplr(cumsum(fliplr(P)));
131
    [w0,w2] = ndgrid(w0,w2);
132
    
133
    mu0 = mu./w;
134
    mu2 = fliplr(cumsum(fliplr((1:nbins).*P))./cumsum(fliplr(P)));
135
    [mu0,mu2] = ndgrid(mu0,mu2);
136
    
137
    w1 = 1-w0-w2;
138
    w1(w1<=0) = NaN;
139
    
140
    sigma2B =...
141
        w0.*(mu0-mu(end)).^2 + w2.*(mu2-mu(end)).^2 +...
142
        (w0.*(mu0-mu(end)) + w2.*(mu2-mu(end))).^2./w1;
143
    sigma2B(isnan(sigma2B)) = 0; % zeroing if k1 >= k2
144
    
145
    [maxsig,k] = max(sigma2B(:));
146
    [k1,k2] = ind2sub([nbins nbins],k);
147
    
148
    % segmented image
149
    IDX = ones(size(I))*3;
150
    IDX(I<=pixval(k1)) = 1;
151
    IDX(I>pixval(k1) & I<=pixval(k2)) = 2;
152
    
153
    % separability criterion
154
    sep = maxsig/sum(((1:nbins)-mu(end)).^2.*P);
155
    
156
else
157
    k0 = linspace(0,1,n+1); k0 = k0(2:n);
158
    [k,y] = fminsearch(@sig_func,k0,optimset('TolX',1));
159
    k = round(k*(nbins-1)+1);
160
    
161
    % segmented image
162
    IDX = ones(size(I))*n;
163
    IDX(I<=pixval(k(1))) = 1;
164
    for i = 1:n-2
165
        IDX(I>pixval(k(i)) & I<=pixval(k(i+1))) = i+1;
166
    end
167
    
168
    % separability criterion
169
    sep = 1-y;
170
    
171
end
172
173
IDX(~isfinite(I)) = 0;
174
175
%% Function to be minimized if n>=4
176
    function y = sig_func(k)
177
        
178
        muT = sum((1:nbins).*P);
179
        sigma2T = sum(((1:nbins)-muT).^2.*P);
180
        
181
        k = round(k*(nbins-1)+1);
182
        k = sort(k);
183
        if any(k<1 | k>nbins), y = 1; return, end
184
        
185
        k = [0 k nbins];
186
        sigma2B = 0;
187
        for j = 1:n
188
            wj = sum(P(k(j)+1:k(j+1)));
189
            if wj==0, y = 1; return, end
190
            muj = sum((k(j)+1:k(j+1)).*P(k(j)+1:k(j+1)))/wj;
191
            sigma2B = sigma2B + wj*(muj-muT)^2;
192
        end
193
        y = 1-sigma2B/sigma2T; % within the range [0 1]
194
        
195
    end
196
197
end
198
199
function isRGB = isrgb(A)
200
% --- Do we have an RGB image?
201
% RGB images can be only uint8, uint16, single, or double
202
isRGB = ndims(A)==3 && (isfloat(A) || isa(A,'uint8') || isa(A,'uint16'));
203
% ---- Adapted from the obsolete function ISRGB ----
204
if isRGB && isfloat(A)
205
    % At first, just test a small chunk to get a possible quick negative
206
    mm = size(A,1);
207
    nn = size(A,2);
208
    chunk = A(1:min(mm,10),1:min(nn,10),:);
209
    isRGB = (min(chunk(:))>=0 && max(chunk(:))<=1);
210
    % If the chunk is an RGB image, test the whole image
211
    if isRGB, isRGB = (min(A(:))>=0 && max(A(:))<=1); end
212
end
213
end
214