Routine that outputs PET scanner metadata following BIDS.

The metadata generated here are passed along imaging data to the converters, ecat2nii.m or dcm2niix4pet.m allowing to produce a .nii file with a BIDS compliant json file.

  • Default – (aquisition and reconstruction parameters) can be stored in a *_parameters.txt seating on disk next to this function or passed as argument in. Replace * by the name of your scanner - for now we tested ‘SiemensBiograph’, ‘SiemensHRRT’, ‘GEAdvance’, ‘PhillipsVereos’, ‘PhillipsIngenuityPETMR’,’PhillipsIngenuityPETCT’. (see templates, as some info can be recovered from ecat or dcm - ie not all info is necessarily needed)

  • inputs – a series of key/value pairs are expected

Returns metadata

a structure with BIDS fields filled (such structure is ready to be writen as json file using e.g. the bids matlab jsonwrite function, typically associated with the *_pet.nii file)


metadata = get_pet_metadata(key,value)


Mandatory inputs are as follows:

  • Scanner name of scanner, map to a *parameters.txt file e.g. ‘Scanner’, ‘SiemensBiograph’

  • TimeZero when was the tracer injected e.g. ‘TimeZero’,’11:05:01’

  • ModeOfAdministration e.g. ‘ModeOfAdministration’, ‘bolus’

  • TracerName which tracer was used e.g. ‘TracerName’,’DASB’

  • TracerRadionuclide which nuclide was used e.g. ‘TracerRadionuclide’,’C11’

+ at least 2 of those key/value arguments to infer others:

  • InjectedRadioactivity value in MBq e.g. ‘InjectedRadioactivity’, 605.3220

  • InjectedMass Value in ug e.g. ‘InjectedMass’, 1.5934

  • MolarActivity value in GBq/umol e.g. ‘MolarActivity’, 107.66

  • MolecularWeight value in g/mol e.g. ‘MolecularWeight’, 15.02

  • SpecificRadioactivity in Bq/g or Bq/mol e.g. ‘SpecificRadioactivity’, 3.7989e+14

Here is an example of such defaults, used at NRU for our SiemensBiograph_parameters.txt

InstitutionName            = 'Rigshospitalet, NRU, DK';
BodyPart                   = 'Phantom';
AcquisitionMode            = 'list mode';
ImageDecayCorrected        = 'true';
ImageDecayCorrectionTime   = 0;
ReconFilterType            = 'none';
ReconFilterSize            = 0;
AttenuationCorrection      = '10-min transmission scan';
FrameDuration              = 1200;
FrameTimesStart            = 0;


TimeZero also can be [] or ‘ScanStart’ indicating that the scanning time should be used as TimeZero. If TimeZero is not the scan time, we strongly advice to input ScanStart and InjectionStart making sure timing is correct




meta = get_pet_metadata('Scanner','SiemensBiograph','TimeZero','ScanStart',...
                      'TracerName','CB36','TracerRadionuclide','C11', ...
                      'ModeOfAdministration','infusion','SpecificRadioactivity', ...
                       605.3220,'InjectedMass', 1.5934,'MolarActivity', 107.66);
      --> will issue warnings without a SiemensBiographparameters.txt next to this function

meta = get_pet_metadata('Scanner','SiemensBiograph','TimeZero','ScanStart',...
          'TracerName','CB36','TracerRadionuclide','C11', 'ModeOfAdministration',...
          'infusion','SpecificRadioactivity', 605.3220,'InjectedMass', 1.5934,...
          'MolarActivity', 107.66, 'InstitutionName','Rigshospitalet, NRU, DK',...
          'AcquisitionMode','list mode','ImageDecayCorrected','true',...
          'ImageDecayCorrectionTime' ,0,'ReconMethodName','OP-OSEM',...
          'ReconMethodParameterUnits',{'none','none'}, ...
          'ReconMethodParameterValues',[21 3], 'ReconFilterType','XYZGAUSSIAN',...
          'ReconFilterSize',2, 'AttenuationCorrection','MR-based attenuation correction');
     --> works without txt file because all arguments are passed
