Skip to content

Commit 3c22789

Browse files
author
idhamari
committed
update to Slicer version 5.5.0
1 parent 96683fc commit 3c22789

3 files changed

Lines changed: 109 additions & 130 deletions

File tree

CochleaReg/CochleaReg.py

Lines changed: 32 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
#======================================================================================
22
# 3D Slicer [1] plugin that uses elastix toolbox [2] Plugin for Automatic Cochlea #
3-
# Image Registration (ACIR) [3]. More info can be found at [4] #
3+
# Image Registration (ACIR) [3,4]. More info can be found at [5] #
44
# Sample cochlea datasets can be downloaded using Slicer Datastore module #
55
# #
66
# Contributers: #
7-
# - Ibraheem Al-Dhamari, idhamari@uni-koblenz.de #
7+
# - Ibraheem Al-Dhamari, ia@idhamari.com #
88
# [1] https://www.slicer.org #
99
# [2] http://elastix.isi.uu.nl #
1010
# [3] Al-Dhamari et al., (2017): ACIR: automatic cochlea image registration. #
1111
# In: Proceedings SPIE Medical Imaging 2017: Image Processing;. SPIE. Bd. #
1212
# 10133. S. 10133p1-10133p5 #
13-
# #
13+
# [4] Al-Dhamari et al, Automatic intra-subject registration and fusion of #
14+
# multimodal cochlea 3D clinical images. 2022, PLOS ONE, 17(3) #
15+
# [5] https://github.com/MedicalImageAnalysisTutorials/SlicerCochlea #
1416
#-------------------------------------------------------------------------------------#
15-
# Slicer 5.0.3 #
16-
# Updated: 6.8.2022 #
17+
# Slicer 5.4.0 #
18+
# Updated: 18.11.2023 #
1719
#======================================================================================
1820

1921
# Non Slicer libs
@@ -42,7 +44,7 @@
4244
# img : ITK image
4345
# imgNode : Slicer Node
4446
# imgName : Filename without the path and without extension
45-
# imgPath : wholePath + Filename and extension
47+
# imgPath : complete path + Filename and extension
4648

4749

4850
#===================================================================
@@ -56,10 +58,8 @@ def __init__(self, parent):
5658
parent.dependencies = []
5759
parent.contributors = ["Ibraheem Al-Dhamari"]
5860
parent.helpText = " This module uses ACIR method to auatomatically register cochlea images"
59-
parent.acknowledgementText = " This work is sponsored by Cochlear as part of COMBS project "
61+
parent.acknowledgementText = " This work is sponsored partly by Cochlear as part of COMBS project."
6062
self.parent = parent
61-
#end def init
62-
#end class CochleaReg
6363

6464
#===================================================================
6565
# Main Widget
@@ -183,8 +183,7 @@ def onInputFiducialBtnClick(self, volumeType):
183183
for f in nodes:
184184
if (f.GetName() == "_CochleaLocation") :
185185
slicer.mrmlScene.RemoveNode(f)
186-
#endif
187-
#endfor
186+
188187
# Create Fiducial Node for the cochlea location in both images
189188
if (volumeType=="F"):
190189
print(" ..... getting cochlea location in the fixed image")
@@ -197,9 +196,6 @@ def onInputFiducialBtnClick(self, volumeType):
197196
self.vsc.locateItem(self.movingSelectorCoBx.currentNode(), self.movingPointEdt,2, 0)
198197
self.movingFiducialNode= self.vsc.inputFiducialNodes[2]
199198
self.movingFiducialBtn.setStyleSheet("QPushButton{ background-color: DarkSeaGreen }")
200-
#endif
201-
#enddef
202-
203199

