BrownBiomechanics / SlicerAutoscoperM

This 3D Slicer extension enables users to perform image registration.
https://autoscoperm.slicer.org
MIT License
0 stars 3 forks source link

VTK Input port warning in partial volume generation module #40

Closed NicerNewerCar closed 11 months ago

NicerNewerCar commented 11 months ago

Overview

This error is happening during the casting process of the partial volume generation module. Details about the error and the code needed to reproduce the error outside of the module are included below.

The error happens after the second call to _castVolume has completed successfully during the run of castVolumeForTIFF.

Error

[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(0000018227D49920) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(0000018227D48D70) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(0000018227D49920) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(0000018259432900) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(0000018227D49920) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(0000018227D48D70) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(0000018227D49920) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(0000018259432900) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(0000018227D5F270) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(0000018227D5E7D0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(0000018227D5F270) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(0000018259430740) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(0000018227D5F270) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(0000018227D5E7D0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(0000018227D5F270) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(0000018259430740) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(0000018227D60D00) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(0000018227D60AE0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(0000018227D60D00) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(000001827C595100) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(0000018227D60D00) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(0000018227D60AE0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(0000018227D60D00) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(000001827C595100) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(0000018227D49920) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(0000018227D48D70) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(0000018227D49920) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(0000018259432900) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(0000018227D49920) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(0000018227D48D70) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(0000018227D49920) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(0000018259432900) has 0 connections but is not optional.

Functions needed to reproduce the error

import slicer
import numpy as np

def castVolumeForTIFF(volumeNode: slicer.vtkMRMLVolumeNode) -> None:
    """
    Casts a volume node to a new type

    Args:
        volumeNode (slicer.vtkMRMLVolumeNode): Volume node
    """
    _castVolume(volumeNode, "Short")

    volumeArray = slicer.util.arrayFromVolume(volumeNode)
    minVal = np.min(volumeArray)
    if minVal < 0:
        minVal = -minVal
    isNotZero = volumeArray != 0  # Since 0 is the background value, we don't want to add minVal to it
    volumeArray[isNotZero] += minVal

    slicer.util.updateVolumeFromArray(volumeNode, volumeArray)

    _castVolume(volumeNode, "UnsignedShort")

def _castVolume(volumeNode: slicer.vtkMRMLVolumeNode, newType: str):
    castModule = slicer.modules.castscalarvolume
    parameters = {}
    parameters["InputVolume"] = volumeNode.GetID()
    parameters["OutputVolume"] = parameters["InputVolume"]
    parameters["Type"] = newType  # Short to UnsignedShort
    cliNode = slicer.cli.runSync(castModule, None, parameters)
    slicer.mrmlScene.RemoveNode(cliNode)
    del cliNode, parameters, castModule

Example

volumeNode = slicer.util.getNode("Your CT volume node")
castVolumeForTIFF(volumeNode)
NicerNewerCar commented 11 months ago

Update

It appears that both calls to _castVolume are causing the errors actually.

Here is the output after running the code with the highest level of verbosity in Slicer:

>>> castVolumeForTIFF(volumeNode)
[Qt] Python console user input: castVolumeForTIFF(volumeNode)
[Qt] Found CommandLine Module, target is  C:/Users/anthony.lombardi/AppData/Local/NA-MIC/Slicer 5.2.2/bin/../lib/Slicer-5.2/cli-modules/CastScalarVolume.exe
[Qt] ModuleType: CommandLineModule
[Qt] Cast Scalar Volume command line: 
[Qt] C:/Users/anthony.lombardi/AppData/Local/NA-MIC/Slicer 5.2.2/bin/../lib/Slicer-5.2/cli-modules/CastScalarVolume.exe --type Short C:/Users/anthony.lombardi/AppData/Local/Temp/Slicer/FGDG_vtkMRMLScalarVolumeNodeB.nrrd C:/Users/anthony.lombardi/AppData/Local/Temp/Slicer/FGDG_vtkMRMLScalarVolumeNodeB.nrrd 
[Qt] Cast Scalar Volume completed without errors
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE2710) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(000001BDC1AE12E0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE2710) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(000001BDBD1BAE90) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE2710) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(000001BDC1AE12E0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE2710) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(000001BDBD1BAE90) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE2C60) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(000001BDC1AE2B50) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE2C60) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(000001BDBD1BC090) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE2C60) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(000001BDC1AE2B50) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE2C60) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(000001BDBD1BC090) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE0400) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(000001BDC1AE21C0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE0400) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(000001BDBD1B8CD0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE0400) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(000001BDC1AE21C0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE0400) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(000001BDBD1B8CD0) has 0 connections but is not optional.
[VTK] Loaded volume from file: C:/Users/anthony.lombardi/AppData/Local/Temp/Slicer/FGDG_vtkMRMLScalarVolumeNodeB.nrrd. Dimensions: 512x512x401. Number of components: 1. Pixel type: short.
[Qt] Found CommandLine Module, target is  C:/Users/anthony.lombardi/AppData/Local/NA-MIC/Slicer 5.2.2/bin/../lib/Slicer-5.2/cli-modules/CastScalarVolume.exe
[Qt] ModuleType: CommandLineModule
[Qt] Cast Scalar Volume command line: 
[Qt] C:/Users/anthony.lombardi/AppData/Local/NA-MIC/Slicer 5.2.2/bin/../lib/Slicer-5.2/cli-modules/CastScalarVolume.exe --type UnsignedShort C:/Users/anthony.lombardi/AppData/Local/Temp/Slicer/FGDG_vtkMRMLScalarVolumeNodeB.nrrd C:/Users/anthony.lombardi/AppData/Local/Temp/Slicer/FGDG_vtkMRMLScalarVolumeNodeB.nrrd 
[Qt] Cast Scalar Volume completed without errors
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE0400) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(000001BDC1AE21C0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE0400) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(000001BDBD1B8CD0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE0400) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(000001BDC1AE21C0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE0400) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(000001BDBD1B8CD0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE2710) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(000001BDC1AE12E0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE2710) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(000001BDBD1BAE90) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE2710) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(000001BDC1AE12E0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE2710) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(000001BDBD1BAE90) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE2C60) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(000001BDC1AE2B50) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE2C60) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(000001BDBD1BC090) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE2C60) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(000001BDC1AE2B50) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE2C60) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(000001BDBD1BC090) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE0400) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(000001BDC1AE21C0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE0400) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(000001BDBD1B8CD0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE0400) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(000001BDC1AE21C0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(000001BDC1AE0400) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(000001BDBD1B8CD0) has 0 connections but is not optional.
[VTK] Loaded volume from file: C:/Users/anthony.lombardi/AppData/Local/Temp/Slicer/FGDG_vtkMRMLScalarVolumeNodeB.nrrd. Dimensions: 512x512x401. Number of components: 1. Pixel type: unsigned short.

Update 2

The issue appears to be caused by using an output node that has already been populated with information

Using a new node:


nodeName = "MyNewVolume"
imageSize = [512, 512, 512]
voxelType=vtk.VTK_UNSIGNED_CHAR
imageOrigin = [0.0, 0.0, 0.0]
imageSpacing = [1.0, 1.0, 1.0]
imageDirections = [[1,0,0], [0,1,0], [0,0,1]]
fillVoxelValue = 0

# Create an empty image volume, filled with fillVoxelValue
imageData = vtk.vtkImageData()
imageData.SetDimensions(imageSize)
imageData.AllocateScalars(voxelType, 1)
imageData.GetPointData().GetScalars().Fill(fillVoxelValue)
# Create volume node
volumeNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLScalarVolumeNode", nodeName)
volumeNode.SetOrigin(imageOrigin)
volumeNode.SetSpacing(imageSpacing)
volumeNode.SetIJKToRASDirections(imageDirections)
volumeNode.SetAndObserveImageData(imageData)
volumeNode.CreateDefaultDisplayNodes()
volumeNode.CreateDefaultStorageNode()
>>> parameters["OutputVolume"] = volumeNode.GetID()
[Qt] Python console user input: parameters["OutputVolume"] = volumeNode.GetID()
>>> cliNode = slicer.cli.runSync(castModule, None, parameters)
[Qt] Python console user input: cliNode = slicer.cli.runSync(castModule, None, parameters)
[Qt] Found CommandLine Module, target is  C:/Users/anthony.lombardi/AppData/Local/NA-MIC/Slicer 5.2.2/bin/../lib/Slicer-5.2/cli-modules/CastScalarVolume.exe
[Qt] ModuleType: CommandLineModule
[Qt] Cast Scalar Volume command line: 
[Qt] C:/Users/anthony.lombardi/AppData/Local/NA-MIC/Slicer 5.2.2/bin/../lib/Slicer-5.2/cli-modules/CastScalarVolume.exe --type Short C:/Users/anthony.lombardi/AppData/Local/Temp/Slicer/CAAAI_vtkMRMLScalarVolumeNodeB.nrrd C:/Users/anthony.lombardi/AppData/Local/Temp/Slicer/CAAAI_vtkMRMLScalarVolumeNodeD.nrrd 
[Qt] Cast Scalar Volume completed without errors
[VTK] Loaded volume from file: C:/Users/anthony.lombardi/AppData/Local/Temp/Slicer/CAAAI_vtkMRMLScalarVolumeNodeD.nrrd. Dimensions: 512x512x401. Number of components: 1. Pixel type: short.
>>> 

Rerunning the cast with the populated output node

>>> cliNode = slicer.cli.runSync(castModule, None, parameters)
[Qt] Python console user input: cliNode = slicer.cli.runSync(castModule, None, parameters)
[Qt] Found CommandLine Module, target is  C:/Users/anthony.lombardi/AppData/Local/NA-MIC/Slicer 5.2.2/bin/../lib/Slicer-5.2/cli-modules/CastScalarVolume.exe
[Qt] ModuleType: CommandLineModule
[Qt] Cast Scalar Volume command line: 
[Qt] C:/Users/anthony.lombardi/AppData/Local/NA-MIC/Slicer 5.2.2/bin/../lib/Slicer-5.2/cli-modules/CastScalarVolume.exe --type Short C:/Users/anthony.lombardi/AppData/Local/Temp/Slicer/CAAAI_vtkMRMLScalarVolumeNodeB.nrrd C:/Users/anthony.lombardi/AppData/Local/Temp/Slicer/CAAAI_vtkMRMLScalarVolumeNodeD.nrrd 
[Qt] Cast Scalar Volume completed without errors
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(00000186FD8A2740) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(00000186FD8A2C90) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(00000186FD8A2740) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(00000186F1D1CAF0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(00000186FD8A2740) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(00000186FD8A2C90) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(00000186FD8A2740) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(00000186F1D1CAF0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(00000186FD8A2630) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(00000186FD8A2520) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(00000186FD8A2630) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(00000186EF2A4D20) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(00000186FD8A2630) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(00000186FD8A2520) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(00000186FD8A2630) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(00000186EF2A4D20) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(00000186FD8A2850) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(00000186FD8A1FD0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(00000186FD8A2850) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(00000186EF2A36A0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(00000186FD8A2850) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(00000186FD8A1FD0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(00000186FD8A2850) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(00000186EF2A36A0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(00000186FD8A2740) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(00000186FD8A2C90) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(00000186FD8A2740) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(00000186F1D1CAF0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(00000186FD8A2740) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(00000186FD8A2C90) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(00000186FD8A2740) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(00000186F1D1CAF0) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(00000186FD8A2630) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(00000186FD8A2520) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(00000186FD8A2630) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(00000186EF2A4D20) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(00000186FD8A2630) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageThreshold(00000186FD8A2520) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageMapToWindowLevelColors(00000186FD8A2630) has 0 connections but is not optional.
[VTK] Input port 0 of algorithm vtkImageReslice(00000186EF2A4D20) has 0 connections but is not optional.
[VTK] Loaded volume from file: C:/Users/anthony.lombardi/AppData/Local/Temp/Slicer/CAAAI_vtkMRMLScalarVolumeNodeD.nrrd. Dimensions: 512x512x401. Number of components: 1. Pixel type: short.
>>> 
NicerNewerCar commented 11 months ago

Resolved using this code

def _castVolume(volumeNode: slicer.vtkMRMLVolumeNode, newType: str):
    """
    Internal function to cast a volume node to a new type
    """
    tmpVolNode = _createNewVolumeNode("tmpVolNode")
    castModule = slicer.modules.castscalarvolume
    parameters = {}
    parameters["InputVolume"] = volumeNode.GetID()
    parameters["OutputVolume"] = tmpVolNode.GetID()
    parameters["Type"] = newType  # Short to UnsignedShort
    cliNode = slicer.cli.runSync(castModule, None, parameters)
    slicer.mrmlScene.RemoveNode(cliNode)
    del cliNode, parameters, castModule

    volumeNode.SetAndObserveImageData(tmpVolNode.GetImageData())
    slicer.mrmlScene.RemoveNode(tmpVolNode)

def _createNewVolumeNode(nodeName: str) -> slicer.vtkMRMLVolumeNode:
    """
    Internal function to create a blank volume node
    """
    imageSize = [512, 512, 512]
    voxelType = vtk.VTK_UNSIGNED_CHAR
    imageOrigin = [0.0, 0.0, 0.0]
    imageSpacing = [1.0, 1.0, 1.0]
    imageDirections = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
    fillVoxelValue = 0

    # Create an empty image volume, filled with fillVoxelValue
    imageData = vtk.vtkImageData()
    imageData.SetDimensions(imageSize)
    imageData.AllocateScalars(voxelType, 1)
    imageData.GetPointData().GetScalars().Fill(fillVoxelValue)
    # Create volume node
    volumeNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLScalarVolumeNode", nodeName)
    volumeNode.SetOrigin(imageOrigin)
    volumeNode.SetSpacing(imageSpacing)
    volumeNode.SetIJKToRASDirections(imageDirections)
    volumeNode.SetAndObserveImageData(imageData)
    volumeNode.CreateDefaultDisplayNodes()
    volumeNode.CreateDefaultStorageNode()
    return volumeNode