Neurobiology Research Unit, Rigshospitalet
Martin Nørgaard & Cyril Pernet - 2021
Copyright Open NeuroPET team
matlab.dcm2niix4pet(FolderList, MetaList, varargin)
Converts dicom image file to nifti+json calling dcm2niix augmenting the

json file to be BIDS compliant. Note that you are always right when it comes to metadata! DICOM values to be used in the json will be ignored, always using the meta data provided - BUT DICOM values are checked and the code tells you if there is inconsistency between your inputs and what DICOM says.

  • fileout = dcm2bids4pet(FolderList,MetaList)

  • fileout = dcm2bids4pet(FolderList,MetaList,options)

param FolderList

Cell array of char strings with filenames and paths

param MetaList

Cell array of structures for metadata

param options
  • deletedcm to be ‘on’ or ‘off’

  • o the output directory or cell arrays of directories

    IF the folder is BIDS sub-xx files are renamed automatically

  • gz = 6; % -1..-9 : gz compression level (1=fastest..9=smallest, default 6)

  • a = ‘n’; % -a : adjacent DICOMs (images from same series always in same folder) for faster conversion (n/y, default n)

  • ba = ‘y’; % -ba : anonymize BIDS (y/n, default y)

  • d = 5; % directory search depth. Convert DICOMs in sub-folders of in_folder? (0..9, default 5)

  • f = ‘%f_%p_%t_%s’; % filename (%a=antenna (coil) name, %b=basename, %c=comments, %d=description, %e=echo number, %f=folder name, %g=accession number, %i=ID of patient, %j=seriesInstanceUID, %k=studyInstanceUID, %m=manufacturer, %n=name of patient, %o=mediaObjectInstanceUID, %p=protocol, %r=instance number, %s=series number, %t=time, %u=acquisition number, %v=vendor, %x=study ID; %z=sequence name; default ‘%f_%p_%t_%s’)

  • g = ‘n’; % generate defaults file (y/n/o/i [o=only: reset and write defaults; i=ignore: reset defaults], default n)

  • i = ‘n’; % ignore derived, localizer and 2D images (y/n, default n)

  • l = ‘n’; % losslessly scale 16-bit integers to use dynamic range (y/n/o [yes=scale, no=no, but uint16->int16, o=original], default n)

  • m = ‘2’; % merge 2D slices from same series regardless of echo, exposure, etc. (n/y or 0/1/2, default 2) [no, yes, auto]

  • p = ‘y’; % Philips precise float (not display) scaling (y/n, default y)

  • v = 1; % verbose (n/y or 0/1/2, default 0) [no, yes, logorrheic]

  • w = 2; % write behavior for name conflicts (0,1,2, default 2: 0=skip duplicates, 1=overwrite, 2=add suffix)

  • x = ‘n’; % crop 3D acquisitions (y/n/i, default n, use ‘i’gnore to neither crop nor rotate 3D acquistions)

  • z = ‘n’; % gz compress images (y/o/i/n/3, default y) [y=pigz, o=optimal pigz, i=internal:miniz, n=no, 3=no,3D]

meta = get_pet_metadata('Scanner','SiemensBiograph','TimeZero','ScanStart','TracerName','CB36','TracerRadionuclide','C11', ...
            'ModeOfAdministration','infusion','SpecificRadioactivity', 605.3220,'InjectedMass', 1.5934,'MolarActivity', 107.66);
dcm2niix4pet(folder1,meta,'gz',9,'o','mynewfolder','v',1); % change dcm2nii default
dcm2niix4pet({folder1,folder2,folder3},{meta}); % use the same PET meta for all subjects
dcm2niix4pet({folder1,folder2,folder3},{meta1,meta2,meta3}); % each subject has specific metadata info


See also get_pet_metadata.m to generate the metadata structure

updatejsonpetfile to see how the json file gets updated and checked agains DICOM tags

