Example #1
0
def setup_series(inputfile, params, headers_only):
    """
    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
    dcmInfile, pixeldataIn, dicomMode = wadwrapper_lib.prepareInput(
        inputfile, headers_only=headers_only, logTag=logTag())

    # 3. Build and populate qcstructure
    qclib = QCUS_lib.US_QC(guimode=False)
    cs = QCUS_lib.USStruct(dcmInfile, pixeldataIn, dicomMode)
    cs.verbose = False  # do not produce detailed logging
    cs.uni_filter = int(params.find("uni_filter").text)
    cs.uni_delta = float(params.find("uni_delta").text)
    cs.uni_low = float(params.find("uni_low").text)
    cs.sen_filter = int(params.find("sen_filter").text)
    cs.sen_delta = float(params.find("sen_delta").text)
    cs.ver_offset = int(params.find("ver_offset").text)
    cs.hor_offset = int(params.find("hor_offset").text)
    cs.fitcircle_frac = float(params.find("fitcircle_frac").text)
    cs.cluster_fminsize = float(params.find("cluster_fminsize").text)
    try:
        cs.verbose = params.find('verbose').text.lower() in [
            '1', 'true', 'y', 'yes'
        ]
    except:
        pass
    return qclib, cs
Example #2
0
def cdmamsetup_series(inputfile, params, headers_only):
    """
    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
    if not headers_only:  # then we can skip the parameter check
        try:
            phantomversion = params.find("phantomversion").text
        except AttributeError:
            raise ValueError(logTag() + " missing phantomversion parameter!")

        try:
            modeCDCOM = (params.find("modeCDCOM").text == 'True')
        except AttributeError:
            raise ValueError(logTag() + " missing cdcommode parameter!")
    else:
        phantomversion = '3.2'  # dummy for headers
        modeCDCOM = False

    # 2. Check data format
    dcmInfile, pixeldataIn, dicomMode = wadwrapper_lib.prepareInput(
        inputfile, headers_only=headers_only, logTag=logTag())

    # 3. Build and populate qcstructure
    qclib = CDMam_lib.CDMam()
    cs = CDMam_lib.CDMamStruct(dcmInfile, pixeldataIn, phantomversion)
    cs.imnum = 0  # needs to be set to an increasing number if multiple files are used
    cs.verbose = False  # do not produce detailed logging
    cs.imageFileName = inputfile[0]  # only for CDCOM.exe
    qclib.determineScannerID(cs)
    return qclib, cs, modeCDCOM
Example #3
0
def cdmamsetup_series(inputfile,params,headers_only):
    """
    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
    if not headers_only: # then we can skip the parameter check
        try:
            phantomversion = params.find("phantomversion").text
        except AttributeError:
            raise ValueError(logTag()+" missing phantomversion parameter!")
    
        try:
            modeCDCOM = (params.find("modeCDCOM").text == 'True')
        except AttributeError:
            raise ValueError(logTag()+" missing cdcommode parameter!")
    else:
        phantomversion = '3.2' # dummy for headers
        modeCDCOM = False

    # 2. Check data format
    dcmInfile,pixeldataIn,dicomMode = wadwrapper_lib.prepareInput(inputfile,headers_only=headers_only,logTag=logTag())

    # 3. Build and populate qcstructure
    qclib = CDMam_lib.CDMam()
    cs = CDMam_lib.CDMamStruct(dcmInfile,pixeldataIn,phantomversion)
    cs.imnum = 0 # needs to be set to an increasing number if multiple files are used
    cs.verbose = False # do not produce detailed logging
    cs.imageFileName = inputfile[0] # only for CDCOM.exe
    qclib.determineScannerID(cs)
    return qclib,cs,modeCDCOM
Example #4
0
def setup_series(inputfile, params, headers_only):
    """
    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
    """
    if not headers_only: # then we can skip the parameter check
        try:
            phantomversion = params.find("phantomversion").text
        except AttributeError:
            raise ValueError(logTag()+" missing phantomversion parameter!")
    
        try:
            modeCDCOM = (params.find("modeCDCOM").text == 'True')
        except AttributeError:
            raise ValueError(logTag()+" missing cdcommode parameter!")
    else:
        phantomversion = '3.2' # dummy for headers
        modeCDCOM = False
    """
    # 2. Check data format
    dcmInfile, pixeldataIn, dicomMode = wadwrapper_lib.prepareInput(
        inputfile, headers_only=headers_only, logTag=logTag())

    # 3. Build and populate qcstructure
    qclib = QCUS_lib.US_QC(guimode=False)
    cs = QCUS_lib.USStruct(dcmInfile, pixeldataIn, dicomMode)
    cs.verbose = False  # do not produce detailed logging
    return qclib, cs
