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
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#===================================================================
356347class 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
0 commit comments