v2.0.0
Loading...
Searching...
No Matches
inv_source_estimate.cpp
Go to the documentation of this file.
1//=============================================================================================================
20
21//=============================================================================================================
22// INCLUDES
23//=============================================================================================================
24
25#include "inv_source_estimate.h"
26
27//=============================================================================================================
28// QT INCLUDES
29//=============================================================================================================
30
31#include <QFile>
32#include <QDataStream>
33#include <QSharedPointer>
34#include <QDebug>
35
36#include <stdexcept>
37#include <QtEndian>
38//=============================================================================================================
39// USED NAMESPACES
40//=============================================================================================================
41
42using namespace INVLIB;
43using namespace FSLIB;
44using namespace Eigen;
45
46//=============================================================================================================
47// DEFINE MEMBER METHODS
48//=============================================================================================================
49
58
59//=============================================================================================================
60
61InvSourceEstimate::InvSourceEstimate(const MatrixXd &p_sol, const VectorXi &p_vertices, float p_tmin, float p_tstep)
62: data(p_sol)
63, vertices(p_vertices)
64, tmin(p_tmin)
65, tstep(p_tstep)
67, sourceSpaceType(InvSourceSpaceType::Unknown)
68, orientationType(InvOrientationType::Unknown)
69{
70 this->update_times();
71}
72
73//=============================================================================================================
74
76: data(p_SourceEstimate.data)
77, vertices(p_SourceEstimate.vertices)
78, times(p_SourceEstimate.times)
79, tmin(p_SourceEstimate.tmin)
80, tstep(p_SourceEstimate.tstep)
81, method(p_SourceEstimate.method)
82, sourceSpaceType(p_SourceEstimate.sourceSpaceType)
83, orientationType(p_SourceEstimate.orientationType)
84, positions(p_SourceEstimate.positions)
85, couplings(p_SourceEstimate.couplings)
86, focalDipoles(p_SourceEstimate.focalDipoles)
87, connectivity(p_SourceEstimate.connectivity)
88{
89}
90
91//=============================================================================================================
92
94: tmin(0)
95, tstep(-1)
99{
100 if(!read(p_IODevice, *this))
101 {
102 throw std::runtime_error("Source estimation not found");
103 }
104}
105
106//=============================================================================================================
107
109{
110 data = MatrixXd();
111 vertices = VectorXi();
112 times = RowVectorXf();
113 tmin = 0;
114 tstep = 0;
118 positions = MatrixX3f();
119 couplings.clear();
120 focalDipoles.clear();
121 connectivity.clear();
122}
123
124//=============================================================================================================
125
127{
128 InvSourceEstimate p_sourceEstimateReduced;
129
130 qint32 rows = this->data.rows();
131
132 p_sourceEstimateReduced.data = MatrixXd::Zero(rows,n);
133 p_sourceEstimateReduced.data = this->data.block(0, start, rows, n);
134 p_sourceEstimateReduced.vertices = this->vertices;
135 p_sourceEstimateReduced.times = RowVectorXf::Zero(n);
136 p_sourceEstimateReduced.times = this->times.block(0,start,1,n);
137 p_sourceEstimateReduced.tmin = p_sourceEstimateReduced.times(0);
138 p_sourceEstimateReduced.tstep = this->tstep;
139 p_sourceEstimateReduced.method = this->method;
140 p_sourceEstimateReduced.sourceSpaceType = this->sourceSpaceType;
141 p_sourceEstimateReduced.orientationType = this->orientationType;
142 p_sourceEstimateReduced.positions = this->positions;
143 p_sourceEstimateReduced.couplings = this->couplings;
144 p_sourceEstimateReduced.focalDipoles = this->focalDipoles;
145 p_sourceEstimateReduced.connectivity = this->connectivity;
146
147 return p_sourceEstimateReduced;
148}
149
150//=============================================================================================================
151
152bool InvSourceEstimate::read(QIODevice &p_IODevice, InvSourceEstimate& p_stc)
153{
154 QSharedPointer<QDataStream> t_pStream(new QDataStream(&p_IODevice));
155
156 t_pStream->setFloatingPointPrecision(QDataStream::SinglePrecision);
157 t_pStream->setByteOrder(QDataStream::BigEndian);
158 t_pStream->setVersion(QDataStream::Qt_5_0);
159
160 if(!t_pStream->device()->open(QIODevice::ReadOnly))
161 return false;
162
163 QFile* t_pFile = qobject_cast<QFile*>(&p_IODevice);
164 if(t_pFile)
165 qInfo("Reading source estimate from %s...", t_pFile->fileName().toUtf8().constData());
166 else
167 qInfo("Reading source estimate...");
168
169 // read start time in ms
170 *t_pStream >> p_stc.tmin;
171 p_stc.tmin /= 1000;
172 // read sampling rate in ms
173 *t_pStream >> p_stc.tstep;
174 p_stc.tstep /= 1000;
175 // read number of vertices
176 quint32 t_nVertices;
177 *t_pStream >> t_nVertices;
178 p_stc.vertices = VectorXi(t_nVertices);
179 // read the vertex indices
180 for(quint32 i = 0; i < t_nVertices; ++i)
181 *t_pStream >> p_stc.vertices[i];
182 // read the number of timepts
183 quint32 t_nTimePts;
184 *t_pStream >> t_nTimePts;
185 //
186 // read the data
187 //
188 p_stc.data = MatrixXd(t_nVertices, t_nTimePts);
189 for(qint32 i = 0; i < p_stc.data.array().size(); ++i)
190 {
191 float value;
192 *t_pStream >> value;
193 p_stc.data.array()(i) = value;
194 }
195
196 //Update time vector
197 p_stc.update_times();
198
199 // close the file
200 t_pStream->device()->close();
201
202 qInfo("[done]");
203
204 return true;
205}
206
207//=============================================================================================================
208
209bool InvSourceEstimate::write(QIODevice &p_IODevice)
210{
211 // Create the file and save the essentials
212 QSharedPointer<QDataStream> t_pStream(new QDataStream(&p_IODevice));
213
214 t_pStream->setFloatingPointPrecision(QDataStream::SinglePrecision);
215 t_pStream->setByteOrder(QDataStream::BigEndian);
216 t_pStream->setVersion(QDataStream::Qt_5_0);
217
218 if(!t_pStream->device()->open(QIODevice::WriteOnly))
219 {
220 qWarning("Failed to write source estimate!");
221 return false;
222 }
223
224 QFile* t_pFile = qobject_cast<QFile*>(&p_IODevice);
225 if(t_pFile)
226 qInfo("Write source estimate to %s...", t_pFile->fileName().toUtf8().constData());
227 else
228 qInfo("Write source estimate...");
229
230 // write start time in ms
231 *t_pStream << static_cast<float>(1000*this->tmin);
232 // write sampling rate in ms
233 *t_pStream << static_cast<float>(1000*this->tstep);
234 // write number of vertices
235 *t_pStream << static_cast<quint32>(this->vertices.size());
236 // write the vertex indices
237 for(qint32 i = 0; i < this->vertices.size(); ++i)
238 *t_pStream << static_cast<quint32>(this->vertices[i]);
239 // write the number of timepts
240 *t_pStream << static_cast<quint32>(this->data.cols());
241 //
242 // write the data
243 //
244 for(qint32 i = 0; i < this->data.array().size(); ++i)
245 *t_pStream << static_cast<float>(this->data.array()(i));
246
247 // close the file
248 t_pStream->device()->close();
249
250 qInfo("[done]");
251 return true;
252}
253
254//=============================================================================================================
255
257{
258 QFile file(path);
259 if (!file.open(QIODevice::ReadOnly)) {
260 qWarning("InvSourceEstimate::read_w - Cannot open file %s", path.toUtf8().constData());
261 return InvSourceEstimate();
262 }
263
264 QDataStream stream(&file);
265 stream.setByteOrder(QDataStream::BigEndian);
266 stream.setFloatingPointPrecision(QDataStream::SinglePrecision);
267
268 // Skip 2-byte magic
269 quint16 magic;
270 stream >> magic;
271
272 // Read number of vertices (3-byte big-endian integer)
273 quint8 b0, b1, b2;
274 stream >> b0 >> b1 >> b2;
275 qint32 nVertices = (static_cast<qint32>(b0) << 16)
276 | (static_cast<qint32>(b1) << 8)
277 | static_cast<qint32>(b2);
278
279 VectorXi vertices(nVertices);
280 MatrixXd data(nVertices, 1);
281
282 for (qint32 i = 0; i < nVertices; ++i) {
283 // Read 3-byte vertex index
284 stream >> b0 >> b1 >> b2;
285 vertices[i] = (static_cast<qint32>(b0) << 16)
286 | (static_cast<qint32>(b1) << 8)
287 | static_cast<qint32>(b2);
288
289 // Read 4-byte big-endian float
290 float val;
291 stream >> val;
292 data(i, 0) = static_cast<double>(val);
293 }
294
295 file.close();
296
297 InvSourceEstimate stc(data, vertices, 0.0f, 0.0f);
298 return stc;
299}
300
301//=============================================================================================================
302
303void InvSourceEstimate::write_w(const QString& path) const
304{
305 if (isEmpty()) {
306 qWarning("InvSourceEstimate::write_w - Source estimate is empty");
307 return;
308 }
309
310 QFile file(path);
311 if (!file.open(QIODevice::WriteOnly)) {
312 qWarning("InvSourceEstimate::write_w - Cannot open file %s for writing", path.toUtf8().constData());
313 return;
314 }
315
316 QDataStream stream(&file);
317 stream.setByteOrder(QDataStream::BigEndian);
318 stream.setFloatingPointPrecision(QDataStream::SinglePrecision);
319
320 // Write 2-byte magic (zeros)
321 stream << static_cast<quint8>(0) << static_cast<quint8>(0);
322
323 // Write number of vertices as 3-byte big-endian integer
324 qint32 nVertices = static_cast<qint32>(vertices.size());
325 stream << static_cast<quint8>((nVertices >> 16) & 0xFF)
326 << static_cast<quint8>((nVertices >> 8) & 0xFF)
327 << static_cast<quint8>(nVertices & 0xFF);
328
329 // Write each vertex index (3 bytes) and value (4-byte float)
330 for (qint32 i = 0; i < nVertices; ++i) {
331 qint32 idx = vertices[i];
332 stream << static_cast<quint8>((idx >> 16) & 0xFF)
333 << static_cast<quint8>((idx >> 8) & 0xFF)
334 << static_cast<quint8>(idx & 0xFF);
335
336 stream << static_cast<float>(data(i, 0));
337 }
338
339 file.close();
340}
341
342//=============================================================================================================
343
344void InvSourceEstimate::update_times()
345{
346 if(data.cols() > 0)
347 {
348 this->times = RowVectorXf(data.cols());
349 this->times[0] = this->tmin;
350 for(float i = 1; i < this->times.size(); ++i)
351 this->times[i] = this->times[i-1] + this->tstep;
352 }
353 else
354 this->times = RowVectorXf();
355}
356
357//=============================================================================================================
358
360{
361 if (this != &rhs) // protect against invalid self-assignment
362 {
363 data = rhs.data;
364 vertices = rhs.vertices;
365 times = rhs.times;
366 tmin = rhs.tmin;
367 tstep = rhs.tstep;
368 method = rhs.method;
371 positions = rhs.positions;
372 couplings = rhs.couplings;
375 }
376 // to support chained assignment operators (a=b=c), always return *this
377 return *this;
378}
379
380//=============================================================================================================
381
383{
384 return data.cols();
385}
386
387//=============================================================================================================
388
389VectorXi InvSourceEstimate::getIndicesByLabel(const QList<FsLabel> &lPickedLabels, bool bIsClustered) const
390{
391 VectorXi vIndexSourceLabels;
392
393 if(lPickedLabels.isEmpty()) {
394 qWarning() << "InvSourceEstimate::getIndicesByLabel - picked label list is empty. Returning.";
395 return vIndexSourceLabels;
396 }
397
398 if(bIsClustered) {
399 for(int i = 0; i < this->vertices.rows(); i++) {
400 for(int k = 0; k < lPickedLabels.size(); k++) {
401 if(this->vertices(i) == lPickedLabels.at(k).label_id) {
402 vIndexSourceLabels.conservativeResize(vIndexSourceLabels.rows()+1,1);
403 vIndexSourceLabels(vIndexSourceLabels.rows()-1) = i;
404 break;
405 }
406 }
407 }
408 } else {
409 int hemi = 0;
410
411 for(int i = 0; i < this->vertices.rows(); i++) {
412 // Detect left right hemi separation
413 if(i > 0){
414 if(this->vertices(i) < this->vertices(i-1)){
415 hemi = 1;
416 }
417 }
418
419 for(int k = 0; k < lPickedLabels.size(); k++) {
420 for(int l = 0; l < lPickedLabels.at(k).vertices.rows(); l++) {
421 if(this->vertices(i) == lPickedLabels.at(k).vertices(l) && lPickedLabels.at(k).hemi == hemi) {
422 vIndexSourceLabels.conservativeResize(vIndexSourceLabels.rows()+1,1);
423 vIndexSourceLabels(vIndexSourceLabels.rows()-1) = i;
424 break;
425 }
426 }
427 }
428 }
429 }
430
431 return vIndexSourceLabels;
432}
InvSourceEstimate value type — central source-space data container produced by every INVLIB inverse s...
FreeSurfer surface, annotation and parcellation I/O for mne-cpp.
Inverse source estimation (MNE, dSPM, sLORETA, dipole fitting).
InvEstimateMethod
Definition inv_types.h:37
InvOrientationType
Definition inv_types.h:71
InvSourceSpaceType
Definition inv_types.h:58
std::vector< InvSourceCoupling > couplings
std::vector< InvFocalDipole > focalDipoles
Eigen::VectorXi getIndicesByLabel(const QList< FSLIB::FsLabel > &lPickedLabels, bool bIsClustered) const
static bool read(QIODevice &p_IODevice, InvSourceEstimate &p_stc)
InvSourceEstimate & operator=(const InvSourceEstimate &rhs)
static InvSourceEstimate read_w(const QString &path)
bool write(QIODevice &p_IODevice)
InvSourceSpaceType sourceSpaceType
InvOrientationType orientationType
std::vector< InvConnectivity > connectivity
InvSourceEstimate reduce(qint32 start, qint32 n)
void write_w(const QString &path) const