Hello, I’m rather new to Slicer. I just developed a loadable module in C++ that connect to a MRI using websocket and receive dicom image data. Now i just need to display those dicoms.
So correct me if i’m wrong, i need to :
-Create a Node (not sure which kind), fill it with some dicom data (for now i’ve QbyteArrays)
You need to create a vtkMRMLScalarVolumeNode as shown here. I’m not sure how to set the pixel data in vtkImageData from a QByteArray but @pieper did something similar in the past so maybe he can help.
A much simpler approach is to write the byte array to a file, create a text header file (e.g., a NRRD image file header) and read the header file into Slicer using slicer.util.loadVolume("path/to/something.nhdr").
Thank you for your answer, i used dcmtk to get the pixel data from the dicom and copied it in the vtkImageData. I don’t know the use of DisplayNodes but i get “vtkMRMLScalarVolumeNode::CreateDefaultDisplayNodes failed: scene is invalid” when i try to create one.
But the major problem is that slicer crash when i try to add a new Node to the scene. So it may be related to fact that the scene is invalid but i don’t know why it is that way, it is the only time interact with the scene.
I work on Ubuntu using QtCreator
Here is part of my code :
vtkNew<vtkMRMLScalarVolumeNode> dicomNode;
vtkSmartPointer<vtkImageData> imageData = vkSmartPointer<vtkImageData>::New();
imageData->SetOrigin(0.0,0.0,0.0);
imageData->SetSpacing(2.34375,2.34375,2.34375);
imageData->SetDimensions(583,583,1);
imageData->AllocateScalars(VTK_TYPE_UINT16,1);
if( dcmImage != nullptr )
{
if( dcmImage->getStatus() == EIS_Normal )
{
if( dcmImage->getOutputData(16) != nullptr )
{
// we copy the data in the dcmtk buffer to the vtkImageData one
memcpy((unsigned short *)imageData->GetScalarPointer(), (unsigned short *)dcmImage->getOutputData(16), dcmImage->getOutputDataSize() );
dcmImage->deleteOutputData();
imageData->Modified();
}
}
}
dicomNode->CreateDefaultDisplayNodes();
dicomNode->SetAndObserveImageData(imageData);
this->GetMRMLScene()->AddNewNodeByClass("vtkMRMLScalarVolumeNode", "dicomNode");
ImageData setting are hardcoded for know and are extracted from my dicom image test (DCM_PixelSpacing and DCM_WindowWidth) .
So I guess then that problem is not about the image data. I create this module using the extension wizard, and this code part is in the logic part derivated from vtkSlicerModuleLogic.
Sounds like you are making progress. Now that you have the debugger set up you can single step through one of the other loadable modules and see how it uses the scene and see why it’s different in your module.
Slicer can hold several mrml scene ? I was under the impression that there was only one scene and the link between modules and the scene was kinda automatic, am I wrong ?
There should be no need for low-level manipulation of scene, viewers, logic, etc. Creating a volume node, setting the received vtkImageData into it, adding the volume node to the scene, and creating default display nodes should be enough.
BUT my journey is not finished yet because the created node is filled with just one black slice in I, J and K. First i thought my data were broken, then i tried to load dicoms the regular way and i got the same. Then i thought my module messed up something so i tried with a slicer 4.10.2 version freshly downloaded and i got the same with every dicom series i tried. I cross checked on a collegue computer and it worked on his machine (windows).
Here is my config :
Ubuntu 18.04.2 LTS
-Memory: 7,6 Gio
-Proc : Intel® Core™ i5-8500 CPU @ 3.00GHz × 6
-GPu : Intel® UHD Graphics 630 (Coffeelake 3x8 GT2)
-GNOME : 3.28.2
64-bit
Do my setup miss something, is there a specific on Ubuntu ?
Well i may miss something but if i use scene->AddNode(node), then when I do node->GetDisplayNode, the function check this->GetScene and do not find a scene and throw the vtkMRMLScalarVolumeNode::CreateDefaultDisplayNodes failed: scene is invalid.
Sample data are working, seems to be only dicom not loading.
After scene->AddNode(node) you need to call node->CreateDefaultDisplayNodes() to create display nodes. After that, node->GetDisplayNode() will return valid node.