v2.0.0
Loading...
Searching...
No Matches
mri_vol_data.cpp
Go to the documentation of this file.
1//=============================================================================================================
30
31//=============================================================================================================
32// INCLUDES
33//=============================================================================================================
34
35#include "mri_vol_data.h"
36#include "mri_mgh_io.h"
37#include "mri_nifti_io.h"
38
39#include <fiff/fiff_file.h>
40
41//=============================================================================================================
42// USED NAMESPACES
43//=============================================================================================================
44
45using namespace MRILIB;
46using namespace Eigen;
47
48//=============================================================================================================
49// DEFINE MEMBER METHODS
50//=============================================================================================================
51
53: version(0)
54, width(0)
55, height(0)
56, depth(0)
57, nframes(0)
59, dof(0)
60, rasGood(false)
61, xsize(1.0f)
62, ysize(1.0f)
63, zsize(1.0f)
64, x_ras(-1.0f, 0.0f, 0.0f) // FreeSurfer defaults when goodRASflag is false
65, y_ras( 0.0f, 0.0f, -1.0f) // See: https://surfer.nmr.mgh.harvard.edu/fswiki/FsTutorial/MghFormat
66, z_ras( 0.0f, 1.0f, 0.0f)
67, c_ras( 0.0f, 0.0f, 0.0f)
68, TR(0.0f)
69, flipAngle(0.0f)
70, TE(0.0f)
71, TI(0.0f)
72, FoV(0.0f)
73{
74}
75
76//=============================================================================================================
77
79{
80 return (version == MRI_MGH_VERSION && width > 0 && height > 0 && depth > 0);
81}
82
83//=============================================================================================================
84
85bool MriVolData::read(const QString& path)
86{
87 // Dispatch on filename suffix so callers can use the same one-shot loader
88 // for FreeSurfer MGH/MGZ and NIfTI-1 (.nii / .nii.gz) volumes.
89 const QString lower = path.toLower();
90 if (lower.endsWith(QStringLiteral(".nii")) || lower.endsWith(QStringLiteral(".nii.gz"))) {
91 return MriNiftiIO::read(path, *this);
92 }
93 QVector<FIFFLIB::FiffCoordTrans> additionalTrans;
94 return MriMghIO::read(path, *this, additionalTrans);
95}
96
97//=============================================================================================================
98
99QVector<float> MriVolData::voxelDataAsFloat() const
100{
101 if (slices.isEmpty() || width <= 0 || height <= 0 || depth <= 0)
102 return {};
103
104 const int nPixels = width * height;
105 QVector<float> result(static_cast<qsizetype>(width) * height * depth, 0.0f);
106
107 for (int k = 0; k < depth && k < slices.size(); ++k) {
108 const MriSlice& slice = slices[k];
109 int offset = k * nPixels;
110
111 switch (slice.pixelFormat) {
113 for (int p = 0; p < qMin(nPixels, slice.pixels.size()); ++p)
114 result[offset + p] = static_cast<float>(slice.pixels[p]);
115 break;
117 for (int p = 0; p < qMin(nPixels, slice.pixelsWord.size()); ++p)
118 result[offset + p] = static_cast<float>(slice.pixelsWord[p]);
119 break;
121 for (int p = 0; p < qMin(nPixels, slice.pixelsFloat.size()); ++p)
122 result[offset + p] = slice.pixelsFloat[p];
123 break;
124 }
125 }
126
127 return result;
128}
129
130//=============================================================================================================
131
133{
134 //
135 // Build voxel-to-surface-RAS transform (FreeSurfer convention).
136 //
137 // The direction cosine matrix Mdc stores the orientation of each voxel axis
138 // (columns are x, y, z directions). Scaling by voxel size gives the actual
139 // spacing matrix M:
140 //
141 // M = Mdc * diag(xsize, ysize, zsize)
142 //
143 // The origin P0 in RAS coordinates is:
144 //
145 // P0 = c_ras - M * (dim/2)
146 //
147 // The full 4x4 vox2ras matrix is:
148 //
149 // | M P0 | (in mm, then converted to meters for FIFF)
150 // | 0 1 |
151 //
152 // Reference: https://surfer.nmr.mgh.harvard.edu/fswiki/FsTutorial/MghFormat
153 //
154
155 // Construct M = Mdc * D (scale direction cosines by voxel sizes)
156 Matrix3f M;
157 M.col(0) = x_ras * xsize;
158 M.col(1) = y_ras * ysize;
159 M.col(2) = z_ras * zsize;
160
161 // Compute center voxel
162 Vector3f center(static_cast<float>(width) / 2.0f,
163 static_cast<float>(height) / 2.0f,
164 static_cast<float>(depth) / 2.0f);
165
166 // Compute P0 = c_ras - M * center
167 Vector3f P0 = c_ras - M * center;
168
169 // Build 4x4 matrix in meters (FreeSurfer uses mm, FIFF uses meters)
170 Matrix4f vox2ras = Matrix4f::Identity();
171 vox2ras.block<3, 3>(0, 0) = M / 1000.0f;
172 vox2ras.block<3, 1>(0, 3) = P0 / 1000.0f;
173
174 return vox2ras;
175}
176
177//=============================================================================================================
178
180{
181 // Same as computeVox2Ras() but with c_ras = (0,0,0).
182 // This gives the tkregister (surface RAS) coordinate system
183 // that FreeSurfer surfaces use.
184 Matrix3f M;
185 M.col(0) = x_ras * xsize;
186 M.col(1) = y_ras * ysize;
187 M.col(2) = z_ras * zsize;
188
189 Vector3f center(static_cast<float>(width) / 2.0f,
190 static_cast<float>(height) / 2.0f,
191 static_cast<float>(depth) / 2.0f);
192
193 Vector3f P0 = -M * center; // c_ras = (0,0,0) for tkRAS
194
195 Matrix4f vox2ras_tkr = Matrix4f::Identity();
196 vox2ras_tkr.block<3, 3>(0, 0) = M / 1000.0f;
197 vox2ras_tkr.block<3, 1>(0, 3) = P0 / 1000.0f;
198
199 return vox2ras_tkr;
200}
NIfTI-1 single-file (.nii / .nii.gz) volume reader producing the same per-slice layout as the MGH rea...
FreeSurfer MGH / MGZ volume reader: byte-level decoder for the 284-byte fixed header,...
Format-agnostic in-memory representation of a 3D MRI volume plus its slice decomposition.
FIFF tag-kind, block-kind and type-code numerical definitions, authoritative for FIFFLIB.
#define FIFFV_MRI_PIXEL_BYTE
Definition fiff_file.h:695
#define FIFFV_MRI_PIXEL_FLOAT
Definition fiff_file.h:698
#define FIFFV_MRI_PIXEL_WORD
Definition fiff_file.h:696
Volume I/O, voxel geometry and slice resampling for structural MRI data inside mne-cpp.
constexpr int MRI_MGH_VERSION
Definition mri_types.h:50
constexpr int MRI_UCHAR
Definition mri_types.h:68
static bool read(const QString &mgzFile, MriVolData &volData, QVector< FIFFLIB::FiffCoordTrans > &additionalTrans, const QString &subjectMriDir=QString(), bool verbose=false)
static bool read(const QString &niiFile, MriVolData &volData, bool verbose=false)
Single 2D MRI slice (pixels + slice→RAS transform) used as the volume's storage unit.
QVector< unsigned char > pixels
QVector< unsigned short > pixelsWord
QVector< float > pixelsFloat
Eigen::Vector3f y_ras
Eigen::Matrix4f computeVox2RasTkr() const
bool read(const QString &path)
bool isValid() const
Eigen::Vector3f x_ras
QVector< MriSlice > slices
Eigen::Matrix4f computeVox2Ras() const
Eigen::Vector3f z_ras
Eigen::Vector3f c_ras
QVector< float > voxelDataAsFloat() const