Example #5
0
def setup_series(inputfile,params,headers_only):
    """
    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
    """
    if not headers_only: # then we can skip the parameter check
        try:
            phantomversion = params.find("phantomversion").text
        except AttributeError:
            raise ValueError(logTag()+" missing phantomversion parameter!")
    
        try:
            modeCDCOM = (params.find("modeCDCOM").text == 'True')
        except AttributeError:
            raise ValueError(logTag()+" missing cdcommode parameter!")
    else:
        phantomversion = '3.2' # dummy for headers
        modeCDCOM = False
    """
    # 2. Check data format
    dcmInfile,pixeldataIn,dicomMode = wadwrapper_lib.prepareInput(inputfile,headers_only=headers_only,logTag=logTag())

    # 3. Build and populate qcstructure
    qclib = QCUS_lib.US_QC(guimode=False)
    cs = QCUS_lib.USStruct(dcmInfile,pixeldataIn,dicomMode)
    cs.verbose = False # do not produce detailed logging
    return qclib,cs
Example #6
0
def xrayqc_series(data, results, params):
    """
    QCXRay_UMCU checks:
        Horizontal uniformity
        XRayEdges
        LowContrast
        DynamicRange
        MTF

    Workflow:
        2. Check data format
        3. Build and populate qcstructure
        4. Run tests
        5. Build xml output
        6. Build artefact picture thumbnail
    """
    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())

    ## 3. Build and populate qcstructure
    remark = ""
    qclib = QCXRay_lib.XRayQC()
    room = _getRoomDefinition(params)
    cs = QCXRay_lib.XRayStruct(dcmInfile, pixeldataIn, room)
    cs.verbose = False  # do not produce detailed logging

    ## 4. Run tests
    error, msg = qclib.QC(cs)

    ## 5. Build xml output
    ## Struct now contains all the results and we can write these to the WAD IQ database
    stand = qclib.TableOrWall(cs)
    idname = '_' + stand

    labvals = qclib.ReportEntries(cs)
    tmpdict = {}
    for elem in labvals:
        #labvals.append( {'name':'label','value':0, 'quantity':'columnname','level':'1:default, 2: detail','pos':missing or a number} )
        # if no pos given, the next one will be given
        # if no quantity given, 'name' will be used
        # if no level given, the default will be used
        quan = elem['quantity'] if 'quantity' in elem else str(elem['name'])
        level = elem['level'] if 'level' in elem else None
        rank = elem['rank'] if 'rank' in elem else None
        results.addFloat(elem['name'] + str(idname),
                         elem['value'],
                         quantity=quan,
                         level=level,
                         rank=rank)

    ## 6. Build artefact picture thumbnail
    filename = 'test' + idname + '.jpg'  # Use jpg if a thumbnail is desired

    qclib.saveAnnotatedImage(cs, filename)
    results.addObject('AnnotatedImage' + idname, filename)
Example #7
0
def xrayqc_uniformity_series(data, results, params):
    """
    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
    """
    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())

    ## 3. Build and populate qcstructure
    remark = ""
    qclib = n13_lib.XRayQC()
    room = _getRoomDefinition(params)
    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 = 'unif'
    filename = '%s%s.jpg'%(label,idname) # Use jpg if a thumbnail is desired

    qclib.saveAnnotatedImage(cs,filename, 'artefacts')
    results.addObject('%s%s'%(label,idname),filename)

    labvals = qclib.ReportEntries(cs)
    tmpdict={}
    for elem in labvals:
        #labvals.append( {'name':'label','value':0, 'quantity':'columnname','level':'1:default, 2: detail','pos':missing or a number} )
        # if no pos given, the next one will be given
        # if no quantity given, 'name' will be used
        # if no level given, the default will be used
        quan = elem['quantity'] if 'quantity' in elem else str(elem['name'])
        level = elem['level'] if 'level' in elem else None
        rank = elem['rank'] if 'rank' in elem else None
        results.addFloat(elem['name']+str(idname), elem['value'], quantity=quan, level=level,rank=rank)
Example #8
0
def xrayqc_series(data, results, params):
    """
    QCXRay_UMCU checks:
        Horizontal uniformity
        XRayEdges
        LowContrast
        DynamicRange
        MTF

    Workflow:
        2. Check data format
        3. Build and populate qcstructure
        4. Run tests
        5. Build xml output
        6. Build artefact picture thumbnail
    """
    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())

    ## 3. Build and populate qcstructure
    remark = ""
    qclib = QCXRay_lib.XRayQC()
    room = _getRoomDefinition(params)
    cs = QCXRay_lib.XRayStruct(dcmInfile, pixeldataIn, room)
    cs.verbose = False  # do not produce detailed logging

    ## 4. Run tests
    error, msg = qclib.QC(cs)

    ## 5. Build xml output
    ## Struct now contains all the results and we can write these to the WAD IQ database
    stand = qclib.TableOrWall(cs)
    idname = '_' + stand

    labvals = qclib.ReportEntries(cs)
    tmpdict = {}
    for key, val in labvals:
        results.addFloat(key + str(idname), val, quantity=str(key))

    ## 6. Build artefact picture thumbnail
    filename = 'test' + idname + '.jpg'  # Use jpg if a thumbnail is desired

    qclib.saveAnnotatedImage(cs, filename)
    results.addObject('AnnotatedImage' + idname, filename)
Example #9
0
def xrayqc_series(data, results, params):
    """
    QCXRay_UMCU checks:
        Horizontal uniformity
        XRayEdges
        LowContrast
        DynamicRange
        MTF

    Workflow:
        2. Check data format
        3. Build and populate qcstructure
        4. Run tests
        5. Build xml output
        6. Build artefact picture thumbnail
    """
    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())

    ## 3. Build and populate qcstructure
    remark = ""
    qclib = QCXRay_lib.XRayQC()
    room = _getRoomDefinition(params)
    cs = QCXRay_lib.XRayStruct(dcmInfile,pixeldataIn,room)
    cs.verbose = False # do not produce detailed logging

    ## 4. Run tests
    error,msg = qclib.QC(cs)

    ## 5. Build xml output
    ## Struct now contains all the results and we can write these to the WAD IQ database
    stand = qclib.TableOrWall(cs)
    idname = '_'+stand

    labvals = qclib.ReportEntries(cs)
    tmpdict={}
    for key,val in labvals:
        results.addFloat(key+str(idname), val, quantity=str(key))

    ## 6. Build artefact picture thumbnail
    filename = 'test'+idname+'.jpg' # Use jpg if a thumbnail is desired

    qclib.saveAnnotatedImage(cs,filename)
    results.addObject('AnnotatedImage'+idname,filename)
Example #10
0
def ctheader_series(data, results, params):
    """
    Read selected dicomfields and write to IQC database

    Workflow:
        1. Run tests
        2. Build xml output
    """

    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

    error = qcctlib.HeadOrBody(cs)
    if (error == True or cs.anatomy == lit.stUnknown):
        raise ValueError("{} ERROR! Cannot determine Anatomy".format(logTag))

    result_dict = {}
    idname = ""
    if cs.anatomy == lit.stHead:
        idname = "_H"
    else:
        idname = "_B"
    # 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
    results.addChar('pluginversion' + idname, str(
        qcctlib.qcversion))  # do not specify level, use default from config
    results.addChar('Anatomy', str(
        cs.anatomy))  # do not specify level, use default from config
    for di in dicominfo:
        results.addChar(di[0] + idname,
                        str(di[1])[:min(len(str(di[1])), 128)]
                        )  # do not specify level, use default from config
Example #11
0
def header_series(data, results, **kwargs):
    """
    Read selected dicomfields and write to IQC database

    Workflow:
        1. Read only headers
        2. Run tests
        3. Build xml output
    """
    info = 'qc'

    ## 1. read only headers
    dcmInfile, pixeldataIn, dicomMode = wadwrapper_lib.prepareInput(
        data.series_filelist[0], headers_only=True, logTag=logTag())

    ## 2. Run tests
    qclib = QCDDL_lib.DDLQC()

    ## Table or Wall? from distances and sensitivity; for well defined protocols to be defined in DESCRIPTION field
    cs = QCDDL_lib.DDLStruct(dcmInfile, None, dicomMode)
    cs.verbose = False  # do not produce detailed logging
    dicominfo = qclib.DICOMInfo(cs, info)
    idname = '_' + qclib.HorizontalOrVertical(cs)

    ## 3. Build xml output
    floatlist = []
    results.addChar('pluginversion' + idname, str(
        qclib.qcversion))  # do not specify level, use default from config
    for di in dicominfo:
        if di[0] in floatlist:
            results.addFloat(
                di[0] + idname,
                di[1])  # do not specify level, use default from config
        else:
            results.addChar(di[0] + idname,
                            str(di[1])[:min(len(str(di[1])), 128)]
                            )  # do not specify level, use default from config

    results.addChar(
        'room' + idname,
        cs.guessroom.name)  # do not specify level, use default from config
    results.addChar('stand' + idname, qclib.HorizontalOrVertical(
        cs))  # do not specify level, use default from config
Example #12
0
def qc_series(data, results, **kwargs):
    """
    QCDDL_UMCU checks:
        Horizontal uniformity
        LowContrast
        DynamicRange

    Workflow:
        2. Check data format
        3. Build and populate qcstructure
        4. Run tests
        5. Build xml output
        6. Build artefact picture thumbnail
    """
    ## 2. Check data format
    dcmInfile, pixeldataIn, dicomMode = wadwrapper_lib.prepareInput(
        data.series_filelist[0], headers_only=False, logTag=logTag())

    ## 3. Build and populate qcstructure
    remark = ""
    qclib = QCDDL_lib.DDLQC()
    cs = QCDDL_lib.DDLStruct(dcmInfile, pixeldataIn, dicomMode)
    cs.verbose = False  # do not produce detailed logging

    ## 4. Run tests
    error, msg = qclib.QC(cs)

    ## 5. Build xml output
    ## Struct now contains all the results and we can write these to the WAD IQ database
    stand = qclib.HorizontalOrVertical(cs)
    idname = '_' + stand

    labvals = qclib.ReportEntries(cs)
    tmpdict = {}
    for key, val in labvals:
        results.addFloat(key + str(idname), val, quantity=str(key))

    ## 6. Build artefact picture thumbnail
    filename = 'test' + idname + '.jpg'  # Use jpg if a thumbnail is desired

    qclib.saveAnnotatedImage(cs, filename)
    results.addObject('AnnotatedImage' + idname, filename)
Example #13
0
def ctheader_series(data,results,params):
    """
    Read selected dicomfields and write to IQC database

    Workflow:
        1. Run tests
        2. Build xml output
    """

    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

    error = qcctlib.HeadOrBody(cs)
    if(error == True or cs.anatomy == lit.stUnknown):
        raise ValueError("{} ERROR! Cannot determine Anatomy".format(logTag))

    result_dict = {}
    idname = ""
    if cs.anatomy == lit.stHead:
        idname = "_H"
    else:
        idname = "_B"
    # 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
    results.addChar('pluginversion'+idname, str(qcctlib.qcversion)) # do not specify level, use default from config
    results.addChar('Anatomy', str(cs.anatomy)) # do not specify level, use default from config
    for di in dicominfo:
        results.addChar(di[0]+idname, str(di[1])[:min(len(str(di[1])),128)]) # do not specify level, use default from config
Example #14
0
def mammoqc_series(data, results, **kwargs):
    """
    QCMammo_UMCU checks:
        Uniformity (5 rois) and SNR (hologic),
        DoseRatio (empirical/calculated from DICOM)
        Artefacts (spots, dead pixels)

    Workflow:
        2. Check data format
        3. Build and populate qcstructure
        4. Run tests
        5. Build xml output
        6. Build artefact picture thumbnail
    """
    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())
    ###    try:
    ###        dcmInfile = dicom.read_file(inputfile)
    ###        pixeldataIn = dcmInfile.pixel_array.transpose() # MODULE EXPECTS PYQTGRAPH DATA: X AND Y ARE TRANSPOSED!
    ###    except:
    ###        print logTag()+"could not open dicomfile!"
    ###        sys.exit()

    ## 3. Build and populate qcstructure
    remark = ""
    qcmammolib = QCMammo_lib.Mammo_QC()
    cs_mam = QCMammo_lib.MammoStruct(dcmInfile, pixeldataIn)
    cs_mam.verbose = False  # do not produce detailed logging
    if qcmammolib.NeedsCropping(cs_mam):
        cs_mam.expertmode = True
        qcmammolib.RestrictROI(cs_mam)
        remark = "CROPPED"

    ## 4. Run tests
    # Uniformity check
    error = qcmammolib.Uniformity(cs_mam)
    if error:
        remark += "/ERROR_UNIFORMITY"
    # Contrast L50
    error = qcmammolib.L50Contrast(cs_mam)  # doesn't do anything if not L50
    if error:
        remark += "/ERROR_L50CONTRAST"
    # Dose Ratio
    error = qcmammolib.DoseRatio(cs_mam)
    if error:
        remark += "/ERROR_DOSERATIO"
    # Artefacts
    error = qcmammolib.Artefacts(cs_mam)
    if error:
        remark += "/ERROR_ARTEFACTS"

    ## 5. Build xml output
    ## Struct now contains all the results and we can write these to the
    ## WAD IQ database
    includedlist = ["unif_pct", "snr_hol", "doseratio", "art_clusters", "expert_inoutoverin", "contrast_snr"]
    excludedlist = [
        "verbose",
        "dcmInfile",
        "pixeldataIn",
        "hasmadeplots",
        "means",
        "stdevs",
        "unif",
        "snr_hol",
        "unif_rois",
        "doseratio",
        "art_clusters",
        "art_image",
        "art_borderpx",
        "art_threshold",
        "art_rois",
        "expertmode",
        "expert_roipts",
        "expert_frac",
        "expert_inoutoverin",
        "filtername",
        "scannername",
        "contrast_rois",
        "contrast_mean",
        "contrast_sd",
    ]

    idname = "_" + cs_mam.filtername
    if "SUMPRES" in idname:
        idname = ""  # only one image

    results.addChar("NOTE" + idname, remark)

    for elem in cs_mam.__dict__:
        if elem in includedlist:
            newkeys = []
            newvals = []
            try:
                elemval = cs_mam.__dict__[elem]
                if "contrast_snr" in elem:  # array
                    for ix, snr in enumerate(elemval):
                        newkeys.append("CNR" + str(ix))
                        newvals.append(snr)
                elif "art_clusters" in elem:
                    newkeys.append(str(elem))
                    newvals.append(len(elemval))
                else:
                    newkeys.append(str(elem))
                    newvals.append(elemval)
            except:
                print logTag() + "error for", elem

            tmpdict = {}
            for key, val in zip(newkeys, newvals):
                results.addFloat(key + str(idname), val, quantity=str(key))

    ## 6. Build artefact picture thumbnail
    filename = "test" + idname + ".jpg"  # Use jpg if a thumbnail is desired

    # object_naam_pad = outputfile.replace('result.xml','test'+idname+'.jpg') # Use jpg if a thumbnail is desired
    qcmammolib.saveAnnotatedArtefactImage(cs_mam, filename)
    results.addObject("ArtefactImage" + idname, filename)
Example #15
0
def ctqc_series(data,results,params):
    """
    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
    """
    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

    ## 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))

    idname = ""
    if cs.anatomy == lit.stHead:
        idname = "_H"
    else:
        idname = "_B"
    # 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 = [
        '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'
        'skull_avg',
        'unif_slice',
        'unif_rois'
    ]
    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])
                elif 'shiftxypx' in elem:
                    newkeys.append('shiftxpx')
                    newvals.append(elemval[0])
                    newkeys.append('shiftypx')
                    newvals.append(elemval[1])
                else:
                    newkeys.append(str(elem))
                    newvals.append(elemval)
            except:
                print logTag()+"error for",elem
                elemval = -1.
            for key,val in zip(newkeys,newvals):
                results.addFloat(key+str(idname), val, quantity=str(key))

    ## Build thumbnail
    filename = 'test'+idname+'.jpg' # Use jpg if a thumbnail is desired
    if cs.dicomMode == wadwrapper_lib.stMode2D:
        scipy.misc.imsave(filename,cs.pixeldataIn.transpose()) # MODULE EXPECTS PYQTGRAPH DATA: X AND Y ARE TRANSPOSED!
    else:
        scipy.misc.imsave(filename,(cs.pixeldataIn[cs.unif_slice]).transpose()) # MODULE EXPECTS PYQTGRAPH DATA: X AND Y ARE TRANSPOSED!
    results.addObject('CTslice'+idname,filename)
Example #16
0
def ocr_series(data, results, params):
    """
    Use pyOCR which for OCR
    returns rect rois for plotting in overview
    """
    inputfile = data.series_filelist[0]  # give me a [filename]
    dcmInfile, pixeldataIn, dicomMode = wadwrapper_lib.prepareInput(
        inputfile, headers_only=False, logTag=logTag())

    rectrois = []
    error = False
    msg = ''

    # solve ocr params
    regions = {}
    for param in params:
        #'OCR_TissueIndex.xywh' = 'x;y;w;h'
        #'OCR_TissueIndex.prefix' = 'prefix'
        #'OCR_TissueIndex.suffix' = 'suffix'
        if param.tag.startswith('OCR_'):
            split = param.tag.find('.')  # ':' is illegal in xml names
            name = param.tag[:split]
            stuff = param.tag[split + 1:]
            if not name in regions:
                regions[name] = {'prefix': '', 'suffix': ''}
            if stuff == 'xywh':
                regions[name]['xywh'] = [int(p) for p in param.text.split(';')]
            elif stuff == 'prefix':
                regions[name]['prefix'] = param.text
            elif stuff == 'suffix':
                regions[name]['suffix'] = param.text
            elif stuff == 'type':
                regions[name]['type'] = param.text

    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(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:
            try:
                value = ocr_lib.txt2type(txt, region['type'], region['prefix'],
                                         region['suffix'])
                if region['type'] == 'float':
                    results.addFloat(name, value)
                elif region['type'] == 'string':
                    results.addChar(name, value)
                elif region['type'] == 'bool':
                    results.addBool(name, value)
            except:
                error = True
                msg += name + ' '
    return rectrois, error, msg
Example #17
0
def mrheader_series(data, results, **kwargs):
    """
    Read selected dicomfields and write to IQC database

    Workflow:
        1. Run tests
        2. Build xml output
    """
    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),
        ]

    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:
            print(logTag() + "[mrheader]: ", piqt,
                  "not available for given image")
            sys.exit()

        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
    # plugionversion is newly added in for this plugin since pywad2
    results.addChar('pluginversion' + idname, str(
        qclib.qcversion))  # do not specify level, use default from config
    for key, val in reportkeyvals:
        val2 = "".join([x if ord(x) < 128 else '?'
                        for x in val])  #ignore non-ascii
        results.addChar(key,
                        str(val2)[:min(len(str(val)), 128)]
                        )  # do not specify level, use default from config
Example #18
0
def mammoqc_series(data, results, **kwargs):
    """
    QCMammo_UMCU checks:
        Uniformity (5 rois) and SNR (hologic),
        DoseRatio (empirical/calculated from DICOM)
        Artefacts (spots, dead pixels)

    Workflow:
        2. Check data format
        3. Build and populate qcstructure
        4. Run tests
        5. Build xml output
        6. Build artefact picture thumbnail
    """
    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())

    ## 3. Build and populate qcstructure
    remark = ""
    qcmammolib = QCMammo_lib.Mammo_QC()
    cs_mam = QCMammo_lib.MammoStruct(dcmInfile, pixeldataIn)
    cs_mam.verbose = False  # do not produce detailed logging
    if qcmammolib.NeedsCropping(cs_mam):
        cs_mam.expertmode = True
        qcmammolib.RestrictROI(cs_mam)
        remark = "CROPPED"

    ## 4. Run tests
    # Uniformity check
    error = qcmammolib.Uniformity(cs_mam)
    if error:
        remark += "/ERROR_UNIFORMITY"
    # Contrast L50
    error = qcmammolib.L50Contrast(cs_mam)  # doesn't do anything if not L50
    if error:
        remark += "/ERROR_L50CONTRAST"
    # Dose Ratio
    error = qcmammolib.DoseRatio(cs_mam)
    if error:
        remark += "/ERROR_DOSERATIO"
    # Artefacts
    error = qcmammolib.Artefacts(cs_mam)
    if error:
        remark += "/ERROR_ARTEFACTS"

    ## 5. Build xml output
    ## Struct now contains all the results and we can write these to the
    ## WAD IQ database
    includedlist = [
        'unif_pct', 'snr_hol', 'doseratio', 'art_clusters',
        'expert_inoutoverin', 'contrast_snr'
    ]
    excludedlist = [
        'verbose', 'dcmInfile', 'pixeldataIn', 'hasmadeplots', 'means',
        'stdevs', 'unif', 'snr_hol', 'unif_rois', 'doseratio', 'art_clusters',
        'art_image', 'art_borderpx', 'art_threshold', 'art_rois', 'expertmode',
        'expert_roipts', 'expert_frac', 'expert_inoutoverin', 'filtername',
        'scannername', 'contrast_rois', 'contrast_mean', 'contrast_sd'
    ]

    idname = '_' + cs_mam.filtername
    if "SUMPRES" in idname:
        idname = ""  # only one image

    results.addChar('NOTE' + idname, remark)

    for elem in cs_mam.__dict__:
        if elem in includedlist:
            newkeys = []
            newvals = []
            try:
                elemval = cs_mam.__dict__[elem]
                if 'contrast_snr' in elem:  # array
                    for ix, snr in enumerate(elemval):
                        newkeys.append('CNR' + str(ix))
                        newvals.append(snr)
                elif 'art_clusters' in elem:
                    newkeys.append(str(elem))
                    newvals.append(len(elemval))
                else:
                    newkeys.append(str(elem))
                    newvals.append(elemval)
            except:
                print(logTag() + "error for", elem)

            tmpdict = {}
            for key, val in zip(newkeys, newvals):
                results.addFloat(key + str(idname), val, quantity=str(key))

    ## 6. Build artefact picture thumbnail
    filename = 'test' + idname + '.jpg'  # Use jpg if a thumbnail is desired

    #object_naam_pad = outputfile.replace('result.xml','test'+idname+'.jpg') # Use jpg if a thumbnail is desired
    qcmammolib.saveAnnotatedArtefactImage(cs_mam, filename)
    results.addObject('ArtefactImage' + idname, filename)
Example #19
0
def ctqc_series(data, results, params):
    """
    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
    """
    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

    ## 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))

    idname = ""
    if cs.anatomy == lit.stHead:
        idname = "_H"
    else:
        idname = "_B"
    # 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 = [
        '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'
        'skull_avg', 'unif_slice', 'unif_rois'
    ]
    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])
                elif 'shiftxypx' in elem:
                    newkeys.append('shiftxpx')
                    newvals.append(elemval[0])
                    newkeys.append('shiftypx')
                    newvals.append(elemval[1])
                else:
                    newkeys.append(str(elem))
                    newvals.append(elemval)
            except:
                print logTag() + "error for", elem
                elemval = -1.
            for key, val in zip(newkeys, newvals):
                results.addFloat(key + str(idname), val, quantity=str(key))

    ## Build thumbnail
    filename = 'test' + idname + '.jpg'  # Use jpg if a thumbnail is desired
    if cs.dicomMode == wadwrapper_lib.stMode2D:
        scipy.misc.imsave(filename, cs.pixeldataIn.transpose(
        ))  # MODULE EXPECTS PYQTGRAPH DATA: X AND Y ARE TRANSPOSED!
    else:
        scipy.misc.imsave(filename, (cs.pixeldataIn[cs.unif_slice]).transpose(
        ))  # MODULE EXPECTS PYQTGRAPH DATA: X AND Y ARE TRANSPOSED!
    results.addObject('CTslice' + idname, filename)
Example #20
0
def mrheader_series(data,results,**kwargs):
    """
    Read selected dicomfields and write to IQC database

    Workflow:
        1. Run tests
        2. Build xml output
    """
    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),
        ]

    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:
            print logTag()+"[mrheader]: ", piqt, "not available for given image"
            sys.exit()

        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
    # plugionversion is newly added in for this plugin since pywad2
    results.addChar('pluginversion'+idname, str(qclib.qcversion)) # do not specify level, use default from config
    for key,val in reportkeyvals:
        val2 = "".join([x if ord(x) < 128 else '?' for x in val]) #ignore non-ascii 
        results.addChar(key, str(val2)[:min(len(str(val)),128)]) # do not specify level, use default from config
Example #21
0
def mrqc_series(data, results, **kwargs):
    """
    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
    """
    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),
        ]

    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"

        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)
                results.addObject('FFU' + '_' + idname, 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:
            error = qclib.SNR(cs)
            if not error:
                idname = "_" + setname + make_idname(qclib, cs, cs.snr_slice)
                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]))
                ## Build thumbnail
                filename = 'LIN' + idname + '.jpg'  # Use jpg if a thumbnail is desired
                qclib.saveResultImage(cs, 'LIN', filename)
                results.addObject('LIN' + '_' + idname, 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)
                results.addObject('SLP' + '_' + idname, 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)
                results.addObject('MTF' + '_' + idname, filename)

        if error:
            raise ValueError("{} ERROR! processing error in {} {}".format(
                logTag(), piqt, doTest))

    for key, val in reportkeyvals:
        results.addFloat(key, val, quantity=str(key.split('_QA')[0]))
Example #22
0
def mrqc_series(data,results,**kwargs):
    """
    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
    """
    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),
        ]

    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"

        cs = QCMR_lib.PiQT_Struct(dcmInfile,pixeldataIn,dicomMode,piqt)
        cs.verbose = None

        if "SNR" in doTest:
            error = qclib.SNR(cs)
            if not error:
                idname = "_"+setname+make_idname(qclib,cs,cs.snr_slice)
                reportkeyvals.append( ("S/N (B)"+idname,cs.snr_SNB) )

        if "ArtifactLevel" in doTest:
            error = qclib.ArtifactLevel(cs)
            if not error:
                idname = "_"+setname+make_idname(qclib,cs,cs.snr_slice)
                reportkeyvals.append( ("Art_Level"+idname,cs.artefact_ArtLevel) )

        if "FloodFieldUniformity" in doTest:
            error = qclib.FloodFieldUniformity(cs)
            if not error:
                import numpy as np
                idname = "_"+setname+make_idname(qclib,cs,cs.snr_slice)
                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 = 'test'+idname+'.jpg' # Use jpg if a thumbnail is desired
                scipy.misc.imsave(filename,cs.lastimage.transpose()) # MODULE EXPECTS PYQTGRAPH DATA: X AND Y ARE TRANSPOSED!
                results.addObject('FFU'+'_'+idname,filename)

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

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

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

        if error:
            raise ValueError("{} ERROR! processing error in {} {}".format(logTag,piqt,doTest))

    for key,val in reportkeyvals:
        results.addFloat(key, val, quantity=str(key.split('_QA')[0]))