def header_series(data, results, action): """ Read selected dicomfields and write to IQC database Workflow: 1. Run tests 2. Build results output """ try: params = action['params'] except KeyError: params = {} dcmInfile, pixeldataIn, dicomMode = wadwrapper_lib.prepareInput([data.series_filelist[0][0]], headers_only=True, logTag=logTag()) cs = qc_lib.fBIRN_Struct(dcmInfile=dcmInfile, pixeldataIn=pixeldataIn, dicomMode=dicomMode) cs.verbose = False ## 1. run tests reportkeyvals = [] dicominfo = qc_info.DICOMInfo(cs, 'dicom', 0) if len(dicominfo) >0: for di in dicominfo: reportkeyvals.append( (di[0],str(di[1])) ) ## 2. Build xml/json output varname = 'pluginversion' results.addString(varname, str(qc_lib.__version__)) for key,val in reportkeyvals: val2 = "".join([x if ord(x) < 128 else '?' for x in val]) #ignore non-ascii results.addString(key, str(val2)[:min(len(str(val)),100)])
def header_series(data, results, action, idname=None): """ Read selected dicomfields and write to IQC database """ try: params = action['params'] except KeyError: params = {} inputfile = data.series_filelist[0] # give me a [filename] wrapper_params = [ 'rgbchannel', 'auto_suffix', ] # parameters for wrapper only rgbchannel = params.get('rgbchannel', 'B') dcmInfile, pixelData, dicomMode = wadwrapper_lib.prepareInput( inputfile, headers_only=True, logTag=logTag(), rgbchannel=rgbchannel) qc = QCUS2_lib.Analysis(dcmInfile, pixelData) for name, value in params.items(): if not name in wrapper_params: qc.set_param(name, value) # find probename idname = '' if params.get('auto_suffix', False): if idname is None: idname = '_' + qc.imageID(probeonly=True) # add pluginversion to 'result' object add_plugin_version(qc, results, 'pluginversion' + idname) # run tests dicominfo = qc.dicom_info() # add results to 'result' object for dtype in dicominfo.keys(): for key, val in dicominfo[dtype]: if dtype in ['int', 'float']: results.addFloat(key + idname, val) elif dtype in ['string']: results.addString(key + idname, str(val)[:min(len(str(val)), 100)]) elif dtype in ['bool']: results.addBool(key + idname, val) elif dtype in ['object']: results.addObject(key + idname, val) else: raise ValueError( "Result '{}' has unknown result type '{}'".format( key, dtype))
def OCR(data, results, action): """ Use pyOCR which for OCR """ try: params = action['params'] except KeyError: params = {} inputfile = data.series_filelist[0] # give me a [filename] dcmInfile, pixeldataIn, dicomMode = wadwrapper_lib.prepareInput( inputfile, headers_only=False, logTag=logTag()) # solve ocr params regions = {} for k, v in params.items(): #'OCR_TissueIndex:xywh' = 'x;y;w;h' #'OCR_TissueIndex:prefix' = 'prefix' #'OCR_TissueIndex:suffix' = 'suffix' if k.startswith('OCR_'): split = k.find(':') name = k[:split] stuff = k[split + 1:] if not name in regions: regions[name] = {'prefix': '', 'suffix': ''} if stuff == 'xywh': regions[name]['xywh'] = [int(p) for p in v.split(';')] elif stuff == 'prefix': regions[name]['prefix'] = v elif stuff == 'suffix': regions[name]['suffix'] = v elif stuff == 'type': regions[name]['type'] = v for name, region in regions.items(): txt, part = ocr_lib.OCR(pixeldataIn, region['xywh']) if region['type'] == 'object': import scipy im = scipy.misc.toimage(part) fn = '%s.jpg' % name im.save(fn) results.addObject(name, fn) else: value = ocr_lib.txt2type(txt, region['type'], region['prefix'], region['suffix']) if region['type'] == 'float': results.addFloat(name, value) elif region['type'] == 'string': results.addString(name, value) elif region['type'] == 'bool': results.addBool(name, value)
def qc_series(data, results, action): """ QCMR_UMCU Checks: Philips fBIRN analysis reimplemented in python Weisskoff analysis Ghosting Residual Noise Temporal Fluctuation Spatial Noise Workflow: 1. Read image or sequence 2. Run test 3. Build results output """ try: params = action['params'] except KeyError: params = {} ## 1. read images dcmInfile,pixeldataIn,dicomMode = wadwrapper_lib.prepareInput(data.series_filelist[0], headers_only=False, logTag=logTag(), skip_check=True, splitOnPosition=False) qclib = qc_lib.fBIRN_QC() cs = qc_lib.fBIRN_Struct(dcmInfile=dcmInfile, pixeldataIn=pixeldataIn, dicomMode=dicomMode) cs.verbose = True # output lot's of comments ## 2. Run tests reportkeyvals = [] error, namevals = qclib.QC(cs) if not error: for typ, name, val in namevals: reportkeyvals.append( (typ, name, val) ) if error: raise ValueError("{} ERROR! processing error in QC".format(logTag())) for typ, name, val in reportkeyvals: if typ == 'float': results.addFloat(name, val) elif typ == 'string': results.addString(name, val) elif typ == 'object': results.addObject(name, val)
def snr_series(data, results, action): """ QCMR_UMCU Checks: B0 mapping test Workflow: 1. Read image or sequence 2. Run test 3. Build results output """ try: params = action['params'] except KeyError: params = {} ## 1. read images dcmInfile,pixeldataIn,dicomMode = wadwrapper_lib.prepareInput(data.series_filelist[0], headers_only=False, logTag=logTag(), skip_check=True, splitOnPosition=False) qclib = qc_lib.fBIRN_QC() cs = qc_lib.fBIRN_Struct(dcmInfile=dcmInfile, pixeldataIn=pixeldataIn, dicomMode=dicomMode) cs.verbose = True # output lot's of comments if 'circleradiusfactor' in params: qclib.usePartCircle = float(params['circleradiusfactor']) ## 2. Run tests reportkeyvals = [] error, namevals = qclib.PureSNR(cs) if not error: for typ, name, val in namevals: reportkeyvals.append( (typ, name, val) ) if error: raise ValueError("{} ERROR! processing error in PureSNR".format(logTag())) for typ, name, val in reportkeyvals: if typ == 'float': results.addFloat(name, val) elif typ == 'string': results.addString(name, val) elif typ == 'object': results.addObject(name, val)
def header_series(data, results, action): """ Read selected dicomfields and write to IQC database Workflow: 1. Run tests 2. Build xml output """ try: params = action['params'] except KeyError: params = {} info = 'dicom' dcmInfile, pixeldataIn, dicomMode = wadwrapper_lib.prepareInput(data.series_filelist[0], headers_only=True, logTag=logTag()) qcctlib = QCCT_lib.CT_QC() cs = QCCT_lib.CTStruct(dcmInfile=dcmInfile, pixeldataIn=pixeldataIn, dicomMode=dicomMode) cs.verbose = False override_settings(cs, params) error = qcctlib.HeadOrBody(cs) if(error == True or cs.anatomy == lit.stUnknown): raise ValueError("{} ERROR! Cannot determine Anatomy".format(logTag)) result_dict = {} # only uncomment if same config used for all scanners: idname += "_"+cs.guessScanner.name ## 1. Run tests dicominfo = qcctlib.DICOMInfo(cs,info) ## 2. Add results to 'result' object # plugionversion is newly added in for this plugin since pywad2 varname = 'pluginversion' results.addString(varname, str(qcctlib.qcversion)) varname = 'Anatomy' results.addString(varname, str(cs.anatomy)) for di in dicominfo: varname = di[0] results.addString(varname, str(di[1])[:min(len(str(di[1])),100)])
def qc_series(data, results, action): """ QCMR_UMCU Checks: Philips PiQT reimplementen in python Uniformity (several ways) Geometrical deformation ArtifactLevel Signal-to-noise (several positions) Resolution (MTF, FTW, SliceWidth) Workflow: 1. Read image or sequence 2. Run test 3. Build xml output """ try: params = action['params'] except KeyError: params = {} dcmInfile, pixeldataIn, dicomMode = wadwrapper_lib.prepareInput( data.series_filelist[0], headers_only=False, logTag=logTag()) qclib = QCMR_lib.PiQT_QC() cs = QCMR_lib.PiQT_Struct(dcmInfile=dcmInfile, pixeldataIn=pixeldataIn, dicomMode=dicomMode, piqttest=None) cs.verbose = False ## id scanner idname = "" error = qclib.DetermineScanID(cs) if error == True or cs.scanID == lit.stUnknown: raise ValueError("{} ERROR! Cannot determine MR Scan ID".format( logTag())) ## 2. Run tests setname = cs.scanID piqttests = [] if setname == 'QA1': piqttests = [ # seq test, "M", philips_slicenumber, echonumber, echotime, ("QA1_Uniformity", "M", 3, 1, 30), ("QA1_Uniformity", "M", 3, 2, 100), ("QA1_Linearity", "M", 2, 1, 30), ("QA1_SliceProfile", "M", 4, 1, 30), ("QA1_SliceProfile", "M", 4, 2, 100), ("QA1_MTF", "M", 5, 1, 30), ("QA1_MTF", "M", 5, 2, 100), ] elif setname == 'QA2': piqttests = [ # seq test, "M", philips_slicenumber, echonumber, echotime, ("QA2_Uniformity", "M", 2, 1, 15), ("QA2_SliceProfile", "M", 3, 1, 15), ] elif setname == 'QA3': piqttests = [ # seq test, "M", philips_slicenumber, echonumber, echotime, ("QA3_Uniformity", "M", 1, 1, 50), ("QA3_Uniformity", "M", 1, 2, 100), ("QA3_Uniformity", "M", 1, 3, 150), ] elif setname == 'MRLSNR': piqttests = [ # seq test, "M", philips_slicenumber, echonumber, element, ("MRL_SNR", "M", 1, 1, 0), ("MRL_1_SNR", "M", 1, 1, 1), ("MRL_2_SNR", "M", 1, 1, 2), ("MRL_3_SNR", "M", 1, 1, 3), ("MRL_4_SNR", "M", 1, 1, 4), ("MRL_5_SNR", "M", 1, 1, 5), ("MRL_6_SNR", "M", 1, 1, 6), ("MRL_7_SNR", "M", 1, 1, 7), ("MRL_8_SNR", "M", 1, 1, 8), ] reportkeyvals = [] for piqt in piqttests: print("[mrqc]", 2, piqt) if "Uniformity" in piqt[0]: test = lit.stTestUniformity doTest = "SNR_ArtifactLevel_FloodFieldUniformity" if "Linearity" in piqt[0]: test = lit.stTestSpatialLinearity doTest = "SpatialLinearity" if "SliceProfile" in piqt[0]: test = lit.stTestSliceProfile doTest = "SliceProfile" if "MTF" in piqt[0]: test = lit.stTestMTF doTest = "MTF" if "SNR" in piqt[0]: # MRL SNR test is performed per slice. Prepare input for single dicom file test = lit.stTestSNR doTest = "SNR" dcmsnr = [data.series_filelist[0][piqt[4]]] dcmInfile, pixeldataIn, dicomMode = wadwrapper_lib.prepareInput( dcmsnr, headers_only=False, logTag=logTag()) cs = QCMR_lib.PiQT_Struct(dcmInfile, pixeldataIn, dicomMode, piqt) cs.verbose = None if "FloodFieldUniformity" in doTest: # FFU also contains SNR and ArtifactLevel error = qclib.FloodFieldUniformity(cs) if not error: import numpy as np idname = "_" + setname + make_idname(qclib, cs, cs.snr_slice) reportkeyvals.append(("S/N (B)" + idname, cs.snr_SNB)) reportkeyvals.append( ("Art_Level" + idname, cs.artefact_ArtLevel)) reportkeyvals.append(("T/C-20" + idname, cs.ffu_TCm20)) reportkeyvals.append(("C-20/C-10" + idname, cs.ffu_Cm20Cm10)) reportkeyvals.append(("C-10/C+10" + idname, cs.ffu_Cm10Cp10)) reportkeyvals.append(("C+10/C+20" + idname, cs.ffu_Cp10Cp20)) reportkeyvals.append(("C+20/Max" + idname, cs.ffu_Cp20MAX)) reportkeyvals.append(("Rad 10%" + idname, cs.ffu_rad10)) reportkeyvals.append(("Int_Unif" + idname, cs.ffu_lin_unif)) ## Build thumbnail filename = 'FFU' + idname + '.jpg' # Use jpg if a thumbnail is desired qclib.saveResultImage(cs, 'FFU', filename) varname = 'FFU' + '_' + idname results.addObject(varname, filename) elif "ArtifactLevel" in doTest: # Artifact also contains SNR error = qclib.ArtifactLevel(cs) if not error: idname = "_" + setname + make_idname(qclib, cs, cs.snr_slice) reportkeyvals.append(("S/N (B)" + idname, cs.snr_SNB)) reportkeyvals.append( ("Art_Level" + idname, cs.artefact_ArtLevel)) elif "SNR" in doTest: # MRL SNR test only needs S/N (B) as output/specd value error = qclib.SNR(cs) if not error: idname = "_" + setname + make_idname( qclib, cs, cs.snr_slice) + "_" + str(piqt[4]) reportkeyvals.append(("S/N (B)" + idname, cs.snr_SNB)) if "SpatialLinearity" in doTest: error = qclib.SpatialLinearity(cs) if not error: idname = "_" + setname + make_idname(qclib, cs, cs.lin_slice) reportkeyvals.append( ("phant_rot" + idname, cs.lin_phantomrotdeg)) reportkeyvals.append(("m/p_angle" + idname, str(-360))) reportkeyvals.append(("size_hor" + idname, cs.lin_sizehor)) reportkeyvals.append(("size_ver" + idname, cs.lin_sizever)) reportkeyvals.append( ("hor_int_av" + idname, cs.lin_intshiftavg[0])) reportkeyvals.append( ("hor_int_dev" + idname, cs.lin_intshiftsdev[0])) reportkeyvals.append( ("hor_max_right" + idname, cs.lin_shiftmax[0])) reportkeyvals.append( ("hor_max_left" + idname, cs.lin_shiftmin[0])) reportkeyvals.append( ("hor_diff_av" + idname, cs.lin_intdiffavg[0])) reportkeyvals.append( ("hor_diff_dev" + idname, cs.lin_intdiffsdev[0])) reportkeyvals.append( ("hor_max" + idname, cs.lin_intdiffmax[0])) reportkeyvals.append( ("hor_min" + idname, cs.lin_intdiffmin[0])) reportkeyvals.append( ("ver_int_av" + idname, cs.lin_intshiftavg[1])) reportkeyvals.append( ("ver_int_dev" + idname, cs.lin_intshiftsdev[1])) reportkeyvals.append( ("ver_max_up" + idname, cs.lin_shiftmax[1])) reportkeyvals.append( ("ver_max_down" + idname, cs.lin_shiftmin[1])) reportkeyvals.append( ("ver_diff_av" + idname, cs.lin_intdiffavg[1])) reportkeyvals.append( ("ver_diff_dev" + idname, cs.lin_intdiffsdev[1])) reportkeyvals.append( ("ver_max" + idname, cs.lin_intdiffmax[1])) reportkeyvals.append( ("ver_min" + idname, cs.lin_intdiffmin[1])) reportkeyvals.append(("lin_NEMA" + idname, cs.lin_nema_max)) ## Build thumbnail filename = 'LIN' + idname + '.jpg' # Use jpg if a thumbnail is desired qclib.saveResultImage(cs, 'LIN', filename) varname = 'LIN' + '_' + idname results.addObject(varname, filename) if "SliceProfile" in doTest: error = qclib.SliceProfile(cs) if not error: idname = "_" + setname + make_idname(qclib, cs, cs.sp_slice) reportkeyvals.append( ("Pos_shift" + idname, cs.sp_phantomshift)) reportkeyvals.append(("FWHM" + idname, cs.sp_slicewidth_fwhm)) reportkeyvals.append(("FWTM" + idname, cs.sp_slicewidth_fwtm)) reportkeyvals.append( ("Slice_int" + idname, cs.sp_slicewidth_lineint)) reportkeyvals.append( ("Angle" + idname, cs.sp_phantomzangledeg)) reportkeyvals.append( ("phant_rot" + idname, cs.sp_phantomrotdeg)) reportkeyvals.append( ("Phase_Shift" + idname, cs.sp_phaseshift)) ## Build thumbnail filename = 'SLP' + idname + '.jpg' # Use jpg if a thumbnail is desired qclib.saveResultImage(cs, 'SLP', filename) varname = 'SLP' + '_' + idname results.addObject(varname, filename) if "MTF" in doTest: error = qclib.MTF(cs) if not error: idname = "_" + setname + make_idname(qclib, cs, cs.mtf_slice) reportkeyvals.append( ("Hor_pxl_size" + idname, cs.mtf_pixelsize[0])) reportkeyvals.append( ("Ver_pxl_size" + idname, cs.mtf_pixelsize[1])) ## Build thumbnail filename = 'MTF' + idname + '.jpg' # Use jpg if a thumbnail is desired qclib.saveResultImage(cs, 'MTF', filename) varname = 'MTF' + '_' + idname results.addObject(varname, filename) if error: raise ValueError("{} ERROR! processing error in {} {}".format( logTag(), piqt, doTest)) for key, val in reportkeyvals: results.addFloat(key, val)
def header_series(data, results, action): """ Read selected dicomfields and write to IQC database Workflow: 1. Run tests 2. Build xml output """ try: params = action['params'] except KeyError: params = {} info = 'dicom' dcmInfile, pixeldataIn, dicomMode = wadwrapper_lib.prepareInput( data.series_filelist[0], headers_only=True, logTag=logTag()) qclib = QCMR_lib.PiQT_QC() cs = QCMR_lib.PiQT_Struct(dcmInfile=dcmInfile, pixeldataIn=pixeldataIn, dicomMode=dicomMode, piqttest=None) cs.verbose = False ## id scanner idname = "" error = qclib.DetermineScanID(cs) if error == True or cs.scanID == lit.stUnknown: raise ValueError("{} ERROR! Cannot determine MR Scan ID".format( logTag())) ## 1. Run tests setname = cs.scanID piqttests = [] if setname == 'QA1': piqttests = [ # seq test, "M", philips_slicenumber, echonumber, echotime, ("QA1_Uniformity", "M", 3, 1, 30), ("QA1_Uniformity", "M", 3, 2, 100), ("QA1_Linearity", "M", 2, 1, 30), ("QA1_SliceProfile", "M", 4, 1, 30), ("QA1_SliceProfile", "M", 4, 2, 100), ("QA1_MTF", "M", 5, 1, 30), ("QA1_MTF", "M", 5, 2, 100), ] elif setname == 'QA2': piqttests = [ # seq test, "M", philips_slicenumber, echonumber, echotime, ("QA2_Uniformity", "M", 2, 1, 15), ("QA2_SliceProfile", "M", 3, 1, 15), ] elif setname == 'QA3': piqttests = [ # seq test, "M", philips_slicenumber, echonumber, echotime, ("QA3_Uniformity", "M", 1, 1, 50), ("QA3_Uniformity", "M", 1, 2, 100), ("QA3_Uniformity", "M", 1, 3, 150), ] elif setname == 'MRLSNR': piqttests = [ # seq test, "M", philips_slicenumber, echonumber, echotime, ("MRL_SNR", "M", 1, 1, 0), ("MRL_1_SNR", "M", 1, 1, 1), ("MRL_2_SNR", "M", 1, 1, 2), ("MRL_3_SNR", "M", 1, 1, 3), ("MRL_4_SNR", "M", 1, 1, 4), ("MRL_5_SNR", "M", 1, 1, 5), ("MRL_6_SNR", "M", 1, 1, 6), ("MRL_7_SNR", "M", 1, 1, 7), ("MRL_8_SNR", "M", 1, 1, 8), ] reportkeyvals = [] for piqt in piqttests: cs = QCMR_lib.PiQT_Struct(dcmInfile, pixeldataIn, dicomMode, piqt) cs.verbose = None ## 1b. Run tests sliceno = qclib.ImageSliceNumber(cs, piqt) if sliceno < 0: msg = "{} [mrheader]: {} not available for given image".format( logTag(), piqt) print(msg) raise ValueError(msg) dicominfo = qclib.DICOMInfo(cs, info, sliceno) if len(dicominfo) > 0: idname = "_" + setname + make_idname(qclib, cs, sliceno) for di in dicominfo: reportkeyvals.append((di[0] + idname, str(di[1]))) ## 2. Build xml output floatlist = ['Central_freq'] # plugionversion is newly added in for this plugin since pywad2 varname = 'pluginversion' + idname results.addString(varname, str(qclib.qcversion)) # do use default from config for key, val in reportkeyvals: is_float = False for fl in floatlist: if key.startswith(fl): is_float = True break if is_float: try: val2 = float(val) except ValueError: val2 = -1 results.addFloat(key, val2) else: val2 = "".join([x if ord(x) < 128 else '?' for x in val]) #ignore non-ascii results.addString( key, str(val2) [:min(len(str(val)), 100)]) # do use default from config
def qc_series(data, results, action): """ QCCT_UMCU Checks: extension of Philips QuickIQ (also for older scanners without that option), for both Head and Body if provided Uniformity HU values Noise Linearity Workflow: 1. Read image or sequence 2. Run test 3. Build xml output """ try: params = action['params'] except KeyError: params = {} dcmInfile, pixeldataIn, dicomMode = wadwrapper_lib.prepareInput(data.series_filelist[0], headers_only=False, logTag=logTag()) qclib = QCCT_lib.CT_QC() cs = QCCT_lib.CTStruct(dcmInfile=dcmInfile, pixeldataIn=pixeldataIn, dicomMode=dicomMode) cs.forceScanner = _getScannerDefinition(params) cs.verbose = False override_settings(cs, params) ## id scanner error = qclib.DetermineCTID(cs) if(error == True or cs.guessScanner.name == lit.stUnknown): raise ValueError("{} ERROR! Cannot determine CT ID".format(logTag)) error = qclib.HeadOrBody(cs) if(error == True or cs.anatomy == lit.stUnknown): raise ValueError("{} ERROR! Cannot determine Anatomy".format(logTag)) # only uncomment if same config used for all scanners: idname += cs.guessScanner.name ## 2. Run tests error = qclib.AnalyseCT(cs) if error: raise ValueError("{} ERROR! Error in AnalyseCT".format(logTag)) ## Struct now contains all the results and we can write these to the ## WAD IQ database includedlist = [ 'skull_avg', 'roiavg', 'roisd', 'snr_hol', 'unif', 'linearity', 'maxdev', 'shiftxypx', ] excludedlist = [ 'verbose', 'dcmInfile', 'pixeldataIn', 'dicomMode', 'hasmadeplots', 'guessScanner', 'anatomy', 'roiavg', 'roisd', 'snr_hol', 'unif', 'linearity', 'maxdev', 'shiftxypx', 'valid' 'unif_slice', 'unif_rois' ] skull_val = -2024 # low value, will need a higher # make sure skull_avg is used if valid, but preserve order of results for elem in cs.__dict__: if elem in includedlist: try: elemval = cs.__dict__[elem] if 'skull_avg' in elem: # skull_avg only defined for head skull_val = elemval break except: print(logTag()+"error for", elem) for elem in cs.__dict__: if elem in includedlist: newkeys = [] newvals = [] try: elemval = cs.__dict__[elem] if 'roiavg' in elem: # array of avgs newkeys.append('MeanCenter') newvals.append(elemval[0]) newkeys.append('MeanAir') newvals.append(elemval[3]) if skull_val <= -1024: # skull_avg only defined for head; if not head, then take teflon plug newkeys.append('MeanHigh') newvals.append(max(elemval)) elif 'shiftxypx' in elem: newkeys.append('shiftxpx') newvals.append(elemval[0]) newkeys.append('shiftypx') newvals.append(elemval[1]) elif 'skull_avg' in elem: skull_val = elemval if elemval > -1024: # skull_avg only defined for head; if not head, then take teflon plug newkeys.append('MeanHigh') newvals.append(elemval) else: newkeys.append(str(elem)) newvals.append(elemval) except: print(logTag()+"error for",elem) elemval = -1. for key,val in zip(newkeys,newvals): varname = key results.addFloat(varname, val) ## Build thumbnail filename = 'test'+'.jpg' # Use jpg if a thumbnail is desired qclib.saveAnnotatedImage(cs, filename) varname = 'CTslice' results.addObject(varname, filename)
def setup_series(inputfile, params, headers_only, for_action): """ Shared routine to set runtime parameters and build structure Workflow: 1. Set runtime parameters 2. Check data format 3. Build and populate qcstructure """ # 1. Set runtime parameters # 2. Check data format rgbchannel = params.get('rgbchannel', 'B') dcmInfile, pixeldataIn, dicomMode = wadwrapper_lib.prepareInput( inputfile, headers_only=headers_only, logTag=logTag(), rgbchannel=rgbchannel) # 3. Build and populate qcstructure qclib = QCUS_lib.US_QC(guimode=False) cs = QCUS_lib.USStruct(dcmInfile, pixeldataIn, dicomMode) if for_action == 'ocr': optional_pars = [ # parname, attribname, type, default ('verbose', 'verbose', 'boolean', False), # by default do not produce detailed logging ('auto_suffix', 'auto_suffix', 'boolean', True), # by default try to add a probename suffix to each result # ocr_threshold and ocr_zoom handled in OCR action ] required_pars = [] elif for_action == 'qc': optional_pars = [ # parname, attribname, type, default ('verbose', 'verbose', 'boolean', False), # by default do not produce detailed logging ('auto_suffix', 'auto_suffix', 'boolean', True), # by default try to add a probename suffix to each result ('signal_thresh', 'signal_thresh', 'int', None), # no default value ('cluster_mode', 'cluster_mode', 'string', None), # no default value ('uni_start', 'uni_start', 'string', None), # no default value ('rev_bbox', 'rev_forcebbox', 'stringint4', None), # no default value ('uni_range_model', 'uni_range_model', 'string', None), # no default value ] required_pars = [ # parname, attribname, type ('uni_filter', 'uni_filter', 'int'), ('uni_delta', 'uni_delta', 'float'), ('uni_depth', 'uni_depth', 'float'), ('sen_filter', 'sen_filter', 'int'), ('sen_delta', 'sen_delta', 'float'), ('ver_offset', 'ver_offset', 'int'), ('hor_offset', 'hor_offset', 'int'), ('fitcircle_frac', 'fitcircle_frac', 'float'), ('cluster_fminsize', 'cluster_fminsize', 'float'), ] elif for_action == 'hdrs': optional_pars = [ # parname, attribname, type, default ('verbose', 'verbose', 'boolean', False), # by default do not produce detailed logging ('auto_suffix', 'auto_suffix', 'boolean', True), # by default try to add a probename suffix to each result ] required_pars = [] # optional parameters for parname, attname, partype, default in optional_pars: try: val = params[parname] if partype == 'boolean': if isinstance(val, str): val = val.lower() in ['1', 'true', 'y', 'yes'] elif partype == 'int': val = int(val) elif partype == 'stringint4': val = [int(v) for v in val.split(';')] setattr(cs, attname, val) except: if not default is None: # only if a default value is given setattr(cs, attname, default) # optional parameters #required for parname, attname, partype in required_pars: val = params[parname] if partype == 'boolean': if isinstance(val, str): val = val.lower() in ['1', 'true', 'y', 'yes'] elif partype == 'int': val = int(val) elif partype == 'stringint4': val = [int(v) for v in val.split(';')] setattr(cs, attname, val) return qclib, cs
def OCR(data, results, action, idname): """ Use pyOCR which for OCR returns rect rois for plotting in overview If results is None, just return the OCR content, do not add to results """ try: params = action['params'] except KeyError: params = {} # optional parameters ocr_options = {} for lab in ['ocr_threshold', 'ocr_zoom', 'ocr_border']: if lab in params: ocr_options[lab] = int(params[lab]) inputfile = data.series_filelist[0] # give me a [filename] rgbchannel = params.get('rgbchannel', 'B') dcmInfile, pixelData, dicomMode = wadwrapper_lib.prepareInput( inputfile, headers_only=False, logTag=logTag(), rgbchannel=rgbchannel) # find probename idname = '' if params.get('auto_suffix', False): if idname is None: idname = '_' + qc.imageID(probeonly=True) # add pluginversion to 'result' object add_plugin_version(qc, results, 'pluginversion' + idname) rectrois = [] error = False msg = '' values = {} # solve ocr params ocr_regions = params.get('ocr_regions', {}) # new format regions = {} for ocrname, ocrparams in ocr_regions.items(): regions[ocrname] = {'prefix': '', 'suffix': ''} for key, val in ocrparams.items(): if key == 'xywh': regions[ocrname]['xywh'] = [int(p) for p in val.split(';')] elif key == 'prefix': regions[ocrname]['prefix'] = val elif key == 'suffix': regions[ocrname]['suffix'] = val elif key == 'type': regions[ocrname]['type'] = val for name, region in regions.items(): rectrois.append([(region['xywh'][0], region['xywh'][1]), (region['xywh'][0] + region['xywh'][2], region['xywh'][1] + region['xywh'][3])]) txt, part = ocr_lib.OCR(pixelData, region['xywh'], **ocr_options) uname = name + str(idname) if region['type'] == 'object': im = toimage(part) fn = '{}.jpg'.format(uname) im.save(fn) results.addObject(uname, fn) else: try: value = ocr_lib.txt2type(txt, region['type'], region['prefix'], region['suffix']) if not results is None: if region['type'] == 'float': results.addFloat(uname, value) elif region['type'] == 'string': results.addString(uname, value) elif region['type'] == 'bool': results.addBool(uname, value) else: values[uname] = value except: print("error", uname, value) error = True msg += uname + ' ' im = toimage(part) fn = '{}.jpg'.format(uname) im.save(fn) if results is None: return values, error, msg return rectrois, error, msg
def qc_series(data, results, action, idname): """ US Reverberations in Air analysis: Check the uniformity of the reverberation patterns Params needs to define: nothing yet Workflow: 1. Set runtime parameters 2. Check data format 3. Build and populate qcstructure 4. Run tests 5. Build xml output 6. Build artefact picture thumbnail """ # 1.-3. try: params = action['params'] except KeyError: params = {} inputfile = data.series_filelist[0] # give me a [filename] wrapper_params = [ 'rgbchannel', 'auto_suffix', ] # parameters for wrapper only rgbchannel = params.get('rgbchannel', 'B') dcmInfile, pixelData, dicomMode = wadwrapper_lib.prepareInput( inputfile, headers_only=False, logTag=logTag(), rgbchannel=rgbchannel) # correct data order wadwrapper_lib return x,y data if len(pixelData.shape) == 2: pixelData = np.transpose(pixelData, (1, 0)) elif len(pixelData.shape) == 3: pixelData = np.transpose(pixelData, (0, 2, 1)) qc = QCUS2_lib.Analysis(dcmInfile, pixelData) for name, value in params.items(): if not name in wrapper_params: qc.set_param(name, value) qc.run() if GUIMODE: qc.show_report() print("Result in {}".format(os.getcwd())) matplotlib.pyplot.show() # find probename idname = '' if params.get('auto_suffix', False): if idname is None: idname = '_' + qc.imageID(probeonly=True) # add pluginversion to 'result' object add_plugin_version(qc, results, 'pluginversion' + idname) # add results to 'result' object report = qc.get_report() for section in report.keys(): for key, vals in report[section].items(): if vals[0] in ['int', 'float']: results.addFloat(key + idname, vals[1]) elif vals[0] in ['string']: results.addString(key + idname, vals[1]) elif vals[0] in ['bool']: results.addBool(key + idname, vals[1]) elif vals[0] in ['object']: results.addObject(key + idname, vals[1]) else: raise ValueError( "Result '{}' has unknown result type '{}'".format( key, vals[0])) return qc # for write_images
def qc_uniformity_series(data, results, action): """ n13_uniformity checks: Uniformity Artefacts Workflow: 2. Check data format 3. Build and populate qcstructure 4. Run tests 5. Build xml output 6. Build artefact picture thumbnail """ try: params = action['params'] except KeyError: params = {} inputfile = data.series_filelist[0] # give me a filename ## 2. Check data format dcmInfile,pixeldataIn,dicomMode = wadwrapper_lib.prepareInput(inputfile,headers_only=False,logTag=logTag()) # select only middle slice for series numslices = len(pixeldataIn) if dicomMode == wadwrapper_lib.stMode3D: nim = int(len(pixeldataIn)/2.) dcmInfile = dcmInfile._datasets[nim] pixeldataIn = np.average(pixeldataIn, axis=0) dicomMode = wadwrapper_lib.stMode2D ## 3. Build and populate qcstructure remark = "" qclib = n13_lib.XRayQC() room = _getRoomDefinition(params, "unif") cs = n13_lib.XRayStruct(dcmInfile,pixeldataIn,room) cs.verbose = False # do not produce detailed logging ## 4. Run tests error,msg = qclib.QCUnif(cs) ## 5. Build xml output ## Struct now contains all the results and we can write these to the WAD IQ database if not cs.DetectorSuffix() is None: idname = '_'+cs.DetectorSuffix() else: idname = '' ## First Build artefact picture thumbnail label = 'artefacts' filename = '%s%s.jpg'%(label,idname) # Use jpg if a thumbnail is desired qclib.saveAnnotatedImage(cs, filename, 'artefacts') varname = '%s%s'%(label,idname) results.addObject(varname, filename) ## also add uniformity thumbnail label = 'uniformity' filename = '%s%s.jpg'%(label,idname) # Use jpg if a thumbnail is desired qclib.saveAnnotatedImage(cs, filename, 'uniformity') varname = '%s%s'%(label,idname) results.addObject(varname, filename) labvals = qclib.ReportEntries(cs) tmpdict={} for elem in labvals: varname = elem['name']+str(idname) results.addFloat(varname, elem['value']) results.addFloat('num_slices'+str(idname), numslices)