204200
# An option to control results displaying
205201
def OnColorsChkBoxChange(self):
@@ -224,12 +220,10 @@ def onApplyBtnClick(self):
224220
self.runBtn.setText("Run")
225221
self.runBtn.setStyleSheet("QPushButton{ background-color: DarkSeaGreen }")
226222
slicer.app.processEvents()
227-
#enddef
228-
223+
229224
def cleanup(self):
230225
pass
231-
#enddef
232-
226+
233227
#===================================================================
234228
# Logic
235229
#===================================================================
@@ -273,7 +267,7 @@ def run(self, fixedVolumeNode, fixedFiducialNode, movingVolumeNode, movingFiduci
273267
if np.sum(fixedPoint)== 0 :
274268
print("Error: select cochlea fixed point")
275269
return -1
276-
#endif
270+
277271
fnm = os.path.join(self.vsc.vtVars['outputPath'] , fixedVolumeNode.GetName()+"_F_Cochlea_Pos.fcsv")
278272
sR = slicer.util.saveNode(fixedFiducialNode, fnm )
279273

@@ -286,7 +280,7 @@ def run(self, fixedVolumeNode, fixedFiducialNode, movingVolumeNode, movingFiduci
286280
if np.sum(fixedPoint)== 0 :
287281
print("Error: select cochlea moving point")
288282
return -1
289-
#endif
283+
290284
fnm = os.path.join(self.vsc.vtVars['outputPath'] , movingVolumeNode.GetName()+"_M_Cochlea_Pos.fcsv")
291285
sR = slicer.util.saveNode(movingFiducialNode, fnm )
292286

@@ -300,18 +294,17 @@ def run(self, fixedVolumeNode, fixedFiducialNode, movingVolumeNode, movingFiduci
300294
#qt.QMessageBox.critical(slicer.util.mainWindow(),'SlicerCochleaRegistration', 'Cochlea locations are missing')
301295
print("Error: select cochlea points in fixed and moving images")
302296
return False
303-
#endif
304297

305298
fixedPointT = self.vsc.v2t(fixedPoint)
306299
movingPointT = self.vsc.v2t(movingPoint)
307300

308301
print("=================== Cropping =====================")
309302
self.vsc.vtVars['fixedCropPath'] = self.vsc.runCropping(fixedVolumeNode, fixedPointT,self.vsc.vtVars['croppingLength'], self.vsc.vtVars['RSxyz'], self.vsc.vtVars['hrChk'],0)
310-
[success, croppedFixedNode] = slicer.util.loadVolume(self.vsc.vtVars['fixedCropPath'])
303+
croppedFixedNode = slicer.util.loadVolume(self.vsc.vtVars['fixedCropPath'])
311304
croppedFixedNode.SetName(fixedVolumeNode.GetName()+"_F_Crop")
312305

313306
self.vsc.vtVars['movingCropPath'] = self.vsc.runCropping(movingVolumeNode, movingPointT,self.vsc.vtVars['croppingLength'], self.vsc.vtVars['RSxyz'], self.vsc.vtVars['hrChk'],0)
314-
[success, croppedMovingNode] = slicer.util.loadVolume(self.vsc.vtVars['movingCropPath'])
307+
croppedMovingNode = slicer.util.loadVolume(self.vsc.vtVars['movingCropPath'])
315308
croppedMovingNode.SetName(movingVolumeNode.GetName()+"_M_Crop")
316309
print ("************ Register cropped moving image to cropped fixed image **********************")
317310
cTI = self.vsc.runElastix(self.vsc.vtVars['elastixBinPath'],self.vsc.vtVars['fixedCropPath'], self.vsc.vtVars['movingCropPath'], self.vsc.vtVars['outputPath'], self.vsc.vtVars['parsPath'], self.vsc.vtVars['noOutput'], "336")
@@ -322,57 +315,55 @@ def run(self, fixedVolumeNode, fixedFiducialNode, movingVolumeNode, movingFiduci
322315
os.rename(resOldDefPath,resDefPath)
323316

324317
print ("************ Load deformation field Transform **********************")
325-
[success, vtTransformNode] = slicer.util.loadTransform(resDefPath)
318+
vtTransformNode = slicer.util.loadTransform(resDefPath)
326319
vtTransformNode.SetName(transNodeName)
327320
print ("************ Transform The Original Moving image **********************")
328321
movingVolumeNode.SetAndObserveTransformNodeID(vtTransformNode.GetID())
329322
#export seg to lbl then export back with input image as reference
330323
slicer.vtkSlicerTransformLogic().hardenTransform(movingVolumeNode) # apply the transform
331324
fnm = os.path.join(self.vsc.vtVars['outputPath'] , movingVolumeNode.GetName()+"_Registered.nrrd")
332325
sR = slicer.util.saveNode(movingVolumeNode, fnm )
333-
[success, registeredMovingVolumeNode] = slicer.util.loadVolume(fnm)
326+
registeredMovingVolumeNode = slicer.util.loadVolume(fnm)
334327
registeredMovingVolumeNode.SetName(movingVolumeNode.GetName()+"_Registered")
335328
#remove the tempnode and load the original
336329
slicer.mrmlScene.RemoveNode(movingVolumeNode)
337-
[success, movingVolumeNode] = slicer.util.loadVolume(movingPath)
330+
movingVolumeNode = slicer.util.loadVolume(movingPath)
338331
movingVolumeNode.SetName(os.path.splitext(os.path.basename(movingVolumeNode.GetStorageNode().GetFileName()))[0])
339332
if (cTI==0) and (cTR==0):
340333
print("No error is reported during registeration ...")
341334
else:
342335
print("error happened during registration ")
343-
#endif
344336

345337
#Remove temporary files and nodes:
346338
self.vsc.removeTmpsFiles()
347339
print("================= Cochlea registration is complete =====================")
348340
logging.info('Processing completed')
349341

350342
return registeredMovingVolumeNode
351-
#enddef
352343

353344
#===================================================================
354345
# Test
355346
#===================================================================
356347
class CochleaRegTest(ScriptedLoadableModuleTest):
357348
def setUp(self):
358349
slicer.mrmlScene.Clear(0)
359-
#enddef
350+
360351

361352
def runTest(self):
362353
self.setUp()
363354
self.testSlicerCochleaRegistration()
364-
#enddef
355+
365356
def testSlicerCochleaRegistration(self, fixedImgPath=None, fixedPoint=None, movingImgPath=None, movingPoint=None):
366357

367358
self.delayDisplay("Starting testSlicerCochleaRegistration test")
368359
self.stm=time.time()
369360

370361
if fixedPoint is None:
371362
fixedPoint = [220,242,78]
372-
#endif
363+
373364
if movingPoint is None:
374365
movingPoint = [196,217,93]
375-
#endif
366+
376367
nodeNames='P100001_DV_L_a'
377368
fileNames='P100001_DV_L_a.nrrd'
378369
urisUniKo = "https://cloud.uni-koblenz-landau.de/s/EwQiQidXqTcGySB/download"
@@ -385,10 +376,11 @@ def testSlicerCochleaRegistration(self, fixedImgPath=None, fixedPoint=None, movi
385376
slicer.mrmlScene.RemoveNode(tmpVolumeNode)
386377
else:
387378
nodeNames = os.path.splitext(os.path.basename(fixedImgPath))[0]
388-
#endif
389-
[success, fixedVolumeNode] = slicer.util.loadVolume(fixedImgPath, returnNode=True)
379+
380+
print("fixedImgPath : ",fixedImgPath)
381+
fixedVolumeNode = slicer.util.loadVolume(fixedImgPath )
390382
fixedVolumeNode.SetName(nodeNames)
391-
#endifelse
383+
392384
nodeNames='P100001_DV_L_b'
393385
fileNames='P100001_DV_L_b.nrrd'
394386
urisUniKo = "https://cloud.uni-koblenz-landau.de/s/qMG2WPjTXabzcbX/download"
@@ -401,10 +393,10 @@ def testSlicerCochleaRegistration(self, fixedImgPath=None, fixedPoint=None, movi
401393
slicer.mrmlScene.RemoveNode(tmpVolumeNode)
402394
else:
403395
nodeNames = os.path.splitext(os.path.basename(movingImgPath))[0]
404-
#endif
405-
[success, movingVolumeNode] = slicer.util.loadVolume(movingImgPath, returnNode=True)
396+
397+
movingVolumeNode = slicer.util.loadVolume(movingImgPath )
406398
movingVolumeNode.SetName(nodeNames)
407-
#endifelse
399+
408400
self.logic = CochleaRegLogic()
409401
self.vsc = VisSimCommon.VisSimCommonLogic()
410402
#setGlobal variables.
@@ -420,14 +412,14 @@ def testSlicerCochleaRegistration(self, fixedImgPath=None, fixedPoint=None, movi
420412
fixedFiducialNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsFiducialNode")
421413
fixedFiducialNode.CreateDefaultDisplayNodes()
422414
fixedFiducialNode.SetName("F_cochleaLocationPoint")
423-
fixedFiducialNode.AddFiducialFromArray(fixedPointRAS)
415+
fixedFiducialNode.AddControlPoint(fixedPointRAS)
424416
fixedFiducialNode.SetNthFiducialLabel(0, "F_CochleaLocation")
425417

426418
movingPointRAS = self.vsc.ptIJK2RAS(movingPoint , movingVolumeNode)
427419
movingFiducialNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsFiducialNode")
428420
movingFiducialNode.CreateDefaultDisplayNodes()
429421
movingFiducialNode.SetName("M_cochleaLocationPoint")
430-
movingFiducialNode.AddFiducialFromArray(movingPointRAS)
422+
movingFiducialNode.AddControlPoint(movingPointRAS)
431423
movingFiducialNode.SetNthFiducialLabel(0, "M_CochleaLocation")
432424

433425
# run the segmentation
@@ -439,11 +431,8 @@ def testSlicerCochleaRegistration(self, fixedImgPath=None, fixedPoint=None, movi
439431
except Exception as e:
440432
print("Can not display results! probably an external call ...")
441433
print(e)
442-
#endtry
443434

444435
self.etm=time.time()
445436
tm=self.etm - self.stm
446437
print("Time: "+str(tm)+" seconds")
447438
self.delayDisplay('Test testSlicerCochleaRegistration passed!')
448-
#enddef
449-
#endclass

CochleaSeg/CochleaSeg.py

Lines changed: 20 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,20 @@
44
# Sample cochlea datasets can be downloaded using Slicer Datastore module #
55
# #
66
# Contributers: #
7-
# - Ibraheem Al-Dhamari, ibraheem.al-dhamari@chaite.de #
7+
# - Ibraheem Al-Dhamari, ia@idhamari.com #
88
# [1] https://www.slicer.org #
99
# [2] http://elastix.isi.uu.nl #
1010
# [3] Al-Dhamari et al.,(2018), Automatic Cochlear Length and Volume Size Estimation #
1111
# First International Workshop on Context-Aware Operating #
1212
# Theater OR 2, MICCAI 2018, Granada Spain. #
13-
# [4] Al-Dhamari et al.,(2022), Automatic Cochlea Multimodal 3D Image Segmentation #
14-
# And Analysis Using Atlas-model-based Method (to be published!).
13+
# [4] Al-Dhamari et al.,(2023), Automatic Cochlea Multimodal 3D Image Segmentation #
14+
# And Analysis Using Atlas-model-based Method. Cochlea Implant International #
15+
# https://doi.org/10.1080/14670100.2023.2274199 #
1516
# [5] https://github.com/MedicalImageAnalysisTutorials/SlicerCochlea #
1617
# #
1718
#-------------------------------------------------------------------------------------#
18-
# Slicer 5.0.3 #
19-
# Updated: 20.9.2022 #
19+
# Slicer 5.4.0 #
20+
# Updated: 18.11.2023 #
2021
#======================================================================================
2122
# Non Slicer libs
2223
from __future__ import print_function
@@ -66,9 +67,6 @@ def __init__(self, parent):
6667
self.parent.helpText += self.getDefaultModuleDocumentationLink()
6768
parent.acknowledgementText = " This work is sponsored by Cochlear as part of COMBS project "
6869
self.parent = parent
69-
#end def init
70-
#end class CochleaSeg
71-
7270
#===================================================================
7371
# Main Widget
7472
#===================================================================
@@ -156,7 +154,6 @@ def setup(self):
156154
self.updateLengthBtn.toolTip = ('How to use:' ' Run segmentation first. ')
157155
self.updateLengthBtn.connect('clicked(bool)', self.onUpdateLengthBtnClick)
158156
self.mainFormLayout.addRow(self.updateLengthBtn )
159-
#enddef
160157

161158
self.layout.addStretch(1) # Collapsible button is held in place when collapsing/expanding.
162159
#------------------------------------------------------------------------
@@ -167,8 +164,7 @@ def setup(self):
167164
def onSideChkBoxChange(self):
168165
nodes = slicer.util.getNodesByClass('vtkMRMLMarkupsFiducialNode')
169166
self.vsc.setItemChk("cochleaSide", self.sideChkBox.checked, "cochleaSide", nodes)
170-
#enddef
171-
167+
172168
# Updating the cochlea length if the
173169
# the user correct some fiducial points
174170
def onUpdateLengthBtnClick(self):
@@ -221,16 +217,15 @@ def onInputFiducialBtnClick(self,volumeType):
221217
#print("inputFiducialNode exist")
222218
self.logic.inputFiducialNode = f
223219
newNode= False
224-
#endif
225-
#endfor
220+
226221
if not hasattr(self.vsc, 'vtVars'):
227222
self.vsc.setGlobalVariables(0)
228-
#end
223+
229224
self.vsc.locateItem(self.inputSelectorCoBx.currentNode(), self.inputPointEdt, 0 , 0)
230225
self.logic.inputFiducialNode= self.vsc.inputFiducialNodes[0]
231226

232227
self.inputFiducialBtn.setStyleSheet("QPushButton{ background-color: DarkSeaGreen }")
233-
#enddef
228+
234229

235230

236231
def onApplyBtnClick(self):
@@ -253,8 +248,7 @@ def onApplyBtnClick(self):
253248
self.runBtn.setText("Run")
254249
self.runBtn.setStyleSheet("QPushButton{ background-color: DarkSeaGreen }")
255250
slicer.app.processEvents()
256-
#enddef
257-
251+
258252
#===================================================================
259253
# Logic
260254
#===================================================================
@@ -337,17 +331,15 @@ def run(self, inputVolumeNode, inputFiducialNode, cochleaSide, customisedOutputP
337331
if np.sum(inputPoint)== 0 :
338332
print("Error: select cochlea point")
339333
return -1
340-
#endif
334+
341335
fnm = os.path.join(self.vsc.vtVars['outputPath'] , inputVolumeNode.GetName()+"_Cochlea_Pos.fcsv")
342336
sR = slicer.util.saveNode(inputFiducialNode, fnm )
343337

344338
#Remove old resulted nodes
345339
for node in slicer.util.getNodes():
346-
if ( segNodeName == node): slicer.mrmlScene.RemoveNode(node) #endif
347-
if ( transRgNodeName == node): slicer.mrmlScene.RemoveNode(node) #endif
348-
if ( transNRgNodeName == node): slicer.mrmlScene.RemoveNode(node) #endif
349-
350-
#endfor
340+
if ( segNodeName == node): slicer.mrmlScene.RemoveNode(node)
341+
if ( transRgNodeName == node): slicer.mrmlScene.RemoveNode(node)
342+
if ( transNRgNodeName == node): slicer.mrmlScene.RemoveNode(node)
351343

352344
inputPointT = self.vsc.v2t(inputPoint)
353345

@@ -490,10 +482,8 @@ def run(self, inputVolumeNode, inputFiducialNode, cochleaSide, customisedOutputP
490482
print("A-value Length Lt" , type(self.vsc.vtVars['AvalueStLtLength']))
491483
print("A-value Length Oc" , type(self.vsc.vtVars['AvalueStOcLength']))
492484

493-
#[self.vsc.vtVars['AvalueStLtLength'],self.vsc.vtVars['AvalueStOcLength'] ]
494485
# Display the result if no error
495486
# Clear cochlea location labels
496-
# TODO 2020: Add scala tympani full length to the table
497487
if (cTInr==0) and (cTRnr==0):
498488
# change the model type from vtk to stl
499489
msn=slicer.vtkMRMLModelStorageNode()
@@ -510,17 +500,17 @@ def run(self, inputVolumeNode, inputFiducialNode, cochleaSide, customisedOutputP
510500
print("creating ", tableName)
511501
spTblNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLTableNode")
512502
spTblNode.SetName(tableName)
513-
#endtry
503+
514504
spTblNode = self.vsc.getItemInfo( chSegNode, croppedNode, spTblNode,0)
515505
for i in range (0,8):
516506
spTblNode.RemoveColumn(3)
517-
#endfor
507+
518508
if spTblNode.GetNumberOfRows()>3:
519509
spTblNode.RemoveRow(spTblNode.GetNumberOfRows()-2)
520510
spTblNode.RemoveRow(spTblNode.GetNumberOfRows()-2)
521-
#endif
511+
522512
stVol = spTblNode.GetCellText(0,1)
523-
svVol = spTblNode.GetCellText(0,3)
513+
svVol = spTblNode.GetCellText(1,1)
524514
spTblNode.AddEmptyRow(); spTblNode.AddEmptyRow()
525515
spTblNode.AddEmptyRow(); spTblNode.AddEmptyRow()
526516
spTblNode.AddEmptyRow()
@@ -554,7 +544,7 @@ def run(self, inputVolumeNode, inputFiducialNode, cochleaSide, customisedOutputP
554544
spTblNode.SetCellText(5,2, str( self.vsc.vtVars['AvalueStLtLength'] ) )
555545
spTblNode.SetCellText(6,2, str( self.vsc.vtVars['AvalueStOcLength'] ) )
556546

557-
spTblNode.RemoveRow(spTblNode.GetNumberOfRows())
547+
#spTblNode.RemoveRow(spTblNode.GetNumberOfRows())
558548
self.spTblNode=spTblNode
559549
fnm = os.path.join(self.vsc.vtVars['outputPath'] , spTblNode.GetName()+".tsv")
560550
sR = slicer.util.saveNode(spTblNode, fnm )

0 commit comments

Comments
 (0)