56 switch (orientation) {
61 return Vector3f::UnitZ();
66 switch (orientation) {
71 return Vector3f::UnitX();
76 switch (orientation) {
81 return Vector3f::UnitY();
84int bestVoxelAxisForDirection(
const Matrix4f& vox2ras,
85 const Vector3f& target,
86 const std::array<bool, 3>& used)
89 float bestScore = -1.0f;
91 for (
int axis = 0; axis < 3; ++axis) {
95 Vector3f axisDirection = vox2ras.block<3, 1>(0, axis);
96 const float norm = axisDirection.norm();
98 axisDirection /= norm;
100 const float score = std::abs(axisDirection.dot(target));
101 if (score > bestScore) {
110PlaneSpec planeSpecForOrientation(
const Matrix4f& vox2ras,
113 std::array<bool, 3> used = {
false,
false,
false};
114 const int fixedAxis = bestVoxelAxisForDirection(vox2ras,
115 anatomicalNormal(orientation),
117 used[fixedAxis] =
true;
119 const int columnAxis = bestVoxelAxisForDirection(vox2ras,
120 anatomicalColumnDirection(orientation),
122 used[columnAxis] =
true;
124 const int rowAxis = bestVoxelAxisForDirection(vox2ras,
125 anatomicalRowDirection(orientation),
128 return {columnAxis, rowAxis, fixedAxis};
131int axisDimension(
const QVector<int>& dims,
int axis)
136int flatIndex(
int x,
int y,
int z,
int dimX,
int dimY)
138 return x + dimX * (y + dimY * z);
148 const QVector<float>& volData,
149 const QVector<int>& dims,
150 const Matrix4f& vox2ras,
154 const int dimX = dims[0];
155 const int dimY = dims[1];
156 const PlaneSpec spec = planeSpecForOrientation(vox2ras, orientation);
157 const int width = axisDimension(dims, spec.columnAxis);
158 const int height = axisDimension(dims, spec.rowAxis);
159 const int fixedDim = axisDimension(dims, spec.fixedAxis);
161 sliceIndex = std::clamp(sliceIndex, 0, fixedDim - 1);
163 MriSliceImage result;
165 result.
width = width;
168 result.
pixels.resize(width, height);
170 for (
int row = 0; row < height; ++row) {
171 for (
int col = 0; col < width; ++col) {
172 std::array<int, 3> voxel = {0, 0, 0};
173 voxel[spec.columnAxis] = col;
174 voxel[spec.rowAxis] = row;
175 voxel[spec.fixedAxis] = sliceIndex;
176 result.
pixels(col, row) = volData[flatIndex(voxel[0], voxel[1], voxel[2], dimX, dimY)];
181 result.
sliceToRas.col(0) = vox2ras.col(spec.columnAxis);
182 result.
sliceToRas.col(1) = vox2ras.col(spec.rowAxis);
183 result.
sliceToRas.col(2) = vox2ras.col(spec.fixedAxis);
184 Vector4f origin = Vector4f::Zero();
185 origin(spec.fixedAxis) =
static_cast<float>(sliceIndex);
190 float minVal = result.
pixels.minCoeff();
191 float maxVal = result.
pixels.maxCoeff();
192 if (maxVal > minVal) {
193 result.
pixels = (result.
pixels.array() - minVal) / (maxVal - minVal);
206 return planeSpecForOrientation(vox2ras, orientation).fixedAxis;
212 const Matrix4f& vox2ras,
222 const Vector3i& voxel)
230 const QVector<float>& volData,
231 const QVector<int>& dims,
232 const Matrix4f& vox2ras,
233 const Vector3f& rasPoint)
235 Vector3i voxel =
rasToVoxel(vox2ras, rasPoint);
237 QVector<MriSliceImage> slices;
252 const Vector3f& rasPoint)
254 Matrix4f ras2vox = vox2ras.inverse();
256 rasH << rasPoint, 1.0f;
257 Vector4f voxH = ras2vox * rasH;
260 static_cast<int>(std::round(voxH.x())),
261 static_cast<int>(std::round(voxH.y())),
262 static_cast<int>(std::round(voxH.z()))
269 const Vector3i& voxel)
272 voxH << static_cast<float>(voxel.x()),
273 static_cast<float>(voxel.y()),
274 static_cast<float>(voxel.z()),
276 Vector4f rasH = vox2ras * voxH;
278 return rasH.head<3>();
313 const Vector3i& voxel)
321 const Vector3f& rasPoint)
330 const Vector3f& rasPoint)
338 const Vector3i& voxel)
Orthogonal-plane resampler that turns a 3D MriVolData into the 2D textures consumed by the slice view...
Format-agnostic in-memory representation of a 3D MRI volume plus its slice decomposition.
Volume I/O, voxel geometry and slice resampling for structural MRI data inside mne-cpp.
Single 2D MRI cross-section produced by MriSlicer (pixel buffer + RAS metadata).
Eigen::Matrix4f sliceToRas
SliceOrientation orientation
static Eigen::Vector3f voxelToRas(const Eigen::Matrix4f &vox2ras, const Eigen::Vector3i &voxel)
static MriSliceImage extractSlice(const QVector< float > &volData, const QVector< int > &dims, const Eigen::Matrix4f &vox2ras, SliceOrientation orientation, int sliceIndex)
static Eigen::Vector3i rasToVoxel(const Eigen::Matrix4f &vox2ras, const Eigen::Vector3f &rasPoint)
static int voxelAxisForOrientation(const Eigen::Matrix4f &vox2ras, SliceOrientation orientation)
static int sliceIndexForOrientation(const Eigen::Matrix4f &vox2ras, SliceOrientation orientation, const Eigen::Vector3i &voxel)
static QVector< MriSliceImage > extractOrthogonal(const QVector< float > &volData, const QVector< int > &dims, const Eigen::Matrix4f &vox2ras, const Eigen::Vector3f &rasPoint)
static int dimensionForOrientation(const QVector< int > &dims, const Eigen::Matrix4f &vox2ras, SliceOrientation orientation)
Format-agnostic 3D MRI volume: header geometry, voxel buffer (as a vector of MriSlice),...
Eigen::Matrix4f computeVox2RasTkr() const
QVector< int > dims() const
QVector< float > voxelDataAsFloat() const