Explorar el Código

Adding irAEMMBrowser

Andrej Studen @ VBOX hace 4 años
padre
commit
67ef22559c
Se han modificado 1 ficheros con 229 adiciones y 0 borrados
  1. 229 0
      slicerModule/iraemmBrowser.py

+ 229 - 0
slicerModule/iraemmBrowser.py

@@ -0,0 +1,229 @@
+import os
+import unittest
+from __main__ import vtk, qt, ctk, slicer
+from slicer.ScriptedLoadableModule import *
+import slicerNetwork
+import loadDicom
+import json
+
+#
+# labkeySlicerPythonExtension
+#
+
+class iraemmBrowser(ScriptedLoadableModule):
+  """Uses ScriptedLoadableModule base class, available at:
+  https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
+  """
+
+  def __init__(self, parent):
+    ScriptedLoadableModule.__init__(self, parent)
+    self.parent.title = "irAEMM Browser" # TODO make this more human readable by adding spaces
+    self.parent.categories = ["LabKey"]
+    self.parent.dependencies = []
+    self.parent.contributors = ["Andrej Studen (UL/FMF)"] # replace with "Firstname Lastname (Organization)"
+    self.parent.helpText = """
+    Interface to irAEMM files in LabKey
+    """
+    self.parent.acknowledgementText = """
+    Developed within the medical physics research programme of the Slovenian research agency.
+    """ # replace with organization, grant and thanks.
+
+#
+# labkeySlicerPythonExtensionWidget
+#
+
+class iraemmBrowserWidget(ScriptedLoadableModuleWidget):
+  """Uses ScriptedLoadableModuleWidget base class, available at:
+  https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
+  """
+
+  def setup(self):
+    print("Setting up iraemmBrowserWidget")
+    ScriptedLoadableModuleWidget.setup(self)
+    # Instantiate and connect widgets ...
+    self.network=slicerNetwork.labkeyURIHandler()
+
+    fconfig=os.path.join(os.path.expanduser('~'),'.labkey','onko-nix.json')
+    self.network.parseConfig(fconfig)
+    self.network.initRemote()
+    self.project="iPNUMMretro/Study"
+    self.dataset="Imaging1"
+
+
+    self.logic=iraemmBrowserLogic(self)
+    
+
+    ds=self.network.filterDataset(self.project,self.dataset,[])
+    ids=[row['PatientId'] for row in ds['rows']]
+    ids=list(set(ids))
+
+    
+    #
+    # Parameters Area
+    #
+    connectionCollapsibleButton = ctk.ctkCollapsibleButton()
+    connectionCollapsibleButton.text = "Patients"
+    self.layout.addWidget(connectionCollapsibleButton)
+
+    connectionFormLayout = qt.QFormLayout(connectionCollapsibleButton)
+
+
+    self.patientList=qt.QComboBox()
+    for id in ids:
+        self.patientList.addItem(id)
+    self.patientList.currentIndexChanged.connect(self.onPatientListChanged)
+    connectionFormLayout.addRow("Patient:",self.patientList)
+
+    self.visitList=qt.QComboBox()
+    self.visitList.currentIndexChanged.connect(self.onVisitListChanged)
+    connectionFormLayout.addRow("Visit:",self.visitList)
+
+    self.ctCode=qt.QLabel("ctCode")
+    connectionFormLayout.addRow("CT:",self.ctCode)
+
+    self.petCode=qt.QLabel("petCode")
+    connectionFormLayout.addRow("PET:",self.petCode)
+
+    self.patientLoad=qt.QPushButton("Load")
+    self.patientLoad.clicked.connect(self.onPatientLoadButtonClicked)
+    connectionFormLayout.addRow("Load patient",self.patientLoad)
+
+    self.keepCached=qt.QCheckBox("keep Cached")
+    self.keepCached.setChecked(1)
+    connectionFormLayout.addRow("Keep cached",self.keepCached)
+    
+    #set to a defined state
+    self.onPatientListChanged(0)
+
+  def onPatientListChanged(self,i):
+      idFilter={'variable':'PatientId','value':self.patientList.currentText,'oper':'eq'}
+      ds=self.network.filterDataset(self.project,self.dataset, [idFilter])
+      seq=[int(row['SequenceNum']) for row in ds['rows']]
+      self.visitList.clear()  
+            
+      for s in seq:
+          self.visitList.addItem("Visit "+str(s))
+      self.onVisitListChanged(0)
+
+  def onVisitListChanged(self,i):
+      try:
+        s=self.visitList.currentText.split(' ')[1]
+      except IndexError:
+        return
+      print("Visit: Selected item: {}->{}".format(i,s))
+      idFilter={'variable':'PatientId','value':self.patientList.currentText,'oper':'eq'}
+      sFilter={'variable':'SequenceNum','value':s,'oper':'eq'}
+      ds=self.network.filterDataset(self.project,self.dataset,[idFilter,sFilter])
+      if not len(ds['rows'])==1:
+          print("Found incorrect number {} of matches for [{}]/[{}]".format(len(ds['rows']),\
+                  self.patientList.currentText,s))
+      row=ds['rows'][0]
+
+      #copy row properties for data access
+      self.currentRow=row
+      self.petCode.setText(row['petResampled'])
+      self.ctCode.setText(row['ctResampled'])
+
+
+  def onPatientLoadButtonClicked(self):
+      print("Load")
+      #delegate loading to logic
+      #try:
+      self.logic.loadImage(self.currentRow,self.keepCached.isChecked())
+      #except AttributeError:
+      #    print("Missing current row")
+      #    return
+
+  def cleanup(self):
+    pass
+
+#
+# irAEMMBrowserLogic
+#
+
+class iraemmBrowserLogic(ScriptedLoadableModuleLogic):
+  """This class should implement all the actual
+  computation done by your module.  The interface
+  should be such that other python code can import
+  this class and make use of the functionality without
+  requiring an instance of the Widget.
+  Uses ScriptedLoadableModuleLogic base class, available at:
+  https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
+  """
+  def __init__(self,parent=None):
+      ScriptedLoadableModuleLogic.__init__(self, parent)
+      if not parent==None:
+          #assume parent has the network set up
+          self.parent=parent
+          self.net=parent.network
+          self.project=parent.project
+
+  def setLabkeyInterface(self,net):
+      #additional way of setting the labkey network interface 
+      #if no parent was provided in logic initialization (stand-alone mode)
+      self.net=net
+
+  def setLabkeyProject(self,project):
+      self.project=project
+
+  def loadImage(self,row,keepCached):
+      
+      
+      #fields={'ctResampled':True,'petResampled':False}
+      fields=['ctResampled','petResampled']
+
+      relativePaths={x:self.project+'/@files/preprocessedImages/'\
+             +row['patientCode']+'/'+row['visitCode']+'/'+row[x]\
+             for x in fields}
+
+      volumeNode={}
+      for f in relativePaths:
+          p=relativePaths[f]
+          labkeyPath=self.net.GetLabkeyPathFromRelativePath(p)
+          rp=self.net.head(labkeyPath)
+          if not rp.code==200:
+              print("Failed to get {}".format(labkeyPath))
+              continue
+
+          #pushes it to background
+          volumeNode[f]=self.net.loadNode(p,'VolumeFile',returnNode=True,keepCached=keepCached)
+          
+      slicer.util.setSliceViewerLayers(background=volumeNode['ctResampled'],\
+          foreground=volumeNode['petResampled'],foregroundOpacity=0.5,fit=True)
+
+
+class irAEMMBrowserTest(ScriptedLoadableModuleTest):
+  """
+  This is the test case for your scripted module.
+  Uses ScriptedLoadableModuleTest base class, available at:
+  https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
+  """
+
+  def setUp(self):
+    """ Do whatever is needed to reset the state - typically a scene clear will be enough.
+    """
+    slicer.mrmlScene.Clear(0)
+
+  def runTest(self):
+    """Run as few or as many tests as needed here.
+    """
+    self.setUp()
+    self.test_irAEMMBrowser()
+
+  def test_irAEMMBrowser(self):
+    """ Ideally you should have several levels of tests.  At the lowest level
+    tests sould exercise the functionality of the logic with different inputs
+    (both valid and invalid).  At higher levels your tests should emulate the
+    way the user would interact with your code and confirm that it still works
+    the way you intended.
+    One of the most important features of the tests is that it should alert other
+    developers when their changes will have an impact on the behavior of your
+    module.  For example, if a developer removes a feature that you depend on,
+    your test should break so they know that the feature is needed.
+    """
+
+    self.delayDisplay("Starting the test")
+    #
+    # first, get some data
+    #
+