v2.0.0
Loading...
Searching...
No Matches
rtsourceinterpolationmatworker.cpp
Go to the documentation of this file.
1//=============================================================================================================
12
13//=============================================================================================================
14// INCLUDES
15//=============================================================================================================
16
20
21#include <fs/fs_label.h>
22
23#include <QDebug>
24
25using namespace DISP3DLIB;
26
27//=============================================================================================================
28// MEMBER METHODS
29//=============================================================================================================
30
32: QObject(parent)
33{
34}
35
36//=============================================================================================================
37
38void RtSourceInterpolationMatWorker::setInterpolationFunction(const QString& sInterpolationFunction)
39{
40 QMutexLocker locker(&m_mutex);
41 m_sInterpolationFunction = sInterpolationFunction;
42}
43
44//=============================================================================================================
45
47{
48 QMutexLocker locker(&m_mutex);
49 m_dCancelDist = dCancelDist;
50}
51
52//=============================================================================================================
53
55 const Eigen::MatrixX3f& matVertices,
56 const std::vector<Eigen::VectorXi>& vecNeighborVertices,
57 const Eigen::VectorXi& vecSourceVertices)
58{
59 QMutexLocker locker(&m_mutex);
60 m_matVerticesLh = matVertices;
61 m_vecNeighborsLh = vecNeighborVertices;
62 m_vecSourceVerticesLh = vecSourceVertices;
63 m_hasLh = (!matVertices.isZero(0) && matVertices.rows() > 0 && vecSourceVertices.size() > 0);
64}
65
66//=============================================================================================================
67
69 const Eigen::MatrixX3f& matVertices,
70 const std::vector<Eigen::VectorXi>& vecNeighborVertices,
71 const Eigen::VectorXi& vecSourceVertices)
72{
73 QMutexLocker locker(&m_mutex);
74 m_matVerticesRh = matVertices;
75 m_vecNeighborsRh = vecNeighborVertices;
76 m_vecSourceVerticesRh = vecSourceVertices;
77 m_hasRh = (!matVertices.isZero(0) && matVertices.rows() > 0 && vecSourceVertices.size() > 0);
78}
79
80//=============================================================================================================
81
83{
84 QMutexLocker locker(&m_mutex);
85 m_iVisualizationType = iVisType;
86}
87
88//=============================================================================================================
89
90void RtSourceInterpolationMatWorker::setAnnotationInfoLeft(const Eigen::VectorXi& vecLabelIds,
91 const QList<FSLIB::FsLabel>& lLabels,
92 const Eigen::VectorXi& vecVertNo)
93{
94 if (vecLabelIds.rows() == 0 || lLabels.isEmpty()) {
95 qDebug() << "RtSourceInterpolationMatWorker::setAnnotationInfoLeft - FsAnnotation data is empty.";
96 return;
97 }
98
99 QMutexLocker locker(&m_mutex);
100 m_lLabelsLh = lLabels;
101 m_nAnnotationVerticesLh = static_cast<int>(vecLabelIds.rows());
102 m_mapLabelIdSourcesLh.clear();
103 m_vertNosLh.clear();
104
105 for (qint32 i = 0; i < vecVertNo.rows(); ++i) {
106 m_mapLabelIdSourcesLh.insert(vecVertNo(i), vecLabelIds(vecVertNo(i)));
107 m_vertNosLh.append(vecVertNo(i));
108 }
109
110 m_bAnnotationLhInit = true;
111}
112
113//=============================================================================================================
114
115void RtSourceInterpolationMatWorker::setAnnotationInfoRight(const Eigen::VectorXi& vecLabelIds,
116 const QList<FSLIB::FsLabel>& lLabels,
117 const Eigen::VectorXi& vecVertNo)
118{
119 if (vecLabelIds.rows() == 0 || lLabels.isEmpty()) {
120 qDebug() << "RtSourceInterpolationMatWorker::setAnnotationInfoRight - FsAnnotation data is empty.";
121 return;
122 }
123
124 QMutexLocker locker(&m_mutex);
125 m_lLabelsRh = lLabels;
126 m_nAnnotationVerticesRh = static_cast<int>(vecLabelIds.rows());
127 m_mapLabelIdSourcesRh.clear();
128 m_vertNosRh.clear();
129
130 for (qint32 i = 0; i < vecVertNo.rows(); ++i) {
131 m_mapLabelIdSourcesRh.insert(vecVertNo(i), vecLabelIds(vecVertNo(i)));
132 m_vertNosRh.append(vecVertNo(i));
133 }
134
135 m_bAnnotationRhInit = true;
136}
137
138//=============================================================================================================
139
140double (*RtSourceInterpolationMatWorker::resolveInterpolationFunction(const QString& name))(double)
141{
142 if (name == QStringLiteral("linear"))
144 if (name == QStringLiteral("gaussian"))
146 if (name == QStringLiteral("square"))
148 if (name == QStringLiteral("cubic"))
150
151 // Default to cubic
153}
154
155//=============================================================================================================
156
157QSharedPointer<Eigen::SparseMatrix<float>> RtSourceInterpolationMatWorker::computeHemi(
158 const Eigen::MatrixX3f& matVertices,
159 const std::vector<Eigen::VectorXi>& vecNeighborVertices,
160 Eigen::VectorXi vecSourceVertices,
161 double dCancelDist,
162 double (*interpFunc)(double))
163{
164 if (matVertices.rows() == 0 || vecSourceVertices.size() == 0) {
165 return QSharedPointer<Eigen::SparseMatrix<float>>();
166 }
167
168 // Compute surface-constrained distances (SCDC / geodesic)
169 QSharedPointer<Eigen::MatrixXd> distTable = GeometryInfo::scdc(
170 matVertices,
171 vecNeighborVertices,
172 vecSourceVertices,
173 dCancelDist);
174
175 if (!distTable || distTable->rows() == 0) {
176 qWarning() << "RtSourceInterpolationMatWorker: SCDC computation failed.";
177 return QSharedPointer<Eigen::SparseMatrix<float>>();
178 }
179
180 // Create interpolation matrix
182 vecSourceVertices,
183 distTable,
184 interpFunc,
185 dCancelDist);
186
187 return interpMat;
188}
189
190//=============================================================================================================
191
193{
194 // ── Snapshot parameters under lock ─────────────────────────────────
195 Eigen::MatrixX3f vertsLh, vertsRh;
196 std::vector<Eigen::VectorXi> neighborsLh, neighborsRh;
197 Eigen::VectorXi srcVertsLh, srcVertsRh;
198 bool hasLh, hasRh;
199 double cancelDist;
200 QString interpFuncName;
201 int visType;
202
203 // FsAnnotation data snapshots
204 QList<FSLIB::FsLabel> labelsLh, labelsRh;
205 QMap<qint32, qint32> mapLabelIdSrcLh, mapLabelIdSrcRh;
206 QList<int> vertNosLh, vertNosRh;
207 bool annotLhInit, annotRhInit;
208 int nAnnotVertsLh, nAnnotVertsRh;
209
210 {
211 QMutexLocker locker(&m_mutex);
212 vertsLh = m_matVerticesLh;
213 vertsRh = m_matVerticesRh;
214 neighborsLh = m_vecNeighborsLh;
215 neighborsRh = m_vecNeighborsRh;
216 srcVertsLh = m_vecSourceVerticesLh;
217 srcVertsRh = m_vecSourceVerticesRh;
218 hasLh = m_hasLh;
219 hasRh = m_hasRh;
220 cancelDist = m_dCancelDist;
221 interpFuncName = m_sInterpolationFunction;
222 visType = m_iVisualizationType;
223
224 labelsLh = m_lLabelsLh;
225 labelsRh = m_lLabelsRh;
226 mapLabelIdSrcLh = m_mapLabelIdSourcesLh;
227 mapLabelIdSrcRh = m_mapLabelIdSourcesRh;
228 vertNosLh = m_vertNosLh;
229 vertNosRh = m_vertNosRh;
230 annotLhInit = m_bAnnotationLhInit;
231 annotRhInit = m_bAnnotationRhInit;
232 nAnnotVertsLh = m_nAnnotationVerticesLh;
233 nAnnotVertsRh = m_nAnnotationVerticesRh;
234 }
235
236 // ── FsAnnotation-based mode ──────────────────────────────────────────
237 if (visType == AnnotationBased) {
238 qDebug() << "RtSourceInterpolationMatWorker: Computing annotation matrices...";
239
240 if (annotLhInit) {
241 auto mat = computeAnnotationOperator(labelsLh, mapLabelIdSrcLh, vertNosLh, nAnnotVertsLh);
242 if (mat && mat->rows() > 0) {
243 qDebug() << "RtSourceInterpolationMatWorker: LH annotation matrix:"
244 << mat->rows() << "x" << mat->cols();
246 }
247 }
248
249 if (annotRhInit) {
250 auto mat = computeAnnotationOperator(labelsRh, mapLabelIdSrcRh, vertNosRh, nAnnotVertsRh);
251 if (mat && mat->rows() > 0) {
252 qDebug() << "RtSourceInterpolationMatWorker: RH annotation matrix:"
253 << mat->rows() << "x" << mat->cols();
255 }
256 }
257
258 qDebug() << "RtSourceInterpolationMatWorker: FsAnnotation matrix computation complete.";
259 return;
260 }
261
262 // ── Interpolation-based mode (default) ─────────────────────────────
263 if (!hasLh && !hasRh) {
264 qDebug() << "RtSourceInterpolationMatWorker: No hemisphere data set, skipping.";
265 return;
266 }
267
268 auto interpFunc = resolveInterpolationFunction(interpFuncName);
269
270 qDebug() << "RtSourceInterpolationMatWorker: Computing interpolation matrices"
271 << "(cancelDist=" << cancelDist << ", func=" << interpFuncName << ")...";
272
273 // ── LH ─────────────────────────────────────────────────────────────
274 if (hasLh) {
275 qDebug() << "RtSourceInterpolationMatWorker: Computing LH matrix ("
276 << vertsLh.rows() << "verts," << srcVertsLh.size() << "sources)...";
277
278 auto mat = computeHemi(vertsLh, neighborsLh, srcVertsLh, cancelDist, interpFunc);
279
280 if (mat && mat->rows() > 0) {
281 qDebug() << "RtSourceInterpolationMatWorker: LH matrix computed:"
282 << mat->rows() << "x" << mat->cols();
284 } else {
285 qWarning() << "RtSourceInterpolationMatWorker: LH interpolation matrix computation failed.";
286 }
287 }
288
289 // ── RH ─────────────────────────────────────────────────────────────
290 if (hasRh) {
291 qDebug() << "RtSourceInterpolationMatWorker: Computing RH matrix ("
292 << vertsRh.rows() << "verts," << srcVertsRh.size() << "sources)...";
293
294 auto mat = computeHemi(vertsRh, neighborsRh, srcVertsRh, cancelDist, interpFunc);
295
296 if (mat && mat->rows() > 0) {
297 qDebug() << "RtSourceInterpolationMatWorker: RH matrix computed:"
298 << mat->rows() << "x" << mat->cols();
300 } else {
301 qWarning() << "RtSourceInterpolationMatWorker: RH interpolation matrix computation failed.";
302 }
303 }
304
305 qDebug() << "RtSourceInterpolationMatWorker: Interpolation matrix computation complete.";
306}
307
308//=============================================================================================================
309
310QSharedPointer<Eigen::SparseMatrix<float>> RtSourceInterpolationMatWorker::computeAnnotationOperator(
311 const QList<FSLIB::FsLabel>& lLabels,
312 const QMap<qint32, qint32>& mapLabelIdSrc,
313 const QList<int>& vertNos,
314 int nVertices)
315{
316 if (lLabels.isEmpty() || vertNos.isEmpty() || nVertices <= 0) {
317 return QSharedPointer<Eigen::SparseMatrix<float>>();
318 }
319
320 // One row per surface vertex: labels need not cover the surface, and their vertex indices are surface indices
321 auto mat = QSharedPointer<Eigen::SparseMatrix<float>>(
322 new Eigen::SparseMatrix<float>(nVertices, vertNos.size()));
323
324 // For each label: assign uniform weight to all its vertices from sources in that label
325 for (int i = 0; i < lLabels.size(); ++i) {
326 const FSLIB::FsLabel& label = lLabels.at(i);
327 QList<qint32> listSourcesVertNoLabel = mapLabelIdSrc.keys(label.label_id);
328
329 for (int j = 0; j < label.vertices.rows(); ++j) {
330 for (int k = 0; k < listSourcesVertNoLabel.size(); ++k) {
331 int colIdx = vertNos.indexOf(listSourcesVertNoLabel.at(k));
332 if (colIdx >= 0 && label.vertices(j) >= 0 && label.vertices(j) < nVertices) {
333 mat->coeffRef(label.vertices(j), colIdx) = 1.0f / listSourcesVertNoLabel.size();
334 }
335 }
336 }
337 }
338
339 return mat;
340}
Background worker that builds the sparse source-to-vertex interpolation matrix for one hemisphere.
Distance-based sparse interpolation weights and per-frame signal smoothing on triangulated meshes.
Surface-constrained geodesic distance and sensor-to-mesh projection helpers.
Reader and in-memory representation of a FreeSurfer/MNE surface label (.label).
3-D brain visualisation using the Qt RHI rendering backend.
static QSharedPointer< Eigen::MatrixXd > scdc(const Eigen::MatrixX3f &matVertices, const std::vector< Eigen::VectorXi > &vecNeighborVertices, Eigen::VectorXi &vecVertSubset, double dCancelDist=FLOAT_INFINITY)
scdc Calculates surface constrained distances on a mesh.
static double gaussian(const double dIn)
gaussian Gaussian interpolation function (sigma=1).
static double linear(const double dIn)
linear Identity interpolation function.
static double cubic(const double dIn)
cubic Cubic hyperbola interpolation function.
static QSharedPointer< Eigen::SparseMatrix< float > > createInterpolationMat(const Eigen::VectorXi &vecProjectedSensors, const QSharedPointer< Eigen::MatrixXd > matDistanceTable, double(*interpolationFunction)(double), const double dCancelDist=FLOAT_INFINITY, const Eigen::VectorXi &vecExcludeIndex=Eigen::VectorXi())
createInterpolationMat Calculates the weight matrix for interpolation.
static double square(const double dIn)
square Negative parabola interpolation function with y-offset of 1.
void setInterpolationFunction(const QString &sInterpolationFunction)
void setInterpolationInfoLeft(const Eigen::MatrixX3f &matVertices, const std::vector< Eigen::VectorXi > &vecNeighborVertices, const Eigen::VectorXi &vecSourceVertices)
void setAnnotationInfoLeft(const Eigen::VectorXi &vecLabelIds, const QList< FSLIB::FsLabel > &lLabels, const Eigen::VectorXi &vecVertNo)
void newInterpolationMatrixRightAvailable(QSharedPointer< Eigen::SparseMatrix< float > > interpMat)
void setInterpolationInfoRight(const Eigen::MatrixX3f &matVertices, const std::vector< Eigen::VectorXi > &vecNeighborVertices, const Eigen::VectorXi &vecSourceVertices)
void newInterpolationMatrixLeftAvailable(QSharedPointer< Eigen::SparseMatrix< float > > interpMat)
void setAnnotationInfoRight(const Eigen::VectorXi &vecLabelIds, const QList< FSLIB::FsLabel > &lLabels, const Eigen::VectorXi &vecVertNo)
A FreeSurfer/MNE surface label: per-vertex indices, Tk-RAS positions and scalar values for one hemisp...
Definition fs_label.h:81
qint32 label_id
Definition fs_label.h:172
Eigen::VectorXi vertices
Definition fs_label.h:166