v2.0.0
Loading...
Searching...
No Matches
fs_annotation.cpp
Go to the documentation of this file.
1//=============================================================================================================
12
13//=============================================================================================================
14// INCLUDES
15//=============================================================================================================
16
17#include "fs_annotation.h"
18#include "fs_label.h"
19#include "fs_surface.h"
20
21#include <iostream>
22
23//=============================================================================================================
24// QT INCLUDES
25//=============================================================================================================
26
27#include <QDebug>
28#include <QFile>
29#include <QDataStream>
30#include <QFileInfo>
31
32//=============================================================================================================
33// USED NAMESPACES
34//=============================================================================================================
35
36using namespace FSLIB;
37using namespace Eigen;
38
39//=============================================================================================================
40// DEFINE MEMBER METHODS
41//=============================================================================================================
42
44: m_iHemi(-1)
45{
46}
47
48//=============================================================================================================
49
50FsAnnotation::FsAnnotation(const QString& p_sFileName)
51: m_sFileName(p_sFileName)
52{
53 FsAnnotation t_Annotation;
54 FsAnnotation::read(m_sFileName, t_Annotation);
55 *this = t_Annotation;
56}
57
58//=============================================================================================================
59
60FsAnnotation::FsAnnotation(const QString &subject_id, qint32 hemi, const QString &atlas, const QString &subjects_dir)
61: m_iHemi(-1)
62{
63 FsAnnotation::read(subject_id, hemi, atlas, subjects_dir, *this);
64}
65
66//=============================================================================================================
67
68FsAnnotation::FsAnnotation(const QString &path, qint32 hemi, const QString &atlas)
69: m_iHemi(-1)
70{
71 FsAnnotation::read(path, hemi, atlas, *this);
72}
73
74//=============================================================================================================
75
79
80//=============================================================================================================
81
83{
84 m_sFileName = QString("");
85 m_Vertices = VectorXi::Zero(0);
86 m_LabelIds = VectorXi::Zero(0);
87 m_Colortable.clear();
88}
89
90//=============================================================================================================
91
92bool FsAnnotation::read(const QString &subject_id, qint32 hemi, const QString &atlas, const QString &subjects_dir, FsAnnotation &p_Annotation)
93{
94 if(hemi != 0 && hemi != 1)
95 return false;
96
97 QString p_sFile = QString("%1/%2/label/%3.%4.annot").arg(subjects_dir).arg(subject_id).arg(hemi == 0 ? "lh" : "rh").arg(atlas);
98
99 return read(p_sFile, p_Annotation);
100}
101
102//=============================================================================================================
103
104bool FsAnnotation::read(const QString &path, qint32 hemi, const QString &atlas, FsAnnotation &p_Annotation)
105{
106 if(hemi != 0 && hemi != 1)
107 return false;
108
109 QString p_sFile = QString("%1/%2.%3.annot").arg(path).arg(hemi == 0 ? "lh" : "rh").arg(atlas);
110
111 return read(p_sFile, p_Annotation);
112}
113
114//=============================================================================================================
115
116bool FsAnnotation::read(const QString& p_sFileName, FsAnnotation &p_Annotation)
117{
118 p_Annotation.clear();
119
120 qInfo("Reading annotation...\n");
121 QFile t_File(p_sFileName);
122 QFileInfo fileInfo(t_File.fileName());
123
124 p_Annotation.m_sFileName = fileInfo.fileName();
125 p_Annotation.m_sFilePath = fileInfo.filePath();
126
127 if (!t_File.open(QIODevice::ReadOnly))
128 {
129 qWarning("\tError: Couldn't open the file");
130 return false;
131 }
132
133 QDataStream t_Stream(&t_File);
134 t_Stream.setByteOrder(QDataStream::BigEndian);
135
136 qint32 numEl;
137 t_Stream >> numEl;
138
139 p_Annotation.m_Vertices = VectorXi(numEl);
140 p_Annotation.m_LabelIds = VectorXi(numEl);
141
142 for(qint32 i = 0; i < numEl; ++i)
143 {
144 t_Stream >> p_Annotation.m_Vertices[i];
145 t_Stream >> p_Annotation.m_LabelIds[i];
146 }
147
148 qint32 hasColortable;
149 t_Stream >> hasColortable;
150 if (hasColortable)
151 {
152 p_Annotation.m_Colortable.clear();
153
154 //Read colortable
155 qint32 numEntries;
156 t_Stream >> numEntries;
157 qint32 len;
158 if(numEntries > 0)
159 {
160
161 qInfo("\tReading from Original Version\n");
162 p_Annotation.m_Colortable.numEntries = numEntries;
163 t_Stream >> len;
164 QByteArray tmp;
165 tmp.resize(len);
166 t_Stream.readRawData(tmp.data(),len);
167 // FreeSurfer includes null terminator in stored length – strip it
168 if (tmp.endsWith('\0'))
169 tmp.chop(1);
170 p_Annotation.m_Colortable.orig_tab = tmp;
171
172 for(qint32 i = 0; i < numEntries; ++i)
173 p_Annotation.m_Colortable.struct_names.append("");
174
175 p_Annotation.m_Colortable.table = MatrixXi(numEntries,5);
176
177 for(qint32 i = 0; i < numEntries; ++i)
178 {
179 t_Stream >> len;
180 tmp.resize(len);
181 t_Stream.readRawData(tmp.data(),len);
182 if (tmp.endsWith('\0'))
183 tmp.chop(1);
184
185 p_Annotation.m_Colortable.struct_names[i]= tmp;
186
187 for(qint32 j = 0; j < 4; ++j)
188 t_Stream >> p_Annotation.m_Colortable.table(i,j);
189
190 p_Annotation.m_Colortable.table(i,4) = p_Annotation.m_Colortable.table(i,0)
191 + p_Annotation.m_Colortable.table(i,1) * 256 //(2^8)
192 + p_Annotation.m_Colortable.table(i,2) * 65536 //(2^16)
193 + p_Annotation.m_Colortable.table(i,3) * 16777216; //(2^24);
194 }
195 }
196 else
197 {
198 qint32 version = -numEntries;
199 if(version != 2)
200 qWarning("\tError! Does not handle version %d", version);
201 else
202 qInfo("\tReading from version %d\n", version);
203
204 t_Stream >> numEntries;
205 p_Annotation.m_Colortable.numEntries = numEntries;
206
207 t_Stream >> len;
208 QByteArray tmp;
209 tmp.resize(len);
210 t_Stream.readRawData(tmp.data(),len);
211 // FreeSurfer includes null terminator in stored length – strip it
212 if (tmp.endsWith('\0'))
213 tmp.chop(1);
214 p_Annotation.m_Colortable.orig_tab = tmp;
215
216 for(qint32 i = 0; i < numEntries; ++i)
217 p_Annotation.m_Colortable.struct_names.append("");
218
219 p_Annotation.m_Colortable.table = MatrixXi(numEntries,5);
220
221 qint32 numEntriesToRead;
222 t_Stream >> numEntriesToRead;
223
224 qint32 structure;
225 for(qint32 i = 0; i < numEntriesToRead; ++i)
226 {
227
228 t_Stream >> structure;
229 if (structure < 0)
230 qWarning("\tError! Read entry, index %d", structure);
231
232 if(!p_Annotation.m_Colortable.struct_names[structure].isEmpty())
233 qWarning("Error! Duplicate Structure %d", structure);
234
235 t_Stream >> len;
236 tmp.resize(len);
237 t_Stream.readRawData(tmp.data(),len);
238 if (tmp.endsWith('\0'))
239 tmp.chop(1);
240
241 p_Annotation.m_Colortable.struct_names[structure]= tmp;
242
243 for(qint32 j = 0; j < 4; ++j)
244 t_Stream >> p_Annotation.m_Colortable.table(structure,j);
245
246 p_Annotation.m_Colortable.table(structure,4) = p_Annotation.m_Colortable.table(structure,0)
247 + p_Annotation.m_Colortable.table(structure,1) * 256 //(2^8)
248 + p_Annotation.m_Colortable.table(structure,2) * 65536 //(2^16)
249 + p_Annotation.m_Colortable.table(structure,3) * 16777216; //(2^24);
250 }
251 }
252 qInfo("\tcolortable with %d entries read\n\t(originally %s)\n", p_Annotation.m_Colortable.numEntries, p_Annotation.m_Colortable.orig_tab.toUtf8().constData());
253 }
254 else
255 {
256 qWarning("\tError! No colortable stored");
257 }
258
259 // hemi info
260 if(t_File.fileName().contains("lh."))
261 p_Annotation.m_iHemi = 0;
262 else
263 p_Annotation.m_iHemi = 1;
264
265 qInfo("[done]\n");
266
267 t_File.close();
268
269 return true;
270}
271
272//=============================================================================================================
273
275 QList<FsLabel> &p_qListLabels,
276 QList<RowVector4i> &p_qListLabelRGBAs,
277 const QStringList& lLabelPicks) const
278{
279 if(this->m_iHemi != p_surf.hemi())
280 {
281 qWarning("FsAnnotation and surface hemisphere (annot = %d; surf = %d) do not match!\n", this->m_iHemi, p_surf.hemi());
282 return false;
283 }
284
285 if(m_LabelIds.size() == 0)
286 {
287 qWarning("FsAnnotation doesn't' contain data!\n");
288 return false;
289 }
290
291 qInfo("Converting labels from annotation...");
292
293//n_read = 0
294//labels = list()
295//label_colors = list()
296
297 VectorXi label_ids = m_Colortable.getLabelIds();
298 QStringList label_names = m_Colortable.getNames();
299 MatrixX4i label_rgbas = m_Colortable.getRGBAs();
300
301 // load the vertex positions from surface
302 MatrixX3f vert_pos = p_surf.rr();
303
304// qDebug() << label_rgbas.rows() << label_ids.size() << label_names.size();
305
306// std::cout << label_ids;
307
308 qint32 label_id, count;
309 RowVector4i label_rgba;
310 VectorXi vertices;
311 VectorXd values;
312 MatrixX3f pos;
313 QString name;
314 for(qint32 i = 0; i < label_rgbas.rows(); ++i)
315 {
316 label_id = label_ids[i];
317 label_rgba = label_rgbas.row(i);
318 count = 0;
319 vertices.resize(m_LabelIds.size());
320 //Where
321 for(qint32 j = 0; j < m_LabelIds.size(); ++j)
322 {
323 if(m_LabelIds[j] == label_id)
324 {
325 vertices[count] = j;
326 ++count;
327 }
328 }
329 // check if label is part of cortical surface
330 if(count == 0)
331 continue;
332 vertices.conservativeResize(count);
333
334 pos.resize(count, 3);
335 for(qint32 j = 0; j < count; ++j)
336 pos.row(j) = vert_pos.row(vertices[j]);
337
338 values = VectorXd::Zero(count);
339 name = QString("%1-%2").arg(label_names[i]).arg(this->m_iHemi == 0 ? "lh" : "rh");
340
341 // put it all together
342 if(lLabelPicks.isEmpty()) {
343 //t_tris
344 p_qListLabels.append(FsLabel(vertices, pos, values, this->m_iHemi, name, label_id));
345 // store the color
346 p_qListLabelRGBAs.append(label_rgba);
347 } else if (lLabelPicks.indexOf(name) != -1) {
348 //t_tris
349 p_qListLabels.append(FsLabel(vertices, pos, values, this->m_iHemi, name, label_id));
350 // store the color
351 p_qListLabelRGBAs.append(label_rgba);
352 }
353 }
354
355// for label_id, label_name, label_rgba in
356// zip(label_ids, label_names, label_rgbas):
357// vertices = np.where(annot == label_id)[0]
358// if len(vertices) == 0:
359// # label is not part of cortical surface
360// continue
361// pos = vert_pos[vertices, :]
362// values = np.zeros(len(vertices))
363// name = label_name + '-' + hemi
364// label = FsLabel(vertices, pos, values, hemi, name=name)
365// labels.append(label)
366
367// # store the color
368// label_rgba = tuple(label_rgba / 255.)
369// label_colors.append(label_rgba)
370
371// n_read = len(labels) - n_read
372// logger.info(' read %d labels from %s' % (n_read, fname))
373
374//# sort the labels and colors by label name
375//names = [label.name for label in labels]
376//labels, label_colors = zip(*((label, color) for (name, label, color)
377// in sorted(zip(names, labels, label_colors))))
378//# convert tuples to lists
379//labels = list(labels)
380//label_colors = list(label_colors)
381
382 qInfo("[done]\n");
383
384 return true;
385}
Reader and in-memory representation of a single FreeSurfer triangular surface (e.g....
Reader and in-memory representation of a FreeSurfer/MNE surface label (.label).
Reader for FreeSurfer per-vertex annotation (parcellation) files such as lh.aparc....
FreeSurfer surface, annotation and parcellation I/O for mne-cpp.
qint32 hemi() const
static bool read(const QString &subject_id, qint32 hemi, const QString &atlas, const QString &subjects_dir, FsAnnotation &p_Annotation)
bool toLabels(const FsSurface &p_surf, QList< FsLabel > &p_qListLabels, QList< Eigen::RowVector4i > &p_qListLabelRGBAs, const QStringList &lLabelPicks=QStringList()) const
QStringList struct_names
Eigen::MatrixXi table
A FreeSurfer/MNE surface label: per-vertex indices, Tk-RAS positions and scalar values for one hemisp...
Definition fs_label.h:79
In-memory FreeSurfer triangular cortical surface for one hemisphere.
Definition fs_surface.h:92
qint32 hemi() const
Definition fs_surface.h:355
const Eigen::MatrixX3f & rr() const
Definition fs_surface.h:376