Skip to main content

MriVolData

Namespace: MRILIB  ·  Library: MRI Library

#include <mri/mri_vol_data.h>

class MRILIB::MriVolData

Format-agnostic 3D MRI volume: header geometry, voxel buffer (as a vector of MriSlice), scan parameters and provenance.

The volume is the single in-memory representation every consumer in mne-cpp operates on, regardless of whether it was loaded from MGH/MGZ, NIfTI-1 or a FreeSurfer COR directory. Storage is decomposed into a vector of MriSlice so the COR.fif writer can serialise without an intermediate copy, while the slice viewer and the BEM coregistration step both index it through the same (column, row, slice) coordinate.

The header captures FreeSurfer's MGH conventions: voxel sizes (spacingX/Y/Z), direction cosines (Mdc, column-major), centre RAS (c_ras) and voxel data type (MRI_UCHAR / MRI_INT / MRI_FLOAT / MRI_SHORT). Optional scan parameters (TR, flip angle, TE, TI, FoV) and tags (Talairach transform path, provenance) round out the structure. The read() entry point dispatches on the file extension so callers do not need to branch on format.

Format reference: https://surfer.nmr.mgh.harvard.edu/fswiki/FsTutorial/MghFormat

Ported from mneMRIdataRec in MNE C (mne_types_mne-c.h) by Matti Hamalainen.

src/examples/ex_mri/main.cpp
MriVolData nifti;
nifti.read(dataDir + "/gradient.nii.gz"); // the suffix selects the NIfTI reader

Public Methods​

MriVolData()​

Default constructor.


read(path)​

Convenience loader: reads an MGH/MGZ file and populates this volume.

Wraps MriMghIO::read() so callers don't need to manage a separate additionalTrans vector. Mirrors MNE-Python's nib.load(path) one-liner.

Parameters:

  • path : const QString & Path to the .mgh or .mgz file.

Returns:

  • bool — True on success, false on error.

isValid()​

Returns whether this volume contains valid data.

Returns:

  • bool — True if the volume has been loaded successfully.

dimX()​

Returns:

  • int — First (x) dimension — fastest-varying axis.

dimY()​

Returns:

  • int — Second (y) dimension.

dimZ()​

Returns:

  • int — Third (z) dimension — slowest-varying axis.

dims()​

Returns:

  • QVector< int > — Volume dimensions as {dimX, dimY, dimZ}.

voxelDataAsFloat()​

Returns all voxel data as a contiguous float array in x-fastest order.

Mirrors MNE-Python's img.get_fdata().ravel(order='F'). Regardless of the on-disk type (UCHAR, SHORT, INT, FLOAT) the output is always float. The array length is width` * `height` * `depth.

Returns:

  • QVector< float > — Flat voxel data; empty vector if the volume has no slices.

computeVox2Ras()​

Builds the voxel-to-surface-RAS (MRI) 4×4 transform matrix.

Following FreeSurfer convention: M = Mdc * diag(xsize, ysize, zsize) P0 = c_ras - M * (dim/2) vox2ras = | M P0 | (in mm, converted to meters for FIFF) | 0 1 |

Returns:

  • Eigen::Matrix4f — The 4×4 voxel-to-scanner-RAS transform in meters.

computeVox2RasTkr()​

Builds the voxel-to-surface-RAS (tkRAS / tkregister) 4×4 transform.

Identical to computeVox2Ras() but forces c_ras = (0,0,0), producing the coordinate system used by FreeSurfer surfaces (lh.white, etc.).

Returns:

  • Eigen::Matrix4f — The 4×4 voxel-to-tkRAS transform in meters.

Example​

Used in examples​

ex_mri​

MRI library: MGH/MGZ and NIfTI volumes, voxel/RAS transforms, slicing and COR sets.

src/examples/ex_mri/main.cpp, line 92
MriVolData mgh;
QVector<FiffCoordTrans> extraTransforms; // e.g. Talairach, if the footer names one
MriMghIO::read(dataDir + "/gradient.mgz", mgh, extraTransforms);
const Matrix4f vox2ras = mgh.computeVox2Ras(); // scanner RAS, metres
const QVector<float> voxels = mgh.voxelDataAsFloat(); // x fastest
Matrix4f vox2rasMm = vox2ras;
vox2rasMm.block<3, 4>(0, 0) *= 1000.0f;
ok &= expect(mgh.dims() == QVector<int>({6, 5, 4}) && (vox2rasMm - nibabelAffine).cwiseAbs().maxCoeff() < 1e-4f && voxels.size() == 120 && voxels[2 + 6 * (3 + 5 * 1)] == 82.0f,
"MGZ: 6x5x4 voxels, vox2ras and voxel (2,3,1) = 82 match nibabel");

Authors of this file​