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