예제 #1
0
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)]) 
예제 #2
0
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))
예제 #3
0
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)
예제 #4
0
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)
예제 #5
0
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)
예제 #6
0
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)])
예제 #7
0
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)
예제 #8
0
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
예제 #9
0
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) 
예제 #10
0
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
예제 #11
0
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
예제 #12
0
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
예제 #13
0
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)