Based on your question, I think you want to do it outside of Slicer. If this is indeed the case, here are the steps, which will not depend on Slicer environment or any Slicer-specific python functionality.
Step 1: Sort your DICOM files into series, and identify PET series. I recommend you use dicomsort for this task. You can run it, for example, with the following parameters to include modality in the name of the sorted series folder:
$ python dicomsort.py <input folder> <sorted_folder>/%PatientID/%StudyDate/%SeriesNumber-%Modality-%SeriesDescription/%SOPInstanceUID.dcm
Step 2: Run SUV calculator command line tool. You can install it as an extension, and then navigate to the folder with the installed extensions to locate it. Instructions how to run a Slicer CLI will vary depending on the operating system you use. On Mac, you can run the CLI executable directly. CLI will take as input directory with the DICOM PET files, and will output a DICOM Real World Value Mapping IOD instance (the macro that contains the SUV factor is described here) saved into a new file and a text file with the computed SUV factor(s):
$ /Applications/Slicer.app/Contents/Extensions-28390/PETDICOMExtension/lib/Slicer-4.11/cli-modules/SUVFactorCalculator -p sorted/QIN-HEADNECK-01-0366/19860303/UnknownSeriesNumber-PT-PET_WB_0 -r . --returnparameterfile output_parameters.txt
saving numbers to
Input parameters okay...
ATTN/DECAY correction detected.
Decay correction START detected.
INJECTED DOSE: 3.8591e+08
RAD. START TIME: 39180
SERIES TIME: 44254.7
DECAYED DOSE: 226226
Warning: No patient height detected. Cannot determine SUVbsa, SUVlbm, and SUVibw conversion factors.
227 files total
Inserted: QIN-HEADNECK-01-0366
Inserted: QIN-HEADNECK-01-0366
Inserted: M
Inserted: YES
Inserted: DCM:113100/113105/113107/113108/113109/113111
Inserted: 1.3.6.1.4.1.14519.5.2.1.2744.7002.103466790444463274538008985123
Inserted: 19860303
Inserted: 120336.292000
Inserted:
Inserted: 2076699673350889
Inserted: Thorax^1HEAD_NECK_PETCT
Inserted: 059Y
Inserted: 63.2
saving to ./1.2.276.0.7230010.3.1.4.0.86172.1563548276.147671.dcm
0 0.000279366 0 0
The last line of the console will actually output various SUV factors calculated by the CLI (and I should add more descriptive printout on the console).
The output_parameters.txt
file will contain the following lines with the SUV factor(s):
SUVbwConversionFactor = 0.000279366
SUVlbmConversionFactor = 0
SUVbsaConversionFactor = 0
SUVibwConversionFactor = 0
The relevant part of the DICOM RWVM instance created by the CLI are below (output produced by the DCMTK dcmdump
tool, also available via the dicom-dump
package of Atom):
(0040,9096) SQ (Sequence with undefined length #=1) # u/l, 1 RealWorldValueMappingSequence
(fffe,e000) na (Item with undefined length #=8) # u/l, 1 Item
(0028,3003) LO [Standardized Uptake Value body weight] # 38, 1 LUTExplanation
(0040,08ea) SQ (Sequence with undefined length #=1) # u/l, 1 MeasurementUnitsCodeSequence
(fffe,e000) na (Item with undefined length #=3) # u/l, 1 Item
(0008,0100) SH [{SUVbw}g/ml] # 12, 1 CodeValue
(0008,0102) SH [UCUM] # 4, 1 CodingSchemeDesignator
(0008,0104) LO [Standardized Uptake Value body weight] # 38, 1 CodeMeaning
(fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem
(0040,9210) SH [{SUVbw}g/ml] # 12, 1 LUTLabel
(0040,9211) US 26403 # 2, 1 RealWorldValueLastValueMapped
(0040,9216) SS 0 # 2, 1 RealWorldValueFirstValueMapped
(0040,9220) SQ (Sequence with undefined length #=2) # u/l, 1 QuantityDefinitionSequence
(fffe,e000) na (Item with undefined length #=3) # u/l, 1 Item
(0040,a040) CS [CODE] # 4, 1 ValueType
(0040,a043) SQ (Sequence with undefined length #=1) # u/l, 1 ConceptNameCodeSequence
(fffe,e000) na (Item with undefined length #=3) # u/l, 1 Item
(0008,0100) SH [G-C1C6] # 6, 1 CodeValue
(0008,0102) SH [SRT] # 4, 1 CodingSchemeDesignator
(0008,0104) LO [Quantity] # 8, 1 CodeMeaning
(fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem
(0040,a168) SQ (Sequence with undefined length #=1) # u/l, 1 ConceptCodeSequence
(fffe,e000) na (Item with undefined length #=3) # u/l, 1 Item
(0008,0100) SH [126400] # 6, 1 CodeValue
(0008,0102) SH [DCM] # 4, 1 CodingSchemeDesignator
(0008,0104) LO [Standardized Uptake Value] # 26, 1 CodeMeaning
(fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem
(fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem
(fffe,e000) na (Item with undefined length #=3) # u/l, 1 Item
(0040,a040) CS [CODE] # 4, 1 ValueType
(0040,a043) SQ (Sequence with undefined length #=1) # u/l, 1 ConceptNameCodeSequence
(fffe,e000) na (Item with undefined length #=3) # u/l, 1 Item
(0008,0100) SH [G-C036] # 6, 1 CodeValue
(0008,0102) SH [SRT] # 4, 1 CodingSchemeDesignator
(0008,0104) LO [Measurement Method] # 18, 1 CodeMeaning
(fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem
(0040,a168) SQ (Sequence with undefined length #=1) # u/l, 1 ConceptCodeSequence
(fffe,e000) na (Item with undefined length #=3) # u/l, 1 Item
(0008,0100) SH [126410] # 6, 1 CodeValue
(0008,0102) SH [DCM] # 4, 1 CodingSchemeDesignator
(0008,0104) LO [SUV body weight calculation method] # 34, 1 CodeMeaning
(fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem
(fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem
(0040,9224) FD 0 # 8, 1 RealWorldValueIntercept
(0040,9225) FD 0.000279366 # 8, 1 RealWorldValueSlope
(fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem
The SUV factor is stored in the RealWorldValueSlope
attribute, and the preceeding QuantityDefinitionSequence
can be used to get the SUV calculation method and units. Other parts of the DICOM RWVM instance store patient information, references to the PET instances to which the SUV factor applies, etc.
Over-simplifying things, you can easily access the SUV factor (the same that you will find in the text file, but with a lot more detailed metadata) using pydicom
as follows:
import pydicom
d = pydicom.read_file('<RWVM file name>')
suv = d.ReferencedImageRealWorldValueMappingSequence[0].RealWorldValueMappingSequence[0].RealWorldValueSlope
Step 3: you can use dcm2niix
to generate a 3d PET volume from the files in the PET series folder you prepared in Step 1 by running dcm2niix .
in the folder with the PET series files.
Step 4: you can load the reconstructed PET volume using itk-python
or SimpleITK
and apply the SUV factor by multiplying the image by the SUV constant. You can then save the resulting image as a new NIfTI file - see examples on file IO for SimpleITK here.