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_mapLabelIdSourcesLh.clear();
102 m_vertNosLh.clear();
103
104 for (qint32 i = 0; i < vecVertNo.rows(); ++i) {
105 m_mapLabelIdSourcesLh.insert(vecVertNo(i), vecLabelIds(vecVertNo(i)));
106 m_vertNosLh.append(vecVertNo(i));
107 }
108
109 m_bAnnotationLhInit = true;
110}
111
112//=============================================================================================================
113
114void RtSourceInterpolationMatWorker::setAnnotationInfoRight(const Eigen::VectorXi &vecLabelIds,
115 const QList<FSLIB::FsLabel> &lLabels,
116 const Eigen::VectorXi &vecVertNo)
117{
118 if (vecLabelIds.rows() == 0 || lLabels.isEmpty()) {
119 qDebug() << "RtSourceInterpolationMatWorker::setAnnotationInfoRight - FsAnnotation data is empty.";
120 return;
121 }
122
123 QMutexLocker locker(&m_mutex);
124 m_lLabelsRh = lLabels;
125 m_mapLabelIdSourcesRh.clear();
126 m_vertNosRh.clear();
127
128 for (qint32 i = 0; i < vecVertNo.rows(); ++i) {
129 m_mapLabelIdSourcesRh.insert(vecVertNo(i), vecLabelIds(vecVertNo(i)));
130 m_vertNosRh.append(vecVertNo(i));
131 }
132
133 m_bAnnotationRhInit = true;
134}
135
136//=============================================================================================================
137
138double (*RtSourceInterpolationMatWorker::resolveInterpolationFunction(const QString &name))(double)
139{
140 if (name == QStringLiteral("linear")) return Interpolation::linear;
141 if (name == QStringLiteral("gaussian")) return Interpolation::gaussian;
142 if (name == QStringLiteral("square")) return Interpolation::square;
143 if (name == QStringLiteral("cubic")) return Interpolation::cubic;
144
145 // Default to cubic
147}
148
149//=============================================================================================================
150
151QSharedPointer<Eigen::SparseMatrix<float>> RtSourceInterpolationMatWorker::computeHemi(
152 const Eigen::MatrixX3f &matVertices,
153 const std::vector<Eigen::VectorXi> &vecNeighborVertices,
154 Eigen::VectorXi vecSourceVertices,
155 double dCancelDist,
156 double (*interpFunc)(double))
157{
158 if (matVertices.rows() == 0 || vecSourceVertices.size() == 0) {
159 return QSharedPointer<Eigen::SparseMatrix<float>>();
160 }
161
162 // Compute surface-constrained distances (SCDC / geodesic)
163 QSharedPointer<Eigen::MatrixXd> distTable = GeometryInfo::scdc(
164 matVertices,
165 vecNeighborVertices,
166 vecSourceVertices,
167 dCancelDist
168 );
169
170 if (!distTable || distTable->rows() == 0) {
171 qWarning() << "RtSourceInterpolationMatWorker: SCDC computation failed.";
172 return QSharedPointer<Eigen::SparseMatrix<float>>();
173 }
174
175 // Create interpolation matrix
177 vecSourceVertices,
178 distTable,
179 interpFunc,
180 dCancelDist
181 );
182
183 return interpMat;
184}
185
186//=============================================================================================================
187
189{
190 // ── Snapshot parameters under lock ─────────────────────────────────
191 Eigen::MatrixX3f vertsLh, vertsRh;
192 std::vector<Eigen::VectorXi> neighborsLh, neighborsRh;
193 Eigen::VectorXi srcVertsLh, srcVertsRh;
194 bool hasLh, hasRh;
195 double cancelDist;
196 QString interpFuncName;
197 int visType;
198
199 // FsAnnotation data snapshots
200 QList<FSLIB::FsLabel> labelsLh, labelsRh;
201 QMap<qint32, qint32> mapLabelIdSrcLh, mapLabelIdSrcRh;
202 QList<int> vertNosLh, vertNosRh;
203 bool annotLhInit, annotRhInit;
204
205 {
206 QMutexLocker locker(&m_mutex);
207 vertsLh = m_matVerticesLh;
208 vertsRh = m_matVerticesRh;
209 neighborsLh = m_vecNeighborsLh;
210 neighborsRh = m_vecNeighborsRh;
211 srcVertsLh = m_vecSourceVerticesLh;
212 srcVertsRh = m_vecSourceVerticesRh;
213 hasLh = m_hasLh;
214 hasRh = m_hasRh;
215 cancelDist = m_dCancelDist;
216 interpFuncName = m_sInterpolationFunction;
217 visType = m_iVisualizationType;
218
219 labelsLh = m_lLabelsLh;
220 labelsRh = m_lLabelsRh;
221 mapLabelIdSrcLh = m_mapLabelIdSourcesLh;
222 mapLabelIdSrcRh = m_mapLabelIdSourcesRh;
223 vertNosLh = m_vertNosLh;
224 vertNosRh = m_vertNosRh;
225 annotLhInit = m_bAnnotationLhInit;
226 annotRhInit = m_bAnnotationRhInit;
227 }
228
229 // ── FsAnnotation-based mode ──────────────────────────────────────────
230 if (visType == AnnotationBased) {
231 qDebug() << "RtSourceInterpolationMatWorker: Computing annotation matrices...";
232
233 if (annotLhInit) {
234 auto mat = computeAnnotationOperator(labelsLh, mapLabelIdSrcLh, vertNosLh);
235 if (mat && mat->rows() > 0) {
236 qDebug() << "RtSourceInterpolationMatWorker: LH annotation matrix:"
237 << mat->rows() << "x" << mat->cols();
239 }
240 }
241
242 if (annotRhInit) {
243 auto mat = computeAnnotationOperator(labelsRh, mapLabelIdSrcRh, vertNosRh);
244 if (mat && mat->rows() > 0) {
245 qDebug() << "RtSourceInterpolationMatWorker: RH annotation matrix:"
246 << mat->rows() << "x" << mat->cols();
248 }
249 }
250
251 qDebug() << "RtSourceInterpolationMatWorker: FsAnnotation matrix computation complete.";
252 return;
253 }
254
255 // ── Interpolation-based mode (default) ─────────────────────────────
256 if (!hasLh && !hasRh) {
257 qDebug() << "RtSourceInterpolationMatWorker: No hemisphere data set, skipping.";
258 return;
259 }
260
261 auto interpFunc = resolveInterpolationFunction(interpFuncName);
262
263 qDebug() << "RtSourceInterpolationMatWorker: Computing interpolation matrices"
264 << "(cancelDist=" << cancelDist << ", func=" << interpFuncName << ")...";
265
266 // ── LH ─────────────────────────────────────────────────────────────
267 if (hasLh) {
268 qDebug() << "RtSourceInterpolationMatWorker: Computing LH matrix ("
269 << vertsLh.rows() << "verts," << srcVertsLh.size() << "sources)...";
270
271 auto mat = computeHemi(vertsLh, neighborsLh, srcVertsLh, cancelDist, interpFunc);
272
273 if (mat && mat->rows() > 0) {
274 qDebug() << "RtSourceInterpolationMatWorker: LH matrix computed:"
275 << mat->rows() << "x" << mat->cols();
277 } else {
278 qWarning() << "RtSourceInterpolationMatWorker: LH interpolation matrix computation failed.";
279 }
280 }
281
282 // ── RH ─────────────────────────────────────────────────────────────
283 if (hasRh) {
284 qDebug() << "RtSourceInterpolationMatWorker: Computing RH matrix ("
285 << vertsRh.rows() << "verts," << srcVertsRh.size() << "sources)...";
286
287 auto mat = computeHemi(vertsRh, neighborsRh, srcVertsRh, cancelDist, interpFunc);
288
289 if (mat && mat->rows() > 0) {
290 qDebug() << "RtSourceInterpolationMatWorker: RH matrix computed:"
291 << mat->rows() << "x" << mat->cols();
293 } else {
294 qWarning() << "RtSourceInterpolationMatWorker: RH interpolation matrix computation failed.";
295 }
296 }
297
298 qDebug() << "RtSourceInterpolationMatWorker: Interpolation matrix computation complete.";
299}
300
301//=============================================================================================================
302
303QSharedPointer<Eigen::SparseMatrix<float>> RtSourceInterpolationMatWorker::computeAnnotationOperator(
304 const QList<FSLIB::FsLabel> &lLabels,
305 const QMap<qint32, qint32> &mapLabelIdSrc,
306 const QList<int> &vertNos)
307{
308 if (lLabels.isEmpty() || vertNos.isEmpty()) {
309 return QSharedPointer<Eigen::SparseMatrix<float>>();
310 }
311
312 // Count total vertices across all labels
313 int iNumVert = 0;
314 for (int i = 0; i < lLabels.size(); ++i) {
315 iNumVert += lLabels.at(i).vertices.rows();
316 }
317
318 auto mat = QSharedPointer<Eigen::SparseMatrix<float>>(
319 new Eigen::SparseMatrix<float>(iNumVert, vertNos.size()));
320
321 // For each label: assign uniform weight to all its vertices from sources in that label
322 for (int i = 0; i < lLabels.size(); ++i) {
323 const FSLIB::FsLabel &label = lLabels.at(i);
324 QList<qint32> listSourcesVertNoLabel = mapLabelIdSrc.keys(label.label_id);
325
326 for (int j = 0; j < label.vertices.rows(); ++j) {
327 for (int k = 0; k < listSourcesVertNoLabel.size(); ++k) {
328 int colIdx = vertNos.indexOf(listSourcesVertNoLabel.at(k));
329 if (colIdx >= 0 && label.vertices(j) < iNumVert) {
330 mat->coeffRef(label.vertices(j), colIdx) = 1.0f / listSourcesVertNoLabel.size();
331 }
332 }
333 }
334 }
335
336 return mat;
337}
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)
qint32 label_id
Definition fs_label.h:170
Eigen::VectorXi vertices
Definition fs_label.h:164