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