MR RawDeface is a tool for defacing multi-channel raw 3D MRI brain data. Instead of defacing reconstructed images which permanently alters the raw k-space data, MR RawDeface defaces in k-space to preserve the raw data. This defaced data can then be used and shared for reconstruction research, for which both preserving raw data's integrity and protecting the privacy of participants are important.
We use the region-optmized virtual coils (ROVir) [1] framework to locally supress facial signal in k-space. We take the following steps in this pipeline:
(1) We make an initial reconstruction to define the brain and face regions.
(2) We employ TotalSegmentator's face_mr and total_mr tasks [2] to automatically generate a mask for the face and brain regions. We manipulate these masks to simplify their geometry and create space between them to optimize masking for the ROVir framework.
(3) We define a ROVir transform based on these masks. This transform mixes the original measurement coils to form virtual coils, with signal concentrated in either the brain or face regions. You can see the effect in demo.ipynb, where the virtual coils are displayed.
(4) We retain only the top virtual coils with only high brain region signal and discard the virtual coils that have high face region signal. Combining only the top virtual coils yields defaced k-space data.
The benefit of this pipeline is that we act on the coil dimension, discarding only coils with high face region signal, thus preserving raw k-space data. Currently, we have evaluated the pipeline using 14 sets of 12-channel data from Calgary Campinas [3] and one in-house obtained 48-channel dataset. On avergae, we saw a 64.3% brain retention and 1.5% face retention in the 12-channel datasets. For the 48-channel dataset, there was a 89% brain retention and 1.8% face retention. The number of channels your data has may affect the defacing abilities.
Set up a Python environment for MR RawDeface
conda create -n RawDeface python=3.13
Install TotalSegmentator and the following required dependencies
pip install kneed==0.7.0
pip install matplotlib==3.10.3
pip install nibabel==5.3.2
pip install numpy==1.26.4
pip install scipy==1.15.3
pip install scikit-image==0.25.2
pip install TotalSegmentator==2.10.0
pip install PyQt5==5.15.11
Alternatively, you may use the requirements.txt file to quickly install the dependencies using
pip install -r requirements.txt
Clone and open this GitHub repository
git clone https://github.com/chiew-group/MRI-defacer.git
cd MRI-defacer
Note: our pipeline uses the face_mr task from TotalSegmentator, which requires a free non-commercial use license. You must obtain and activate the license before using this tool. You can find out how to do so from the TotalSegmentator repository [2].
After cloning the repository, create config file(s) to specify your inputs. See config.json for the expected file structure. A description of each field can be found in the Expected Input section. Then, use the following command to run the program:
python raw_deface.py --config config.json
If the config file is not specified by the user, the pipeline will use the default config.json file. Given the expected input formats, this tool is fully automated. The output is the defaced raw k-space data.
The image shape and affine matrix of the user's dataset must be specified in the config.json file for the program to handle the orientation correctly.
The format of the k-space data will be manipulated to have the shape (x, y, z, channel), where the x-axis corresponds to sagittal slices, y-axis corresponds to coronal slices, and z-axis corresponds to axial slices. In addition, the voxel spacings will be manipulated to agree with all positive voxel spacings (e.g., +1mm).
| Parameter | Expected Type | Description |
|---|---|---|
| data_path | string | path to raw 4D numpy k-space data |
| data_id | string | ID for data ouput paths |
| x_y_z_channel | list | see explanation below * |
| a11 | float | x-axis image voxel resolution (millimeters) |
| a22 | float | y-axis image voxel resolution (millimeters) |
| a33 | float | z-axis image voxel resolution (millimeters) |
| x_slice | int | slice number for sagittal view |
| y_slice | int | slice number for coronal view |
| z_slice | int | slice number for axial view |
| plt_on | boolean | option to visualize defaced image |
| compare_retention | boolean | option to visualize defacing effect for different coil retention strength |
| show_virtual_coils | boolean | option to visualize individual virtual coils |
| threshold_method | string | 'SIR', 'brain_retain', 'face_retain' * |
| threshold_value | int or null | see explanation below * |
| top_coils | int | option to manually select top virtual coils |
| face_mask | string | optional predefined face mask provided by user |
| brain_mask | string | optional predfined brain mask provided by user |
| manipulation | string | specify manipulation scheme for segmentation results * |
| gap | int | size of gap between face and brain mask * |
| save_defaced_kspace | boolean | option to save defaced k-space data to resulsts folder as a numpy array |
| save_defaced_image | boolean | option to save defaced k-space data to results folder as a NIfTI file |
If top_coils is not specified, then the selected threshold_method and the corresponding threshold_value will be used as a heuristic for determining the top virtual coils to form the defaced data. Additionally, the user can optionally provide their own face_mask and brain_mask. If these are not specified, then the segmentation tool implemented in this pipeline will compute a face and brain mask. The user can also optionally provide the data_path, data_id, channel, and affine elements of a reference dataset to generate the face and brain masks, which will be applied on the target dataset for defacing. Simply add the following lines to the config.json file:
"reference_data": {"data_path": "input/example.npy",
"data_id": "reference",
"x_y_z_channel": [0, 1, 2, 3],
"a11": 1,
"a22": 1,
"a33": -1},
An example of a config.json file with the proper structure and all parameters specified looks like this:
{
"input_data": {"data_path": "input/test03.npy",
"data_id": "03x",
"x_y_z_channel": [0, 1, 2, 3],
"a11": 1,
"a22": 1,
"a33": -1},
"reference_data": {"data_path": "input/example.npy",
"data_id": "reference",
"x_y_z_channel": [0, 1, 2, 3],
"a11": 1,
"a22": 1,
"a33": -1},
"visualization": {"x_slice": 80,
"y_slice": 80,
"z_slice": 120,
"plt_on": true,
"compare_retention": true,
"show_virtual_coils":true},
"coil_selection": {"threshold_method": "face_retained",
"threshold_value": 10,
"top_coils": 10},
"masks": {"face_mask":"segmentations/output_mask_03x/face.nii.gz",
"brain_mask":"segmentations/output_mask_03x/brain.nii.gz",
"manipulation": "A",
"gap": 10},
"output":{"save_defaced_kspace": true,
"save_defaced_image": true}
}
This parameters specifices the quantitative metric used to select the top virtual coils to retain in the final defaced data (see Brief Pipeline Overview step (4)). We suggest using the default method we tested using our data, but leave options for exploration if needed:
(A) if 'SIR' is chosen, the signal-to-interference ratio, or in this case the brain-to-face signal ratio, of each virtual coil is used to choose the top coils. A high SIR is desirable.
(B) if 'brain_retain' is chosen, the percentage signal left from the brain region defined by the automated masking as a function of the number of virtual coils retained is used to choose the top coils. A high brain retention is desirable.
(C) if 'face_retain' is chosen, the percentage signal left from the face region defined by the automated masking as a function of the number of virtual coils retained is used to choose the top coils. A low face retention is desirable.
This parameter specifies a heuristic for choosing the top virtual coils. We again recommend you to use the default of 2 along with the default threshold_method. For example, if threshold_method = 'face_retain' and threshold_value = '2', then the tool retains virtual coils, starting from those with highest brain signal, until a maximum 2% face signal is retained. You can also set threshold_value = null, in which case the tool will use an elbow-finding algorithm to choose the top virtual coils based on the curves formed by the metrics.
Here is an example of the curves generated from each threshold_method for your reference if you choose to experiment with these parameters:

