def _load_files(self, file_list): """ Load CT DICOM files given a list of images :return: """ # intialize some lists images = [] im_order = [] # check that enough slices were loaded if len(file_list) < self.slices_of_interest['SR']: if self.using_pyqa: return #TODO: post message box else: raise ValueError, "Not enough slices were selected. Select all the files or change the SR slice value." # load dicom files from list names maxlist = [] for item in file_list: dcm = item _tmparray = dcm._get_pixel_array() rescaleintercept = int(dcm[tag.Tag("0028", "1052")].value) rescaleslope = int(dcm[tag.Tag("0028", "1053")].value) tmparray = _tmparray * rescaleslope + rescaleintercept images.append(tmparray) tmporder = np.round(dcm.ImagePositionPatient[-1] / dcm.SliceThickness) im_order.append(tmporder) maxlist.append([np.max(tmparray), tmporder]) self.improps = { 'FOV': dcm.DataCollectionDiameter, 'width': np.size(images[0], 0), 'height': np.size(images[0], 1), 'FOV size': field_of_view[0] if dcm.DataCollectionDiameter < FOV_thresh else field_of_view[1], 'Rescale Slope': dcm.RescaleSlope, 'Rescale Intercept': dcm.RescaleIntercept, 'mm/Pixel': dcm.PixelSpacing[0] } self._sort_images(images, im_order)
def QC_getinge_main(data, results, **kwargs): relevantfile = data.getAllInstances()[0] print 'Reading dicomfile', relevantfile dicomobject = relevantfile tmpseriesdescription = dicomobject[tag.Tag("0008", "103E")].value waarde = dicomobject[tag.Tag("0071", "0001")].value results.addChar('Result Thermal selfdesinfection', waarde, level='1') waarde = dicomobject[tag.Tag("0071", "0003")].value results.addChar('Error code', waarde, level='1') waarde = dicomobject[tag.Tag("0071", "0005")].value results.addChar('Error text', waarde)
def spect_cor_main(data, results, **kwargs): print "Starting SPECT cor analysis" relevantfile = data.getAllInstances()[0] pixel_map = relevantfile.pixel_array pixelsize = float(relevantfile[tag.Tag("0028", "0030")].value[0]) data = Datatree(relevantfile) detdict = data.show_sinogram() corlist = [] print "detdict.keys()", detdict.keys() for det in detdict.keys(): print det, detdict[det] source_sinograms = detdict[det] for key in source_sinograms.keys(): print "key=", key, source_sinograms[key] x = np.linspace(0, 2 * np.pi, data.zdim / 2) y = source_sinograms[key] p0 = [60., 1 / 360., 0., data.zdim / 2.] popt, pcov = curve_fit(sinogramfit, x, y, p0) tmp_cor = ((popt[3] + 1) - ((data.xdim + 1) / 2.0)) * pixelsize corlist.append(tmp_cor) yfit = sinogramfit(x, *popt) fig = plt.figure(str(det)) ax = fig.add_subplot(111) plt.title("detector " + str(det)) ax.plot(y, 'bo') ax.plot(yfit) plt.text(0, 100, "COR$_{avg}$ = %.2f" % np.mean(corlist), size=25, rotation=0., ha="left", va="top", bbox=dict( boxstyle="square", ec=(1., 0.5, 0.5), fc=(1., 0.8, 0.8), )) object_naam = 'Sinogram_det_%s.png' % str(det) plt.savefig(object_naam) results.addObject('Sinogram det %s' % str(det), object_naam, level=1) results.addFloat('COR det %s' % str(det), np.mean(corlist), level=1)
def parseqcreport(data, results, **kwargs): params = kwargs.get('params', None) p = {} for param in params: p[param.tag] = (param.text, param.attrib) print p relevantfile = data.getAllInstances()[0] xmltext = relevantfile[tag.Tag(p.get('use_private_tag')[0].split(','))] root = etree.fromstring(xmltext.value) print_xml(root)
def parseqcreport(data,results,**kwargs): params = kwargs.get('params', None) p = {} for param in params: p[param.tag] = (param.text,param.attrib) print p status_ok=True relevantfile = data.getAllInstances()[0] xmltext = relevantfile[tag.Tag(p.get('use_private_tag')[0].split(','))] root = etree.fromstring(xmltext.value) print_xml(root) datagroup = root.find('DataGroup') scandate = datagroup.get('DateTime') datapackages = root.find(".//DataPackage[@Package_Name='ID_FCT_SUMMARY']") summary = datapackages.find(".//DataEntry[@Variable_Name='ID_ErrorCodeSummary']") outval = summary.find("StringVariable[@String_Value]").attrib['String_Value'] results.addFloat('ID_ErrorCodeSummary',outval,level=1) measurementsroot = root.find("DataGroup[@Group_Name='ID_GROUP']") measurements = measurementsroot.findall(".//DataPackage[@Package_Name='ID_MODE']") print '--'*20 for measurement in measurements: print 'New measurement' currvolt = measurement.find(".//DataEntry[@Variable_Name='ID_VOLT']") currcurrent = measurement.find(".//DataEntry[@Variable_Name='ID_CURRENT']") print currcurrent.find('LongVariable').attrib['Long_Value'] print currvolt.find('LongVariable').attrib['Long_Value'] try: print measurement.find(".//DataArray[@Array_Name='ID_RESULT']").find("DataSeries[@Series_Name='ID_SIGMA']").find('.//DoubleVariable').attrib['Double_Value'] except: pass print measurement.find(".//DataArray[@Array_Name='ID_RESULT']").find("DataSeries[@Series_Name='ID_VOLT']").find('.//DoubleVariable').attrib['Double_Value']
def barco_compliance(data, results, **kwargs): dcmlist = data.getAllInstances() if len(dcmlist) > 1: print "only one instance supported!" sys.exit() dicomobject = dcmlist[0] print dicomobject csvfile = dicomobject[tag.Tag("0071", "0071")].value csvfileread = StringIO.StringIO(csvfile) data = csv.reader(csvfileread, delimiter='\t') contrastlijst = [] contrastlijsttarget = [] contrasterrorlijst = [] counter = 0 countertarget = 0 resultxml = [] for row in data: info = row[0].split(' ') datum = ''.join(info[0:3]) scherm = info[6].split('-') scherm = scherm[2] try: print info[10] if info[9] == "contrast" and info[11] == "error": data = info[-1].strip('%') contrasterrorlijst.append(float(data)) except IndexError: pass try: if info[9] == "Ambient" and info[10] == "light:": AmbientLightvalue = info[11] results.addFloat('Omgevingslicht', AmbientLightvalue, level=1) except IndexError: pass try: if info[9] == "Error" and info[10] == "tolerance:": Barcotolerance = info[11] results.addFloat('Barco contrast tolerantiewaarde', Barcotolerance, level=1) except IndexError: pass try: if info[9] == "Measured" and info[10] == "Contrast": counter = 17 except IndexError: pass try: if info[9] == "contrastResponse:" and counter > 0: contrastlijst.append(float(info[-1])) counter -= 1 except IndexError: pass try: if info[9] == "Target" and info[10] == "Contrast": countertarget = 17 print 'hoi' except IndexError: pass try: if info[9] == "contrastResponse:" and countertarget > 0: contrastlijsttarget.append(float(info[-1])) countertarget -= 1 except IndexError: pass try: if info[13] == "Status:": if info[14] == "true": DICOMluminance = True else: DICOMluminance = False except IndexError: pass try: if info[9] == "Result:": if info[10] == "OK": Result = True else: Result = False except IndexError: pass tolerance = 10 error = True for contrasterror in contrasterrorlijst: if contrasterror >= tolerance: error = False print contrastlijst print contrastlijsttarget print contrasterrorlijst results.addBool('Contrast eigen tolerantie', error, level=1) print DICOMluminance results.addBool('Barco Luminance', DICOMluminance, level=1) print Result results.addBool('Barco Result', Result, level=1) helpcounter = 0 for row in contrastlijst: results.addFloat('Contrast ' + str(helpcounter), row, level=1) helpcounter += 1 #------------------------- object_naam = 'GSDFcurve.png' x = range(17) toleranties = [y * tolerance / 100 for y in contrastlijsttarget] tolerantiehoog = [] tolerantielaag = [] for index, item in enumerate(contrastlijsttarget): tolerantiehoog.append(contrastlijsttarget[index] + toleranties[index]) tolerantielaag.append(contrastlijsttarget[index] - toleranties[index]) fig = plt.figure() ax = fig.add_subplot(111) ax.plot(x, contrastlijst, 'b.', x, tolerantiehoog, 'r--', x, tolerantielaag, 'r--', x, contrastlijsttarget, 'b:') plt.suptitle('Display ' + scherm + ' ' + datum) plt.yscale('log') plt.ylabel('dL/L') plt.grid(True) plt.xlabel('Measurement point') plt.savefig(object_naam) results.addObject('GSDF curve', object_naam, level=1)
def parseqcreport(data, results, **kwargs): params = kwargs.get('params', None) p = {} for param in params: p[param.tag] = (param.text, param.attrib) print p status_ok = True relevantfile = data.getAllInstances()[0] xmltext = relevantfile[tag.Tag(p.get('use_private_tag')[0].split(','))] root = etree.fromstring(xmltext.value) print_xml(root) datagroup = root.find('DataGroup') scandate = datagroup.get('DateTime') datapackages = root.findall(".//DataPackage[@Package_Name='ID_MODE']") for data in datapackages: status_ok = True kV = data.find(".//*/DataEntry[@Variable_Name='ID_VOLT']/LongVariable" ).get('Long_Value') mA = data.find( ".//*/DataEntry[@Variable_Name='ID_CURRENT']/LongVariable").get( 'Long_Value') region = data.find( ".//*/DataEntry[@Variable_Name='ID_REGION']/StringVariable").get( 'String_Value').replace('ID_', '') row_n1_ok = data.find( ".//*/DataSeries[@Series_Name='ID_WATER']/SeriesEntry[@Series_ID='ID_ROW_N1']/DataEntry" ).get('Variable_In_Spec') row_n2_ok = data.find( ".//*/DataSeries[@Series_Name='ID_WATER']/SeriesEntry[@Series_ID='ID_ROW_N2']/DataEntry" ).get('Variable_In_Spec') row_n3_ok = data.find( ".//*/DataSeries[@Series_Name='ID_WATER']/SeriesEntry[@Series_ID='ID_ROW_N3']/DataEntry" ).get('Variable_In_Spec') row_n1_kV_ok = data.find( ".//*/DataSeries[@Series_Name='ID_VOLT']/*/DataEntry").get( 'Variable_In_Spec') status_ok = status_ok and row_n1_ok == 'YES' and row_n2_ok == 'YES' and row_n3_ok == 'YES' and row_n1_kV_ok == 'YES' # not present for all mA/kV combinations row_n1_sigma_element = data.find( ".//*/DataSeries[@Series_Name='ID_SIGMA']/*/DataEntry") if row_n1_sigma_element is not None: row_n1_sigma_ok = row_n1_sigma_element.get('Variable_In_Spec') row_n1_sigma = row_n1_sigma_element.find('DoubleVariable').get( 'Double_Value') status_ok = status_ok and row_n1_sigma_ok == 'YES' row_n1 = data.find( ".//*/DataSeries[@Series_Name='ID_WATER']/SeriesEntry[@Series_ID='ID_ROW_N1']/*/DoubleVariable" ).get('Double_Value') row_n2 = data.find( ".//*/DataSeries[@Series_Name='ID_WATER']/SeriesEntry[@Series_ID='ID_ROW_N2']/*/DoubleVariable" ).get('Double_Value') row_n3 = data.find( ".//*/DataSeries[@Series_Name='ID_WATER']/SeriesEntry[@Series_ID='ID_ROW_N3']/*/DoubleVariable" ).get('Double_Value') row_n1_kV = data.find( ".//*/DataSeries[@Series_Name='ID_VOLT']/SeriesEntry/DataEntry/DoubleVariable" ).get('Double_Value') results.addChar('{0} {1}kV {2}mA'.format(region, kV, mA), 'Passed' if status_ok else 'Failed', level=1) results.addFloat("{0} {1}kV {2}mA ROW_N1".format(region, kV, mA), row_n1, level=2, units='HU') results.addFloat("{0} {1}kV {2}mA ROW_N2".format(region, kV, mA), row_n2, level=2, units='HU') results.addFloat("{0} {1}kV {2}mA ROW_N3".format(region, kV, mA), row_n3, level=2, units='HU') if row_n1_sigma_element is not None: results.addFloat("{0} {1}kV {2}mA ROW_N1_sigma".format( region, kV, mA), row_n1_sigma, level=2, units='HU') results.addFloat("{0} {1}kV {2}mA ROW_N1_voltage".format( region, kV, mA), row_n1_kV, level=2, units='kV')
def metadata(self, dcminstance): outdict = {} for key in self.tagdict.keys(): print key outdict[key] = dcminstance[tag.Tag(self.tagdict[key])]
def parseqcreport(data, results, **kwargs): params = kwargs.get('params', None) p = {} for param in params: p[param.tag] = (param.text, param.attrib) print p status_ok = True relevantfile = data.getAllInstances()[0] xmltext = relevantfile[tag.Tag(p.get('use_private_tag')[0].split(','))] root = etree.fromstring(xmltext.value) print_xml(root) datagroup = root.find('DataGroup') scandate = datagroup.get('DateTime') # Region is either defined globally or per protocol; try both datapackage_common = root.findall( ".//DataPackage[@Package_Name='ID_COMMON']") for data in datapackage_common: region_element = data.find( ".//*/DataEntry[@Variable_Name='ID_REGION']/StringVariable") if region_element is not None: region = region_element.get('String_Value').replace('ID_', '') datapackages = root.findall(".//DataPackage[@Package_Name='ID_MODE']") for data in datapackages: status_ok = True kV = data.find(".//*/DataEntry[@Variable_Name='ID_VOLT']/LongVariable" ).get('Long_Value') mA = data.find( ".//*/DataEntry[@Variable_Name='ID_CURRENT']/LongVariable").get( 'Long_Value') region_element = data.find( ".//*/DataEntry[@Variable_Name='ID_REGION']/StringVariable") # not present for some scanners if region_element is not None: region = region_element.get('String_Value').replace('ID_', '') kV_ok = data.find(".//*/DataSeries[@Series_Name='ID_VOLT']/*/DataEntry" ).get('Variable_In_Spec') status_ok = status_ok and kV_ok == 'INTOL' # not present for all mA/kV combinations sigma_element = data.find( ".//*/DataSeries[@Series_Name='ID_SIGMA']/*/DataEntry") if sigma_element is not None: sigma_ok = sigma_element.get('Variable_In_Spec') sigma = sigma_element.find('DoubleVariable').get('Double_Value') status_ok = status_ok and sigma_ok == 'INTOL' kV_measured = data.find( ".//*/DataSeries[@Series_Name='ID_VOLT']/SeriesEntry/DataEntry/DoubleVariable" ).get('Double_Value') results.addChar('{0} {1}kV {2}mA'.format(region, kV, mA), 'Passed' if status_ok else 'Failed', level=1) if sigma_element is not None: results.addFloat("{0} {1}kV {2}mA sigma".format(region, kV, mA), sigma, level=2, units='HU') results.addFloat("{0} {1}kV {2}mA voltage".format(region, kV, mA), kV_measured, level=2, units='kV')
def parseqcreport(data, results, **kwargs): params = kwargs.get('params', None) p = {} for param in params: p[param.tag] = (param.text, param.attrib) print p relevantfile = data.getAllInstances()[0] xmltext = relevantfile[tag.Tag(p.get('use_private_tag')[0].split(','))] root = etree.fromstring(xmltext.value) print_xml(root) #Sections: #Title title = root.find('aTitle') #Scandate scandate = root.find('bScandate') #Phantomparameters phantompars = root.find('cPhantomParameters') Isotope = phantompars.find('aIsotope').text results.addChar('Isotope', Isotope, level=1) AssayActivity = phantompars.find('bAssayActivity').find('aValue').text #+phantompars.find('bAssayActivity').find('bMeasure').text results.addFloat('AssayActivity', AssayActivity, level=1) AssayDatetime = phantompars.find('cAssayDateTime').text results.addChar('AssayDateTime', AssayDatetime, level=1) Volume = phantompars.find('dVolume').find('aValue').text results.addFloat('Volume', Volume, level=1) CalibrationFactor = phantompars.find('eCalibrationFactor').text results.addFloat('CalibrationFactor', CalibrationFactor, level=1) #Inputforcomputation compinput = root.find('dInputforComputation') SWversion = compinput.find('eICSSWVersion').text results.addChar('Software version', SWversion, level=2) Gantrytype = compinput.find('fSystemType').text results.addChar('Gantry type', Gantrytype, level=2) DailySinogram = compinput.find('aDailySinoLocation').text results.addChar('Sinogram location', DailySinogram, level=2) ProposedECFval = compinput.find('bProposedECFValue').find('aValue').text results.addFloat('Proposed ECF', ProposedECFval, level=2) LastPartialSetup = compinput.find('cLastSuccessfulSetup').find( 'LastSetupDateTime').text results.addChar('Last partial setup', LastPartialSetup, level=2) LastPartialSetupState = compinput.find('cLastSuccessfulSetup').find( 'LastSetupState').text results.addChar('Last partial setup state', LastPartialSetupState, level=2) LastFullSetup = compinput.find('hLastSuccessfulSetup').find( 'LastSetupDateTime').text results.addChar('Last full setup', LastPartialSetup, level=2) LastFullSetupState = compinput.find('hLastSuccessfulSetup').find( 'LastSetupState').text results.addChar('Last full setup state', LastPartialSetupState, level=2) Partialsetupenabled = compinput.find('gPartialSetupEnabled').text results.addChar('Partial setup enabled', Partialsetupenabled, level=2) ICSname = compinput.find('dICSName').text results.addChar('ICS name', ICSname, level=2) #Results sectionresults = root.find('eResults') SystemQualityResults = sectionresults.find('aSystemQualityResults').text results.addChar('System Quality Results', SystemQualityResults, level=1) QCPhantomActivity = sectionresults.find('aPhantomAgeResult').text results.addChar('QC Phantom Activity', QCPhantomActivity, level=1) #DetailedQCreport detres = root.find('fDetailedSystemQualityReport').find('aItem') BlockNoise = detres.find('aBlockNoise').find('cBlkValue').find( 'aValue').text results.addFloat('Block Noise', BlockNoise, level=2) BlockEfficiency = detres.find('bBlockEfficiency').find('cBlkValue').find( 'aValue').text results.addFloat('Block Efficiency', BlockEfficiency, level=2) MeasuredRandoms = detres.find('cMeasureRandoms').find('cBlkValue').find( 'aValue').text results.addFloat('Measured Randoms', MeasuredRandoms, level=2) ScannerEfficiency = detres.find('dScannerEfficiency').find( 'cBlkValue').find('aValue').text results.addFloat('Scanner Efficiency', ScannerEfficiency, level=2) ScatterRatio = detres.find('eScatterRatio').find('cBlkValue').find( 'aValue').text results.addFloat('Scatter Ratio', ScatterRatio, level=2) ECF = detres.find('fECF').find('cBlkValue').find('aValue').text results.addFloat('ECF', ECF, level=2) ImagePlaneEfficiency = detres.find('gPlaneEff').find('cBlkValue').find( 'aValue').text results.addFloat('Plane efficiency', ImagePlaneEfficiency, level=2) BlockTimingOffset = detres.find('hTimeAlignment').find('cBlkValue').find( 'aValue').text results.addFloat('BlockTimingOffset', BlockTimingOffset, level=2) BlockTimingWidth = detres.find('iTAFWHM').find('cBlkValue').find( 'aValue').text results.addFloat('BlockTimingWidth', BlockTimingWidth, level=2) TimeAlignmentResidual = detres.find('lTAResidual').find('cBlkValue').find( 'aValue').text results.addFloat('Time alignment residual', TimeAlignmentResidual, level=2)
def __init__(self, data, results, **kwargs): self.params = kwargs.get('params', None) p = {} for param in self.params: p[param.tag] = (param.text,param.attrib) self.unif1 = p.get('unif1') self.unif2 = p.get('unif2') try: self.dome_corr = p.get('perform_dome_correction')[0] except: self.dome_corr = False self.dome_corr = self.dome_corr in ['yes','ja','1','true'] print "Perform dome correction = ", self.dome_corr print "unif and lin matching criteria:" print self.unif1 print self.unif2 # data comes either as: # - two series of each 1 instance (1 instance for each detector) # - one series, one instance (multiframe: frame0=detector1, frame1=detector2) # - one series, two instances (1 instance for each detector) # # FIXME: better handling of all three possibilities (incl naming of detector labels) serieslist = data.getAllSeries() for series in serieslist: print "Current series: ", series[0].SeriesDescription #instances = series[1] for instance in series: print instance.SeriesDescription dicomobject = instance tmpseriesdescription = dicomobject[tag.Tag("0008","103E")].value try: if self.unif1[1]['seriesdescription'] == tmpseriesdescription: print "UNIF1 series Match!" tmp = self.unif1[1]['instancetag'].split(',') tmpinstancetag = tag.Tag(tmp[0],tmp[1]) print "instance tag: ", tmp print "instance tag val: ", dicomobject[tmpinstancetag].value print '--',self.unif1[0] if self.unif1[0] == str(dicomobject[tmpinstancetag].value): print "UNIF1 instance Match!" try: if int(dicomobject[tag.Tag("0028","0008")].value) > 1: print "multiframe! " bits = int(dicomobject[tag.Tag("0028","0100")].value) frames = int(dicomobject[tag.Tag("0028","0008")].value) rows = int(dicomobject[tag.Tag("0028","0010")].value) columns = int(dicomobject[tag.Tag("0028","0011")].value) count = rows*columns*frames if bits == 8: dtype = np.uint8 elif bits == 16: dtype = np.uint16 elif bits == 32: dtype = np.uint32 tmppixelmap = np.reshape(np.fromstring(dicomobject.PixelData,count=count,dtype=dtype),(frames,rows,columns)) for n in range(frames): print "Frame: ", n tmpresult = self.Uniformity_main(tmppixelmap[n],results,'det%s'%str(n+1),self.dome_corr) else: frames = 1 tmppixelmap = dicomobject.pixel_array tmpresult = self.Uniformity_main(tmppixelmap,results,'det1',self.dome_corr) except: pass except: pass try: if self.unif2[1]['seriesdescription'] == tmpseriesdescription: print "UNIF2 series Match!" tmp = self.unif2[1]['instancetag'].split(',') tmpinstancetag = tag.Tag(tmp[0],tmp[1]) if self.unif2[0] == str(dicomobject[tmpinstancetag].value): print "UNIF2 instance Match!" try: if int(dicomobject[tag.Tag("0028","0008")].value) > 1: print "multiframe! " bits = int(dicomobject[tag.Tag("0028","0100")].value) frames = int(dicomobject[tag.Tag("0028","0008")].value) rows = int(dicomobject[tag.Tag("0028","0010")].value) columns = int(dicomobject[tag.Tag("0028","0011")].value) count = rows*columns*frames if bits == 8: dtype = np.uint8 elif bits == 16: dtype = np.uint16 elif bits == 32: dtype = np.uint32 tmppixelmap = np.reshape(np.fromstring(dicomobject.PixelData,count=count,dtype=dtype),(frames,rows,columns)) for n in range(frames): print "Frame: ", n tmpresult = self.Uniformity_main(tmppixelmap[n],results,'det%s'%str(n+1),self.dome_corr) #self.resultxml.append(tmpresult) else: frames = 1 tmppixelmap = dicomobject.pixel_array tmpresult = self.Uniformity_main(tmppixelmap,results,'det2',self.dome_corr) #self.resultxml.append(tmpresult) except: pass except: pass print "End of class init"