matplotlib

Source code for utils.dicom2xml

import dicom, SetBeam20, scaleConverter
from xml.etree import ElementTree as ET
import numpy as np
#from utils import SetBeam20
from . import SetBeam20

# Author: Pankaj Mishra, Jul 7, 2014
# Update: 7/29/2014 Removed hardcoded path -CLW
# Fixed mm to cm conversion error - CLW 10/24/2014, see #3

[docs]class Dicom2Xml: def __init__(self, filename, outxml): self.filename = filename self.outxml = outxml def dicomToDataset(self): dataset = dicom.read_file(self.filename, force=True) self.ds = dataset
[docs] def getLeafJaws(self, leafJawsSequence, cp): ''' Extract Mlc, X or Y jaws (if present) and then add it to the existinXML string ''' selectionStr = {"MLCX": "Mlc", "ASYMX": "X", "ASYMY": "Y", "X": "X", "Y": "Y"} for lj in leafJawsSequence: if(selectionStr[lj.RTBeamLimitingDeviceType] == "Y"): # Fixed mm to cm conversion error - CLW 10/24/2014 ET.SubElement(cp, 'Y1').text = str(lj.LeafJawPositions[0]/10.0) ET.SubElement(cp, 'Y2').text = str(lj.LeafJawPositions[1]/10.0) elif(selectionStr[lj.RTBeamLimitingDeviceType] == "X"): # Fixed mm to cm conversion error - CLW 10/24/2014 ET.SubElement(cp, 'X1').text = str(lj.LeafJawPositions[0]/10.0) ET.SubElement(cp, 'X2').text = str(lj.LeafJawPositions[1]/10.0) elif(selectionStr[lj.RTBeamLimitingDeviceType] == "Mlc"): mlcTag = ET.SubElement(cp,'Mlc') ET.SubElement(mlcTag,'ID').text = '1' # Fixed mm to cm conversion error - CLW 10/24/2014 Barr=map(lambda x:float(x)/10.0,lj.LeafJawPositions[:60]) Aarr=map(lambda x:float(x)/10.0,lj.LeafJawPositions[60:]) ET.SubElement(mlcTag, 'B').text = " ".join(map(str,Barr)) ET.SubElement(mlcTag, 'A').text = " ".join(map(str,Aarr))
[docs] def findMlcModel(self, inMlc): ''' Determine the MLCModel type. Currently NDS120, NDS120HD, NDS80 are supported. :param inMlc: MLC array from the DICOM file ''' # MLC model pattern NDS120 (in mm) firstLast10 = np.array(10*np.ones(10, dtype='float', order = 'C')) middle40 = np.array(5*np.ones(40, dtype='float', order = 'C')) nds120 = np.concatenate((firstLast10, middle40, firstLast10)) # MLC model pattern ND120HD (in mm) firstLast14 = np.array(5*np.ones(14, dtype=np.float32, order = 'C')) middle32 = np.array(2.5*np.ones(32, dtype=np.float32, order = 'C')) nds120HD = np.concatenate((firstLast14, middle32, firstLast14)) # Now some constants mlcLength = len(inMlc) if mlcLength == 61: if np.all(np.diff(inMlc) == nds120): return 'NDS120' elif np.all(np.diff(inMlc) == nds120HD): return 'NDS120HD' elif mlcLength == 41: return 'NDS80'
def extractControlPoints(self): lookupTable = {'NominalBeamEnergy' : 'Energy', \ 'DoseRateSet' : 'DRate', \ 'GantryAngle' : 'GantryRtn', \ 'BeamLimitingDeviceAngle' : 'CollRtn',\ 'TableTopVerticalPosition' : 'CouchVrt',\ 'TableTopLongitudinalPosition' : 'CouchLng', \ 'TableTopLateralPosition' : 'CouchLat',\ 'PatientSupportAngle' : 'CouchRtn',\ 'CumulativeMetersetWeight' : 'Mu',\ 'BeamLimitingDevicePositionSequence' : 'MlcJaws' } energyType = {"PHOTON": "x", "ELECTRON": "e"} dose = 0; root = ET.Element('VarianResearchBeam') sb = ET.SubElement(root,'SetBeam') ET.SubElement(sb, 'Id').text = '1' # Determine the MLCModel type: NDS80, NDS120, NDS120HD inMlc = [float(s) for s in self.ds.BeamSequence[0].BeamLimitingDeviceSequence[2].LeafPositionBoundaries] ET.SubElement(sb, 'MLCModel').text = self.findMlcModel(inMlc) ET.SubElement(sb, 'Accs').text = '' controlpoint = ET.SubElement(sb, 'ControlPoints') dosePrev = 0.0 # For cumulative dose for (beam, frac) in zip(self.ds.BeamSequence, self.ds.FractionGroupSequence[0].ReferencedBeamSequence): # Control point for cnt in range(0, beam.NumberofControlPoints): cp = ET.SubElement(controlpoint, 'Cp') for elem in beam.ControlPointSequence[cnt]: keyTag = elem.name.replace(" ", "") if(keyTag in lookupTable.keys()): if (lookupTable[keyTag] == 'Energy'): ET.SubElement(cp, lookupTable[keyTag]).text = str(elem.value) + energyType[beam.RadiationType] elif (lookupTable[keyTag] == "MlcJaws"): self.getLeafJaws(elem, cp) elif(lookupTable[keyTag] == "Mu"): dose = dosePrev + frac.BeamMeterset*elem.value ET.SubElement(cp, lookupTable[keyTag]).text = str(dose) else: ET.SubElement(cp, lookupTable[keyTag]).text = str(elem.value) dosePrev = dosePrev + frac.BeamMeterset # Cumulative dose #------------------------------------ Validate and write output XML file # Convert IEC (from DICOM) to Varian Scale # NOTE: Please fix the schema check part SOOOOON!!!!! tree = ET.ElementTree(root) tree.write(self.outxml) fp = scaleConverter.ScaleConverter(self.outxml) fp.convertScale('VarianScale') fp.tree.write(self.outxml)