v2.0.0
Loading...
Searching...
No Matches
mri_slicer.cpp
Go to the documentation of this file.
1//=============================================================================================================
34
35//=============================================================================================================
36// INCLUDES
37//=============================================================================================================
38
39#include "mri_slicer.h"
40#include "mri_vol_data.h"
41
42#include <Eigen/LU>
43
44#include <algorithm>
45#include <cmath>
46
47//=============================================================================================================
48// USED NAMESPACES
49//=============================================================================================================
50
51using namespace MRILIB;
52using namespace Eigen;
53
54//=============================================================================================================
55// STATIC METHODS
56//=============================================================================================================
57
59 const QVector<float>& volData,
60 const QVector<int>& dims,
61 const Matrix4f& vox2ras,
62 SliceOrientation orientation,
63 int sliceIndex)
64{
65 const int dimX = dims[0];
66 const int dimY = dims[1];
67 const int dimZ = dims[2];
68
69 MriSliceImage result;
70 result.orientation = orientation;
71
72 switch (orientation) {
74 sliceIndex = std::clamp(sliceIndex, 0, dimZ - 1);
75 result.width = dimX;
76 result.height = dimY;
77 result.sliceIndex = sliceIndex;
78 result.pixels.resize(dimX, dimY);
79
80 for (int iy = 0; iy < dimY; ++iy) {
81 for (int ix = 0; ix < dimX; ++ix) {
82 result.pixels(ix, iy) = volData[ix + dimX * (iy + dimY * sliceIndex)];
83 }
84 }
85
86 // sliceToRas: maps (col, row) in the 2D image to RAS
87 // col -> x voxel direction, row -> y voxel direction, fixed z = sliceIndex
88 result.sliceToRas = Matrix4f::Zero();
89 result.sliceToRas.col(0) = vox2ras.col(0); // x direction
90 result.sliceToRas.col(1) = vox2ras.col(1); // y direction
91 result.sliceToRas.col(2) = vox2ras.col(2); // z direction (unused for 2D but kept)
92 Vector4f origin;
93 origin << 0.0f, 0.0f, static_cast<float>(sliceIndex), 1.0f;
94 result.sliceToRas.col(3) = vox2ras * origin;
95 break;
96 }
98 sliceIndex = std::clamp(sliceIndex, 0, dimY - 1);
99 result.width = dimX;
100 result.height = dimZ;
101 result.sliceIndex = sliceIndex;
102 result.pixels.resize(dimX, dimZ);
103
104 for (int iz = 0; iz < dimZ; ++iz) {
105 for (int ix = 0; ix < dimX; ++ix) {
106 result.pixels(ix, iz) = volData[ix + dimX * (sliceIndex + dimY * iz)];
107 }
108 }
109
110 // col -> x direction, row -> z direction, fixed y = sliceIndex
111 result.sliceToRas = Matrix4f::Zero();
112 result.sliceToRas.col(0) = vox2ras.col(0); // x direction
113 result.sliceToRas.col(1) = vox2ras.col(2); // z direction
114 result.sliceToRas.col(2) = vox2ras.col(1); // y direction (unused for 2D but kept)
115 Vector4f originC;
116 originC << 0.0f, static_cast<float>(sliceIndex), 0.0f, 1.0f;
117 result.sliceToRas.col(3) = vox2ras * originC;
118 break;
119 }
121 sliceIndex = std::clamp(sliceIndex, 0, dimX - 1);
122 result.width = dimY;
123 result.height = dimZ;
124 result.sliceIndex = sliceIndex;
125 result.pixels.resize(dimY, dimZ);
126
127 for (int iz = 0; iz < dimZ; ++iz) {
128 for (int iy = 0; iy < dimY; ++iy) {
129 result.pixels(iy, iz) = volData[sliceIndex + dimX * (iy + dimY * iz)];
130 }
131 }
132
133 // col -> y direction, row -> z direction, fixed x = sliceIndex
134 result.sliceToRas = Matrix4f::Zero();
135 result.sliceToRas.col(0) = vox2ras.col(1); // y direction
136 result.sliceToRas.col(1) = vox2ras.col(2); // z direction
137 result.sliceToRas.col(2) = vox2ras.col(0); // x direction (unused for 2D but kept)
138 Vector4f originS;
139 originS << static_cast<float>(sliceIndex), 0.0f, 0.0f, 1.0f;
140 result.sliceToRas.col(3) = vox2ras * originS;
141 break;
142 }
143 }
144
145 // Normalize pixels to [0, 1]
146 float minVal = result.pixels.minCoeff();
147 float maxVal = result.pixels.maxCoeff();
148 if (maxVal > minVal) {
149 result.pixels = (result.pixels.array() - minVal) / (maxVal - minVal);
150 } else {
151 result.pixels.setZero();
152 }
153
154 return result;
155}
156
157//=============================================================================================================
158
159QVector<MriSliceImage> MriSlicer::extractOrthogonal(
160 const QVector<float>& volData,
161 const QVector<int>& dims,
162 const Matrix4f& vox2ras,
163 const Vector3f& rasPoint)
164{
165 Vector3i voxel = rasToVoxel(vox2ras, rasPoint);
166
167 QVector<MriSliceImage> slices;
168 slices.reserve(3);
169 slices.append(extractSlice(volData, dims, vox2ras, SliceOrientation::Axial, voxel.z()));
170 slices.append(extractSlice(volData, dims, vox2ras, SliceOrientation::Coronal, voxel.y()));
171 slices.append(extractSlice(volData, dims, vox2ras, SliceOrientation::Sagittal, voxel.x()));
172
173 return slices;
174}
175
176//=============================================================================================================
177
178Vector3i MriSlicer::rasToVoxel(const Matrix4f& vox2ras,
179 const Vector3f& rasPoint)
180{
181 Matrix4f ras2vox = vox2ras.inverse();
182 Vector4f rasH;
183 rasH << rasPoint, 1.0f;
184 Vector4f voxH = ras2vox * rasH;
185
186 return Vector3i(
187 static_cast<int>(std::round(voxH.x())),
188 static_cast<int>(std::round(voxH.y())),
189 static_cast<int>(std::round(voxH.z()))
190 );
191}
192
193//=============================================================================================================
194
195Vector3f MriSlicer::voxelToRas(const Matrix4f& vox2ras,
196 const Vector3i& voxel)
197{
198 Vector4f voxH;
199 voxH << static_cast<float>(voxel.x()),
200 static_cast<float>(voxel.y()),
201 static_cast<float>(voxel.z()),
202 1.0f;
203 Vector4f rasH = vox2ras * voxH;
204
205 return rasH.head<3>();
206}
207
208//=============================================================================================================
209// MriVolData convenience overloads
210//=============================================================================================================
211
213 SliceOrientation orientation,
214 int sliceIndex)
215{
216 return extractSlice(vol.voxelDataAsFloat(), vol.dims(),
217 vol.computeVox2Ras(), orientation, sliceIndex);
218}
219
220//=============================================================================================================
221
222QVector<MriSliceImage> MriSlicer::extractOrthogonal(const MriVolData& vol,
223 const Vector3f& rasPoint)
224{
225 return extractOrthogonal(vol.voxelDataAsFloat(), vol.dims(),
226 vol.computeVox2Ras(), rasPoint);
227}
228
229//=============================================================================================================
230
231Vector3i MriSlicer::rasToVoxel(const MriVolData& vol,
232 const Vector3f& rasPoint)
233{
234 return rasToVoxel(vol.computeVox2Ras(), rasPoint);
235}
236
237//=============================================================================================================
238
239Vector3f MriSlicer::voxelToRas(const MriVolData& vol,
240 const Vector3i& voxel)
241{
242 return voxelToRas(vol.computeVox2Ras(), voxel);
243}
MriSlicer class declaration.
MriVolData class declaration.
MRI volume and coordinate-system I/O (volumes, voxel geometry, transforms).
SliceOrientation
Definition mri_slicer.h:72
Extracted MRI slice image.
Definition mri_slicer.h:81
Eigen::Matrix4f sliceToRas
Definition mri_slicer.h:87
SliceOrientation orientation
Definition mri_slicer.h:85
Eigen::MatrixXf pixels
Definition mri_slicer.h:82
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 QVector< MriSliceImage > extractOrthogonal(const QVector< float > &volData, const QVector< int > &dims, const Eigen::Matrix4f &vox2ras, const Eigen::Vector3f &rasPoint)
MRI volume data from FreeSurfer MGH/MGZ file.
QVector< int > dims() const
Eigen::Matrix4f computeVox2Ras() const
QVector< float > voxelDataAsFloat() const