Cyril Pernet 2022
Copyright Open NeuroPET team

generic function that updates PET json file with missing PET-BIDS information, if only the jsonfile is provided, it only checks if valid (and possibly updates some fields from scalar to array)

  • status = updatejsonpetfile(jsonfilename,newfields,dcminfo)

  • jsonfilename – json file to check or update update can also be the json structure (add field filename to ensure update on disk)

  • newfields – (optional) a structure with the newfields to go into the json file

  • dcminfo – (optional) a dcmfile or the dicominfo structure from a representative dicom file. This information is used to also update the json file, and if a comflict exists, it returns warning messages, assumnimg the newfield provided is correct (i.e. as a user you know better than default dicom, presumably)

Returns status

the state of the updating (includes warning messages returned if any)

jsonfilename = fullfile(pwd,'DBS_Gris_13_FullCT_DBS_Az_2mm_PRR_AC_Images_20151109090448_48.json')
metadata = get_SiemensBiograph_metadata('TimeZero','ScanStart','tracer','AZ10416936','Radionuclide','C11', ...
                       'ModeOfAdministration','bolus','Radioactivity', 605.3220,'InjectedMass', 1.5934,'MolarActivity', 107.66)
dcminfo = dicominfo('DBSGRIS13.PT.PETMR_NRU.48.13.2015.')
status = updatejsonpetfile(jsonfilename,metadata,dcminfo)
Cyril Pernet 2022
Copyright Open NeuroPET team
matlab.ecat2nii(FileListIn, MetaList, varargin)

Converts ECAT 7 image file from hrrt pet scanner (ecat format) to nifti image files + json

  • FileListOut = ecat2nii(FileListIn,MetaList)

  • FileListOut = ecat2nii(FileListIn,MetaList,options)

  • FileListIn – a name or a Cell array of characters with paths and filenames

  • MetaList – a structure or Cell array of structures for metadata (a single structure can be use other many FileListIn - see examples) options are name/value pairs

  • FileListOut – a name or cell array of characters with filenames (with path if the path out is different)

  • sifout – is true or false (default) to output a sif file, default = false, 0/1 to indicate SIF is a simple ascii file that contains the PET frame start and end times, and the numbers of observed events during each PET time frame.

  • gz – is true (default) or false to output .nii.gz or .nii

  • savemat – is true or false (default) to save the ecat data as .mat

Returns FileListOut

is the name or a cell array of names of the nifti files created (should be the same as FileListOut entered as option with the added proper extension .nii or .nii.gz)

Example Meta = get_pet_metadata('Scanner','SiemensHRRT','TimeZero','ScanStart','TracerName','DASB','TracerRadionuclide','C11', ...
                   'ModeOfAdministration','bolus','InjectedRadioactivity', 605.3220,'InjectedMass', 1.5934,'MolarActivity', 107.66)
FileListOut = ecat2nii(EcatFile,Meta,'FileListOut',ConvertedRenamedFile1);
FileListOut = ecat2nii({EcatFile1,EcatFile2},Meta,'gz',false,'sifout',true);
FileListOut = ecat2nii({EcatFile1,EcatFile2},{Meta1,Meta2},'FileListOut',{ConvertedRenamedFile1,ConvertedRenamedFile2}));``


Uses: readECAT7.m (Raymond Muzic, 2002)

jsonwrite.m (Guillaume Flandin, 2020) nii_tool.m (Xiangrui Li, 2016)

See also get_pet_metadata.m to generate the metadata structure

Claus Svarer, Martin Nørgaard, Chris Rorden & Cyril Pernet - 2021
Copyright Open NeuroPET team

Routine to check input consistency, possibly generate new ones from PET BIDS metadata - this only makes sense if you respect the input units as indicated


dataout = check_metaradioinputs(varargin)


