-
Notifications
You must be signed in to change notification settings - Fork 28
/
palm_icodown.m
199 lines (172 loc) · 6.22 KB
/
palm_icodown.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
function palm_icodown(varargin)
% Downsample a data-per-vertex (DPV), data-per-face (DPF),
% surface (SRF), or surfvol (MGH/MGZ) from a higher-order tessellated
% icosahedron to a lower order one. Note that the file must have been
% derived from either FreeSurfer or Brainder tools. It may not work
% if the vertices follow a different sequence inside the file.
%
% For facewise, the downsampling method is pycnophylactic and,
% therefore, should be used for quantities that require mass
% conservation, such as areal quantities.
% For vertexwise, the method removes the redundant vertices.
% Consider smoothing if needed before downsampling.
%
% Usage:
% palm_icodown(filein,ntarget,fileout,surface)
%
% - filein : File to be downsampled.
% - ntarget : Icosahedron order of the downsampled file.
% - fileout : Output file, downsampled.
% - suface : Optional. For facewise, if the face indices aren't
% ordered in the usual manner, entering a surface
% is necessary to merge the faces correctly.
%
% _____________________________________
% Anderson M. Winkler
% Yale University / Institute of Living
% Apr/2012 (first version)
% Jul/2016 (this version, with vertexwise, surface and mgh/mgz)
% http://brainder.org
% Accept arguments
nargin = numel(varargin);
filein = varargin{1};
ntarget = varargin{2};
fileout = varargin{3};
% Constants for the icosahedron
V0 = 12;
F0 = 20;
% Read data from disk
X = palm_miscread(filein);
% try
% [dpx,crd,idx] = dpxread(filein);
% nX = numel(dpx);
% ftype = 'dpx';
% catch
% try
% [vtx,fac] = srfread(filein);
% nV = size(vtx,1);
% ftype = 'srf';
% catch
% error('File %s not recognised as either DPX (curvature) or SRF (surface).',filein);
% end
% end
switch X.readwith,
case {'srfread','fs_read_surf'},
% Data to operate on
vtx = X.data.vtx;
fac = X.data.fac;
nV = size(vtx,1);
% Find icosahedron order
n = round(log((nV-2)/(V0-2))/log(4));
% Sanity check
if nV ~= 4^n*(V0-2)+2,
error('Data not from icosahedron.');
elseif ntarget >= n,
error('This script only downsamples data.');
else
fprintf('Downsampling surface geometry:');
end
% Remove vertices:
vtx = vtx(1:(4^ntarget*(V0-2)+2),:);
% Remove face indices:
for j = (n-1):-1:ntarget,
fprintf(' %d',j);
nVj = 4^j*(V0-2)+2;
facnew = zeros(4^j*F0,3);
fout = find(all(fac > nVj,2));
for f = 1:numel(fout),
vidx = fac(fout(f),:);
ftomerge = fac(sum(...
fac == vidx(1) | ...
fac == vidx(2) | ...
fac == vidx(3),2) == 2,:);
facnew(f,:) = sum(ftomerge.*(ftomerge <= nVj),1);
end
fac = facnew;
end
fprintf('. Done.\n');
% Prepare to save
X.data.vtx = vtx;
X.data.fac = fac;
X.filename = fileout;
case {'dpxread','fs_read_curv','fs_load_mgh'},
% Data to operate on
dpx = X.data;
nX = size(dpx,1);
% Detect what kind of data this is
if mod(nX,10), % vertexwise
% Find icosahedron order
n = round(log((nX-2)/(V0-2))/log(4));
% Sanity check
if nX ~= 4^n*(V0-2)+2,
error('Data not from icosahedron.');
elseif ntarget >= n,
error('This script only downsamples data.');
else
fprintf('Downsampling vertexwise data.\n');
end
% Downsample vertices
dpx = dpx(1:(4^ntarget*(V0-2)+2),:,:,:);
else % facewise
% Find icosahedron order
n = round(log(nX/F0)/log(4));
% Sanity check
if nX ~= 4^n*F0,
error('Data not from icosahedron.');
elseif ntarget >= n,
error('This script only downsamples data.')
else
fprintf('Downsampling facewise data:');
end
% If a surface was given
if nargin == 4,
% Load it
[~,fac] = srfread(filein);
% Downsample faces (general case)
for j = (n-1):-1:ntarget,
fprintf(' %d',j);
nVj = 4^j*(V0-2)+2;
facnew = zeros(4^j*F0,3);
fout = find(all(fac > nVj,2));
dpfnew = dpf(fout,:,:,:);
for f = 1:numel(fout),
vidx = fac(fout(f),:);
fidx = sum(...
fac == vidx(1) | ...
fac == vidx(2) | ...
fac == vidx(3),2) == 2;
ftomerge = fac(fidx,:);
facnew(f,:) = sum(ftomerge.*(ftomerge <= nVj),1);
dpfnew(f,:,:,:) = dpfnew(f,:,:,:) + sum(dpf(fidx,:,:,:),1);
end
fac = facnew;
end
fprintf('. Done.\n');
else
% Downsample faces (platonic only)
for d = 1:(n-ntarget),
siz = size(dpx);
siz(1) = siz(1)/4;
dpxnew = zeros(siz);
for n = 1:size(dpx,4);
dpxnew(:,1,1,n) = sum(reshape(dpx(:,1,1,n),[4 nX/4]))';
end
end
end
end
% Prepare to save
X.data = dpx;
X.filename = fileout;
switch X.readwith,
case 'dpxread',
nXdown = numel(dpx);
X.extra.crd(nXdown+1:end,:) = [];
X.extra.idx(nXdown+1:end,:) = [];
case 'fs_read_curv',
X.extra.fnum = 4^ntarget*F0; % this will only work for vertexwise
case 'fs_load_mgh',
X.extra.volsz = size(X.data);
end
end
% Save now
palm_miscwrite(X);