forked from fieldtrip/fieldtrip
/
ft_prepare_localspheres.m
195 lines (165 loc) · 6.25 KB
/
ft_prepare_localspheres.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
function [headmodel, cfg] = ft_prepare_localspheres(cfg, mri)
% FT_PREPARE_LOCALSPHERES is deprecated, please use FT_PREPARE_HEADMODEL and
% FT_PREPARE_MESH
%
% See also FT_PREPARE_HEADMODEL
% Copyright (C) 2005-2006, Jan-Mathijs Schoffelen & Robert Oostenveld
%
% This file is part of FieldTrip, see http://www.ru.nl/neuroimaging/fieldtrip
% for the documentation and details.
%
% FieldTrip is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% FieldTrip is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id$
warning('FT_PREPARE_LOCALSPHERES is deprecated, please use FT_PREPARE_HEADMODEL with cfg.method = ''localspheres'' instead.')
revision = '$Id$';
% do the general setup of the function
ft_defaults
ft_preamble init
ft_preamble provenance
ft_preamble trackconfig
ft_preamble debug
ft_preamble loadvar mri
% the abort variable is set to true or false in ft_preamble_init
if abort
return
end
% check if the input cfg is valid for this function
cfg = ft_checkconfig(cfg, 'renamed', {'spheremesh', 'numvertices'});
% set the defaults
if ~isfield(cfg, 'radius'), cfg.radius = 8.5; end
if ~isfield(cfg, 'maxradius'), cfg.maxradius = 20; end
if ~isfield(cfg, 'baseline'), cfg.baseline = 5; end
if ~isfield(cfg, 'feedback'), cfg.feedback = 'yes'; end
if ~isfield(cfg, 'smooth'); cfg.smooth = 5; end % in voxels
if ~isfield(cfg, 'threshold'), cfg.threshold = 0.5; end % relative
if ~isfield(cfg, 'numvertices'), cfg.numvertices = []; end
if ~isfield(cfg, 'singlesphere'), cfg.singlesphere = 'no'; end
if ~isfield(cfg, 'headshape'), cfg.headshape = []; end
hasmri = exist('mri', 'var'); % note that nargin will not work in case of cfg.inputfile
if hasmri
headshape = ft_prepare_mesh(cfg, mri);
elseif isfield(cfg,'headshape') && nargin == 1
if ischar(cfg.headshape)
headshape = ft_read_headshape(cfg.headshape);
else
headshape = cfg.headshape;
end
else
error('no head shape available')
end
% read the gradiometer definition from file or copy it from the configuration
if isfield(cfg, 'gradfile')
grad = ft_read_sens(cfg.gradfile);
else
grad = cfg.grad;
end
Nshape = size(headshape.pnt,1);
Nchan = size(grad.tra, 1);
% set up an empty figure
if strcmp(cfg.feedback, 'yes')
clf
hold on
axis equal
axis vis3d
axis off
drawnow
end
% plot all channels and headshape points
if strcmp(cfg.feedback, 'yes')
cla
ft_plot_sens(grad);
ft_plot_mesh(headshape, 'vertexcolor', 'g', 'facecolor', 'none', 'edgecolor', 'none');
drawnow
end
% fit a single sphere to all headshape points
[single_o, single_r] = fitsphere(headshape.pnt);
fprintf('single sphere, %5d surface points, center = [%4.1f %4.1f %4.1f], radius = %4.1f\n', Nshape, single_o(1), single_o(2), single_o(3), single_r);
headmodel = [];
if strcmp(cfg.singlesphere, 'yes')
% only return a single sphere
headmodel.r = single_r;
headmodel.o = single_o;
return;
end
% start with an empty structure that will hold the results
headmodel.r = zeros(Nchan,1); % radius of every sphere
headmodel.o = zeros(Nchan,3); % origin of every sphere
headmodel.label = cell(Nchan,1); % corresponding gradiometer channel label for every sphere
for chan=1:Nchan
coilsel = find(grad.tra(chan,:)~=0);
allpnt = grad.coilpos(coilsel, :); % position of all coils belonging to this channel
allori = grad.coilori(coilsel, :); % orientation of all coils belonging to this channel
if strcmp(cfg.feedback, 'yes')
cla
plot3(grad.coilpos(:,1), grad.coilpos(:,2), grad.coilpos(:,3), 'b.'); % all coils
plot3(allpnt(:,1), allpnt(:,2), allpnt(:,3), 'r*'); % this channel in red
end
% determine the average position and orientation of this channel
thispnt = mean(allpnt,1);
[u, s, v] = svd(allori);
thisori = v(:,1)';
if dot(thispnt,thisori)<0
% the orientation should be outwards pointing
thisori = -thisori;
end
% compute the distance from every coil along this channels orientation
dist = zeros(size(coilsel));
for i=1:length(coilsel)
dist(i) = dot((allpnt(i,:)-thispnt), thisori);
end
[m, i] = min(dist);
% check whether the minimum difference is larger than a typical distance
if abs(m)>(cfg.baseline/4)
% replace the position of this channel by the coil that is the closest to the head (axial gradiometer)
% except when the center of the channel is approximately just as good (planar gradiometer)
thispnt = allpnt(i,:);
end
% find the headshape points that are close to this channel
dist = sqrt(sum((headshape.pnt-repmat(thispnt,Nshape,1)).^2, 2));
shapesel = find(dist<cfg.radius);
if strcmp(cfg.feedback, 'yes')
ft_plot_mesh(headshape.pnt(shapesel,:), 'vertexcolor', 'g');
drawnow
end
% fit a sphere to these headshape points
if length(shapesel)>10
[o, r] = fitsphere(headshape.pnt(shapesel,:));
fprintf('channel = %s, %5d surface points, center = [%4.1f %4.1f %4.1f], radius = %4.1f\n', grad.label{chan}, length(shapesel), o(1), o(2), o(3), r);
else
fprintf('channel = %s, not enough surface points, using all points\n', grad.label{chan});
o = single_o;
r = single_r;
end
if r > cfg.maxradius
fprintf('channel = %s, not enough surface points, using all points\n', grad.label{chan});
o = single_o;
r = single_r;
end
% add this sphere to the volume conductor
headmodel.o(chan,:) = o;
headmodel.r(chan) = r;
headmodel.label{chan} = grad.label{chan};
end % for all channels
headmodel.type = 'localspheres';
% ensure that the geometrical units are specified
headmodel = ft_convert_units(headmodel);
% do the general cleanup and bookkeeping at the end of the function
ft_postamble debug
ft_postamble trackconfig
ft_postamble provenance
if hasmri
ft_postamble previous mri
end
ft_postamble history headmodel