wadqc / WAD_Python

WAD analyse modules in Python
GNU General Public License v3.0
2 stars 3 forks source link

implementing my own module into the WAD software #11

Open TimothyRepkes opened 7 years ago

TimothyRepkes commented 7 years ago

Hello,

I am writing a Python script for the CT QC Light procedure of the hospital I am performing my internship at.

I used the Bucky_BEAM_Phantom as a blueprint for my own (https://github.com/wadqc/WAD_Python/blob/master/Plugins/Bucky/Bucky_BEAM/Bucky_BEAM_Phantom.py). Now i have come to the point where i need to generate an output of my results and the blueprint leaves me clueless.

def print_beam_output(dcmfile,results):
     '''Function receives a dicom file and results class object. The fuction calls the function calculate_beam_uniformity to calculate mean,std and snr and subsequently writes out the received results into the results class object.
     '''

     try:
          detectorname = str(dcmfile.SeriesDescription)
     except:
         detectorname = 'UnknownDetector'

     calc_output = calculate_beam_uniformity(dcmfile.pixel_array)

     results.addFloat('Gemiddelde ROI SNR %s'%detectorname,calc_output['avg']['snr'],level=1)
     results.addFloat('Gemiddelde ROI mean %s'%detectorname,calc_output['avg']['mean'],level=1)
     results.addFloat('Gemiddelde stdev %s'%detectorname,calc_output['avg']['std'],level=1)
     results.addFloat('Gemiddelde ROI1 %s'%detectorname,calc_output['roi1']['mean'],level=2)
     results.addFloat('Gemiddelde ROI2 %s'%detectorname,calc_output['roi2']['mean'],level=2)
     results.addFloat('Gemiddelde ROI3 %s'%detectorname,calc_output['roi3']['mean'],level=2)    
     results.addFloat('Gemiddelde ROI4 %s'%detectorname,calc_output['roi4']['mean'],level=2)

     results.addFloat('stdev ROI1 %s'%detectorname,calc_output['roi1']['std'],level=2 )
     results.addFloat('stdev ROI2 %s'%detectorname,calc_output['roi2']['std'],level=2 )
     results.addFloat('stdev ROI3 %s'%detectorname,calc_output['roi3']['std'],level=2 )    
     results.addFloat('stdev ROI4 %s'%detectorname,calc_output['roi4']['std'],level=2 )

     print('CWD:',os.getcwd())
     fig = plt.figure()
     ax = fig.add_subplot(111)
     plt.title("QC bucky")
     img = calc_output['image']
     middlex, middley = zip(*calc_output['middle'])
     plt.imshow(img)
     plt.scatter(middlex,middley)
     plt.savefig('%s.png'%detectorname.replace(" ",""))
     results.addObject('QCbeeld','%s.png'%detectorname.replace(" ",""))
     print('CWD',os.getcwd())     

The second input is "results" i have no clue what format it should be but the results are added to this. I found out it was part of the "pluginresults" script but it isn't imported as a lib or anything in this script. The next function in this script however supplies the "results". But it has it as an input aswel. So it still isn't defined.

def QC_bucky_run(data, results, **kwargs):
     '''Function extracts instances from data object. From the params section in the config XML file the filter for relevant bucky files is determined. For each relevant file the print_beam_output function is called.
     '''

     paramdict = kwargs.get('params', None) #read out all the parameter tags from the config_xml

     select_instance_lst = [] #create a list of all buckydata to be processed
     for child in paramdict:
          print(child, type(child), child.tag, type(child.tag))
          if 'bucky' in child.tag:
               select_instance_lst.append(child.attrib) 

     for crit in select_instance_lst:
          tmpfile = data.getInstanceByTags(crit)
          for elem in tmpfile:
               try:
                    print_beam_output(elem,results)
               except:
                    print("Warning, failed %s "%crit)

More imputs making it inimitable for me. but the last part of code in the scripts defines the "results" input with.

if __name__ == "__main__":
    from pyWAD import PluginTools

    series_lst = [[],[]] #to test from the command line add test files from a series here
    result_dir = "./"

    data = PluginData()
    results = PluginResults()
    QC_bucky_run()

    for result in tools.results:
        print result

but i am clue less on how to apply this to my file which i have been trying to expend with trial and error and manually applying the dicom files. my code goes like:

def CT_qclight_uniformity (dicomfiles):

    ds = getting_dataset (dicomfiles)

# This try is for previous code. it wil only run when the dicom file applies to my demands.
    try:
        # De pixel data van de dataset (ds) wordt gekoppeld aan de Refference Dataset (RefDs)
        RefDs = pds._getPixelDataFromDataset(ds)

        # Defining middle
        xdim ,ydim = np.shape(RefDs)
        middle = [(xdim /2,ydim/2)]

        # ROI middle
        xc = int(middle[0][0])
        yc = int(middle[0][1])

        # the deflection
        widthx = int(xdim/32)
        widthy = int(xdim/32)
        roidim= (2*widthx)*(2*widthy)

        # Just 1 roi for clean code to understand my problem
        roic = np.zeros(np.shape(RefDs))
        roic[xc - widthx : xc +widthx, yc - widthy:yc + widthy] = 1
        roic = ma.make_mask(roic)

        # An empty dict for the results
        results = {}

        tmpc = ma.array(RefDs,mask=1-roic)
        results['roic']={'mean':np.mean(tmpc),'std':np.std(tmpc)} 
        results['middle'] = middle
        results['image'] = RefDs

    except UnboundLocalError:
        print "The dicom file is not correct for this module."
    return results

#results = pluginresults.PluginResults(3)
def print_uniformity(dicomfiles):
#results = 1

    #PluginResults = pluginresults.PluginResults(results)
    #results = PluginResults()
    calc_output = CT_qclight_uniformity(dicomfiles)
    ds = getting_dataset(dicomfiles)
    try:
        detectorname = str(ds.SeriesDescription)
    except:
        detectorname = 'UnknownDetector'

    #print detectorname

    #pluginresults.PluginResults.addFloat('gemiddlede' , 2)
    #results.addFloat('Gemiddelde ROI mean %s'%detectorname,calc_output['avg']['mean'],level=1)
    results.addFloat('Gemiddelde ROI1 %s'%detectorname,calc_output['roi1']['mean'],level=2)

    print('CWD:',os.getcwd())
    fig = plt.figure()
    ax = fig.add_subplot(111)
    plt.title("QC bucky")
    img = calc_output['image']
    middlex, middley = zip(*calc_output['middle'])
    plt.imshow(img)
    plt.scatter(middlex,middley)
    plt.savefig('%s.png'%detectorname.replace(" ",""))
    results.addObject('QCbeeld','%s.png'%detectorname.replace(" ",""))
    print('CWD',os.getcwd())

i removed the other ROI's to make the code cleaner

#results = pluginresults.PluginResults(3)
def print_uniformity(dicomfiles, results):
#results = 1

    #PluginResults = pluginresults.PluginResults(results)
    #results = PluginResults()

The # in this part are things i tried to make de code run but to no succes. if i look at the Bucky to understand it my last "def" needs results as input but the error i get is "... is not a integer" (... = string or dict or anything i tried what is not an integer). so i just run it 1 or 3 because it is an integer.

Can anyone help me trying to get this right. How to understand to code of the Bucky to apply this on my script. If I understand how it works I can put it in my recommendations for the following internships who will be making modules to automate the QC measurements. The WAD QC is a good initiative but currently lacks some clarifications on how certain steps work.

wadqc commented 7 years ago

The plugin is used as part of a QC framework. The input and output file formats are described in https://github.com/wadqc/WAD_Documentatie/wiki/Specificaties-analysemodule (sorry this is in Dutch but the XML code is, well, XML. This wiki contains a lot more info, maybe you can try to figure out the general concept from it. Again this is in Dutch. The next version will me more international. Summary: there is a DICOM frontend (dcm4chee), three WAD services (collector, selector, processor) acting around a database. The selector produces the input file, the processor calls the worker (analysis module, e.g. pywadplugin) and imports its output file into the database.

Actually the bucky analysis code you refer to is supposed to be called by the processor service through https://github.com/wadqc/WAD_Python/blob/master/pywadplugin.py

The input file referes to a configuration file, there is an example here: https://github.com/wadqc/WAD_Python/blob/master/Testing/Bucky/Bucky_BEAM/series/config_BEAM.xml

Hope this helps!

asch99 commented 7 years ago

Also, there already is a plugin for QC-Light CT analysis: https://github.com/wadqc/WAD_Python/tree/master/Plugins/CT/CT_Philips_QuickIQ