-
Notifications
You must be signed in to change notification settings - Fork 27
/
limo_STAPLE.m
146 lines (123 loc) · 4.83 KB
/
limo_STAPLE.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
function [W, p, q] = limo_STAPLE(varargin)
% This code is an adaptation of the original code to work directly with
% outputs from LIMO tools - Vecorized MATLAB implementation of the STAPLE
% algorithm by Warfield et al.
% Function: [W, p, q] = STAPLE(stat_files, threshold)
%
% IMPUT : stat_files is a cell array of statitical maps generated by LIMO
% threshold to apply to stat_files to get an estimated ground truth
% (0.5 by default)
%
% OUTPUT: W weight matrix for each voxel
% p vector of sensitivities for each expert
% q vector of specificities for each expert
% staple_mask, a binary image writen on the drive
%
% Reference: Warfield, Simon K., Kelly H. Zou, and William M. Wells.
% "Simultaneous truth and performance level estimation (STAPLE):
% an algorithm for the validation of image segmentation."
% Medical Imaging, IEEE Transactions on 23.7 (2004): 903-921.
%
% Original code edited by Cyril Pernet to work with EEG/LIMO results
% ------------------------------
% Copyright (C) LIMO Team 2020
%% check inputs
if nargin == 0
limo_STAPLE
return
else
stat_files = varargin{1};
if ~iscell(stat_files)
error('argument in must be a cell array of names')
end
if nargin == 1
threshold = 0.5;
else
threshold = varargin{2};
end
clear varargin
end
if nargin > 2
warn('more arguments in than needed??? only using arguments 1 and 2')
end
%% how many maps
if size(stat_files,1) == 1
stat_files=stat_files';
end
N = size(stat_files,1);
%% make the matrix DD (keep all clusters separate)
for map = N:-1:1
data = load(stat_files{map});
data = data.(cell2mat(fieldnames(data)));
nclusters(map) = max(data(:));
if map == 1
map_dim = size(data);
end
try
DD(:,N) = data(:);
catch load_err
error('couldn''t load map %g\n %s\n',map,load_err.message)
end
end
%% STAPLE-Algorithm by Warfield et al. for binary segementations
% --> Andreas Husch's code
%% Parameters
MAX_ITERATIONS = 30;
EPSILON = 0.00001; % convergence criterion
for cluster = max(nclusters):-1:1
D = double(DD==cluster);
% Initial sensitivity and specificity parameter p(j),q(j) for all
% raters j
p(1:N) = 0.99999;
q(1:N) = 0.99999;
Tprior = (sum(D(:))/length(D(:))); % note dependence on (sub)volume size, final result depends on this prior (which is not an implementation issue but a basic limitation of the EM approach)
avgW = 1;
W = zeros(1,length(D));
%% EM
for step=1:MAX_ITERATIONS
% E-Step
% The following vectorized code is equivalent to this loop by MUCH
% faster on current CPUs
% for i = 1:length(D)
% W(i) = ((prod(p(D(i,:))) * prod(1 - p(~D(i,:)))) * Tprior) / ...
% ((prod(p(D(i,:))) * prod(1 - p(~D(i,:)))) * Tprior + (prod(q(~D(i,:))) * prod(1 - q(D(i,:))))) * (1- Tprior) ;
% %NOTE that prod([]) = 1
% end
P = repmat(p,length(D), 1);
Q = repmat(q,length(D), 1);
P_given_D = P .* D; %TODO: use bsxfun instead of repmat?
P_given_D(P_given_D(:)== 0) = 1; %
Q_given_D = 1 - Q .* D;
Q_given_D(Q_given_D(:)== 0) = 1; % alternative: initialize with 1 and set Q_given_D(D) = 1- P(D)
compP_given_not_D = 1 - P .* ~D;
compP_given_not_D(compP_given_not_D(:)== 0) = 1;
compQ_given_not_D = Q .* ~D;
compQ_given_not_D(compQ_given_not_D(:)== 0) = 1;
% W(i) can be interpretated as the prob. of cell i beeing true (i.e. is part of the groundtruth y) for given p(1:N), q(1:N)
W = (prod(P_given_D') .* prod(compP_given_not_D') * Tprior) ./ ...
((prod(P_given_D') .* prod(compP_given_not_D') * Tprior) + (prod(Q_given_D') .* prod(compQ_given_not_D') * (1 - Tprior)));
% Convergence?
if(abs(avgW - sum(W) / length(W)) < EPSILON)
break;
end
avgW = sum(W) / length(W);
% M-Step
p = (W * D) / sum(W(:)); % W * D = sum(W(D))
q = ((1 - W) * ~D) / sum(1 - W(:));
end
%% write the result image
staple_wmap = reshape(W,map_dim);
save(fullfile(pwd,['staple_wmap_cluster' num2str(cluster) '.mat']),'staple_wmap')
staple_thmap = staple_wmap.*(staple_wmap>threshold/N);
save(fullfile(pwd,['staple_thmap_cluster' num2str(cluster) '.mat']),'staple_thmap')
staple_thmap(find(staple_thmap)) = cluster; % label cluster
if ndims(staple_thmap) == 2 %#ok<ISMAT>
all_maps(:,:,cluster) = staple_thmap;
else
all_maps(:,:,:,cluster) = staple_thmap;
end
end
staple_thmap = sum(all_maps,ndims(all_maps));
save(fullfile(pwd,'staple_thmap_labelled.mat'),'staple_thmap')
figure; imagesc(staple_thmap);
title('Binary STAPLE map')