matlab

Conversion workflows

dcm2niix4pet

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.

format:
  • 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 varargin:
  • 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

  • sort_method DICOM order for per-volume scatter/decay recovery:

    ‘name’ (default) uses natural filename order without reading all headers; ‘acquisition_time’ reads every header to order volumes chronologically; ‘auto’ checks name order and falls back to acquisition time if needed. This controls JSON metadata recovery, not dcm2niix image ordering.

  • sort_pattern Optional filename-stem regex with named frame and optional

    slice tokens; see sort_dcm. Orders by frame, then slice.

  • 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 acquisitions)

  • 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]

  • notrack Opt-out of sending tracking information of this run to the PET2BIDS developers. This information helps to improve PET2BIDS and provides an indicator of real world usage crucial for obtaining funding.”

Example
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

Note

See also get_pet_metadata.m to generate the metadata structure

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

Cyril Pernet 2022
Copyright Open NeuroPET team

ecat2nii

matlab.ecat2nii(FileListIn, MetaList, varargin)

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

Format:
  • FileListOut = ecat2nii(FileListIn,MetaList)

  • FileListOut = ecat2nii(FileListIn,MetaList,options)

Parameters:
  • 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}));``

Note

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

PET metadata

get_pet_metadata

matlab.get_pet_metadata(varargin)

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.

Parameters:
  • Default – (acquisition 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 written as json file using e.g. the bids matlab jsonwrite function, typically associated with the *_pet.nii file)

Format:

metadata = get_pet_metadata(key,value)

Note

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 or amount units such as nmol e.g. ‘InjectedMass’, 1.5934

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

  • TracerMolecularWeight value in g/mol e.g. ‘TracerMolecularWeight’, 15.02 (legacy MolecularWeight is also accepted)

  • SpecificRadioactivity in units commensurate with Bq/g (default Bq/g) 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;

Note

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

Note

OPTIONAL INPUTS ARE ALL OTHER BIDS FIELDS

Example

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',...
          'ReconMethodParameterLabels',{'subsets','iterations'},...
          '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

updatejsonpetfile

matlab.updatejsonpetfile(varargin)

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)

Format:
  • status = updatejsonpetfile(jsonfilename,newfields,dcminfo,dicomfolder,sort_method,sort_pattern)

Parameters:
  • 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 conflict exists, it returns warning messages, assumnimg the newfield provided is correct (i.e. as a user you know better than default dicom, presumably)

  • dicomfolder – (optional) source DICOM folder for per-volume scatter and decay factors. If omitted, inferred from dcminfo or its Filename field. The matching .nii or .nii.gz must be beside the JSON file.

  • sort_method – (optional) DICOM ordering: ‘name’ (default), ‘acquisition_time’, or ‘auto’; see sort_dcm. Pass [] for dicomfolder to infer it from dcminfo. VolumeTimes are printed in seconds since midnight. AcquisitionDate and AcquisitionTime must be valid. If volume dates/times do not strictly increase in name order, warn and retry recovery using acquisition-time order.

  • sort_pattern – (optional) filename-stem regex with named frame and optional slice tokens; see sort_dcm.

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.11.11.14.03.16.226.61519201.dcm')
status = updatejsonpetfile(jsonfilename,metadata,dcminfo)
Cyril Pernet 2022
Copyright Open NeuroPET team

check_metaradioinputs

matlab.check_metaradioinputs(varargin)

Check radiotracer metadata and infer missing quantities with consistent units.

Format:

dataout = check_metaradioinputs(‘Name’, value, …) A cell array of name/value pairs is also accepted.

Parameters:
  • InjectedRadioactivity – default MBq

  • InjectedMass – default ug; also accepts amount units such as nmol

  • SpecificRadioactivity – default Bq/g (NOT numerically equal to MBq/ug)

  • MolarActivity – default GBq/umol

  • TracerMolecularWeight – default g/mol Legacy MolecularWeight fields are accepted as input aliases.

Each quantity accepts a corresponding <Name>Units argument. Activity units Bq, kBq, MBq, GBq, TBq, Ci, mCi, uCi; mass units kg, g, mg, ug, ng; and amount units mol, mmol, umol, nmol, pmol are supported, including ratios commensurate with Bq/g, Bq/mol and g/mol. InjectedMass units determine whether its relations use specific or molar activity. Micro signs are accepted as ‘u’. Supplied values and units are preserved. Omitted units use the defaults above. Inferred values use requested units, or the defaults if none were supplied. For example, 10 MBq / 10 ug is 1 MBq/ug, or 1e12 Bq/g. Unknown/incompatible units are warned about and excluded from calculations. Missing/non-numeric inputs and zero denominators cannot generate a numeric result. Only absent output quantities are marked ‘n/a’; inputs are retained. Consistency uses relative tolerance 1e-5 rather than integer truncation.

See also

Radiotracer quantity inference for the formulas, unit conversions, and worked examples.

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

get_recon_method

matlab.get_recon_method(headervalue)

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

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

Parameters:

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 2025
Copyright Open NeuroPET team

Supporting utilities

readECAT7

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.

format:

[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.

Returns:

  • 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.

Note

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.

flattenstruct

matlab.flattenstruct(structin)
routine that take a structure with nested subfileds

and output all fields in a flat structure

format:
  • structout = flattenstruct(structin)

param structin:

a structure with nested fields

returns structout:

a flat structure with all the fields

Note

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

jsonwrite

matlab.jsonwrite(varargin)

Serialize a JSON (JavaScript Object Notation) structure

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

Parameters:
  • 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]

Returns:

S the serialized JSON structure (string)

References:

JSON Standard: https://www.json.org/ jsonencode: https://www.mathworks.com/help/matlab/ref/jsonencode.html

Note

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