arguments in are provided via the following params (key/value pairs) e.g. - ‘InjectedRadioctivity’,81.24 - ‘SpecificRadioactivity’,1.3019e+04

  • InjectedRadioactivity – in MBq

  • InjectedMass – in ug

  • SpecificRadioactivity – in Bq/g or MBq/ug

  • MolarActivity – in GBq/umol

  • MolecularWeight – in g/mol


a structure with the original and updated field, including expected units

Claus Svarer, Martin Nørgaard & Cyril Pernet - 2021
Copyright Open NeuroPET team

from the dicom value of the PET reconstruction method, it returns the actual name of the method and the number of iterations and subsets if any

  • [method,iteration,subset] = get_recon_method(headervalue)


headervalue – the name in the ecat or dicom field of the reconstrusction method

Returns method

the full name of the reconstrucrtion method or empty if no match found

Returns iteration

the number of iterations or ‘none’

Returns subset

the number of subsets or ‘none’

Cyril Pernet 2022
Copyright Open NeuroPET team
routine that take a structure with nested subfileds

and output all fields in a flat structure

  • structout = flattenstruct(structin)

param structin

a structure with nested fields

returns structout

a flat sructure with all the fields


there is an exception handling for the fieldname ‘Item_1’ which is a DICOM name used by manufacturers to store various items

Cyril Pernet Novembre 2021
Copyright Open NeuroPET team
matlab.readECAT7(fs, matrix, varargin)

Read the main header, subheaders, and image/sinogram data from ECAT v 7.x *.v, *.i, *.S, and *.a files.


[mh,sh,data] = readECAT(fs, [matrix], [‘Calibrated’, ‘on’])

param fs

(optional) file specification (name/path) of file to read. if file specification is not given, then user is prompted to select a file.

param matrix

(optional) vector of matrix numbers to read. Default = all matrices in file.

param Calibrated’

‘on’ or ‘off’, if on it calibrates to pixel values in units given in mh.data_units. When ‘Calibrated’ is ‘on’, pixel values are stored as doubles; otherwise, pixels are int16. Calibration is achieved by multiplication of pixels by ecat_calibration_factor (in mh) and the scale_factor (in sh). The default is uncalibrated in which case pixels are int16.


  • mh - main header

  • sh - cell array of subheaders. sh{i} is subheader for matrix(i).

  • data - cell array containing pixel data. data{i} is a

    [rows, cols, planes] or [proj, views, planes] array with the data of matrix i. The data are stored in the file as 2 byte signed integers.


To convert data from cell array of 3D arrays to a 4D array: d=double(cat(4,data{:})); This could be helpful to convert a time-sequence of image volumes to something that can be more easily manipulated.

This should work for the entire line of ECAT scanners running 7.x of the software.

Original version written by BT Christian, 12/10/98

Overhaul by RF Muzic, 20000726

Revised by RF Muzic, 20010916

Revised by RF Muzic, 20011221 add support for 3D sinogram files (prev only images supported)

Revised by RF Muzic, 20021017 generalize support from multiple frames to multiple matrices. The distinction is that a matrix could correspond to different bed position or different frame.

Revised by RF Muzic, 20021029 correct length of last fill block in image file subheader. It is actually 49 shorts (to make a 512 byte sh block) whereas CTI docs says 48. Add support for .a files.

Copyright ? 2002 Raymond F. Muzic, Jr.

Not intended for clinical/diagnostic use. User assumes all risk.


Serialize a JSON (JavaScript Object Notation) structure

: format: - jsonwrite(filename,json,options)
  • S = jsonwrite(json)

  • filename – the name of the JSON file to write

  • json – the JSON structure

  • options

    • prettyPrint true or false to indent output [Default: true]

    • replacementStyle string to control how non-alphanumeric characters

      are replaced {‘underscore’,’hex’,’delete’,’nop’} [Default: ‘underscore’]

    • convertInfAndNaN encode NaN, Inf and -Inf as “null” [Default: true]


S the serialized JSON structure (string)


JSON Standard: jsonencode:


Guillaume Flandin $Id: spm_jsonwrite.m 8031 2020-12-10 13:37:00Z guillaume $