Splitting 4D Nifti file into a series of 3D files in Matlab

NIfTI-1 is a data format proposed by the NifTI (Neuroimaging Informatics Technology Initiative) DFWG (Data Format Working Group) that can be used for storing neuroimaging datasets (e.g. MRI, functional MRI, etc.). This format is adapted from the widely used ANALYZE 7.5 format from Mayo Clinic. A Nifti file consists of a header part containing the meta-data and the raw image data itself. The header and the image data can be stored together in the same file with an *.nii extension or can be split into two files with an *.hdr extension for the header and an *.img extension for the image data.

For functional MRI, it is not uncommon to store the dataset in a single 4D (3D space + time) Nifti file, especially when experiments involved several hundreds of image volumes. Just imagine the convenience of working with a single file as compared to several hundreds of files. However, there are also instances when it is convenient to manipulate datasets one volume at a time. In this case, having a single volume stored in a single file is very handy.

In this post, I will outline a Matlab script that can be used to extract the 3D images from the 4D NifTI file. The script uses some SPM functions such as spm_select()spm_vol()spm_read_vols(), and spm_write_vol(). Type “help function_name” in Matlab for a description of each function. Be sure that SPM is in Matlab’s path before using this script.

Without further ado, here is the full function list:

function abk_4Dto3D(fname)
% function abk_4Dto3D(fname)
%
% Splits a 4D nifti file into a series of 3D nifti files.
% Needs SPM functions to work. If input file is fdata.nii,
% the output files will have filenames like fdata_001.nii,
% fdata_002.nii, etc.
 
if (nargin < 1)
    [fname,sts] = spm_select;
    if (sts == 0)
        fprintf('abk_4Dto3D: Operation cancelled.n');
        return;
    end
end
 
vol = spm_vol(fname);
img = spm_read_vols(vol);
sz = size(img);
 
tvol = vol(1);
tvol = rmfield(tvol,'private');
tvol.descrip = 'generated by abk_4Dto3D.m';
 
[dn,fn,ext] = fileparts(fname);
 
for ctr=1:sz(4)
    tvol.fname = sprintf('%s%s%s_%.3d%s',dn,filesep,fn,ctr,ext);
    fprintf('Writing %s\n',tvol.fname);
    spm_write_vol(tvol,img(:,:,:,ctr));
end
fprintf('done.n');
end

The script accepts the filename, given by the fname input parameter, of the 4D Nifti file. If fname is not specified, the script will prompt the user to select a file using spm_select() (line 10). Once the filename is specified, it will then read the 4D image data, and save it back one 3D image at a time.

Now to the code. Line 1 is simply the usual Matlab function declaration. This is followed by several lines of comments starting with the % character (lines 2 – 7). In line 9, the script checks if the function was called with an input parameter. If none was provided, it prompts the user to make a selection (line 10). It then checks if the user cancelled the operation (lines 11 – 14) and returns if true. Otherwise, it reads the header information using SPM’s spm_vol() function (line 17), loads the 4D data into the img variable (line 18) using spm_read_vols(), and gets the image dimension and store it in sz (line 19).

In lines 21 – 23, the header information is copied into the tvol variable (line 21), which will be used later to save the images. The private field of tvol is then removed (line 22) and the header description is changed (line 23) to indicate the new file generator. In line 25, the filename is split into three variables dnfn, and ext corresponding to the directory location, the base filename, and the extension, respectively.

In lines 27 – 31 is where the 4D image data is actually split into a series of 3D image files. Note how the variable tvol is repeatedly used, changing only the fname field each time. This is because the 3D images have basically the same header information.

Note that the same function could also be used to extract only certain volumes from the 4D nifti files with a slight modification. To implement this, we need to change the function declaration in line 1 into function abk_4Dto3D(fname,idx), where the additional parameter idx is a vector containing the volume numbers to extract. We also need to change lines 27 – 31 as follows:

for ctr=1:length(idx)
    tvol.fname = sprintf('%s%s%s_%.3d%s',dn,filesep,fn,ctr,ext);
    fprintf('Writing %sn',tvol.fname);
    spm_write_vol(tvol,img(:,:,:,idx(ctr)));
end

ctr now runs from 1 to the number of volumes to extract given by the length of idx. The filenames will still be consecutively numbered from 1 to the length of idx (line 2). But this time, the 3D images that are saved are only the volumes specified in idx (line 4).

Have questions, leave a comment.

You may also like...

2 Responses

  1. Dear Dr. Epifanio Bagarinao,

    Thanks a lot for sharing your script: Splitting 4D Nifti file into a series of 3D files in Matlab. It’s indeed very useful if one manage to iterate it over a group of participants. I tested initially with 2 participants, but I got the following error:

    >> abk_4Dto3D
    Error using fileparts (line 41)
    Input must be a row vector of characters or string scalar.

    Error in abk_4Dto3D (line 25)
    [dn,fn,ext] = fileparts(fname);

    My data (4D .nii flies) is arranged as follows:
    S001-> wFiltered_4DVolume
    S002-> wFiltered_4DVolume

    P.D. It works when I convert only 1 participant. To recall , this also can be achieved throught the SPM12 batch -> batch -> SPM -> Util -> 4D to 3D

    Many thanks in advance to letting me know how can I iterate your conde over my group.

    Best regards,

    Julian G.

    • baggy says:

      Dear Julian,

      Thanks for your email. The script was intended to process only one nifti file. If you want to process several nifti files, you can try the script in this URL: https://myguide.bagarinao.com/batch-processing-in-spm/, specifically File 6 (segment.m). Just replace the body of the for loop as follows:

      for ctr = 1:numSubj
      abk_4Dto3D(subjId{ctr});
      end

      and create a text file containing the full path of each nifti image. One filename per line. An example is in File 7.

      Basically, the script reads each line in the text file into the subjId variable to get the filenames and process each file one at a time in the for loop. For it to work, you will need:
      1) abk_4Dto3D.m
      2) modified segment.m or you can rename it
      3) the text file containing the list of filenames

      Hope this helps. Let me know if you have additional questions.

Leave a Reply