|
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 |
|