This parameters specifies the amount times the face mask is shrunk to create a gap between the face mask and brain mask. We recommend to use the default gap of 10, as that works well with our current masking scheme.
If the current shape of the data is not the required data.shape = (x, y, z, ch), the user can specify how the current data shape maps to the required data shape using a list. The first element specifies the current index of the x-axis in data.shape, the second element specifies the current index of the y-axis in data.shape, the third element specifies the current index of the z-axis in data.shape, and the fourth element specifies the current index of the channel dimension in data.shape. For example, if x_y_z_channel = [2, 0, 1, 3] is specified, it means the current axis 0 corresponds to y, the current axis 1 corresponds to z, the current axis 2 corresponds to x, and the current axis 3 corresponds to channels (i.e. data.shape = (y, z, x, ch)).
The user may want to take the raw output from the segmentation (in which case the manipulation parameter can be omitted), or explore the different mask manipulation schemes. The available options are no manipulations (when parameter is unspecified in config file), "A", and "B". An example of mask manipulation schemes "A" and "B" is shown in the demo_64ch.ipynb notebook.
After running main.py, the final defaced k-space data should exist in a folder named results as defaced_{dataID}.npy. You can see example outputs in the demo.ipynb Notebook. The example uses a fully sampled 12-channel dataset from Calgary Campinas [3] preprocessed to be oriented as outlined in Expected Input and our default parameters in config.json.
The example uses a fully sample 64-channel dataset that can be found here: https://huggingface.co/datasets/lyx228/Fully_Sampled_MRI/tree/main.
- You may uncomment line 199 in main.py to see a comparison of the brain and face retention versus the number of top virtual coils retained.
compare_retention(data, eigenvec, brain_covar, face_covar, nc, x_slice) # visualize comparison between different # of coils retained
- You may uncomment line 200 in main.py to see all virtual coils.
show_virtual_coils(data, eigenvec, x_slice) # visualize all individual virtual coils
- Wrong affine or orientation: check the shape of your data and the voxel spacing. This affects the ability of TotalSegmentator to identify the brain and face regions. The expected orientations as outlined in Expected Input has worked in our testing. Check the segmentation results in a folder named segmentation.
- Poor threshold heuristic: the threshold_method and threshold parameters in config.json may not be generalizable to your data. You may view the metric curves and adjust accordingly.
- The NIfTI version of your input may not have been generated well. You can check the input after coverting into a NIfTI image, which can be found in a folder named input using 3DSlicer. Note in to_nifti.py, the image intensity is max-min normalized to 0-255.
- Ensure that you have obtained and activated a license for the face_mr task from TotalSegmentator. Otherwise, the TotalSegmentator call will fail.