Display Dicom data just received by websocket connection

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)

-Add the node to the MRML scene

-That it ?

Thank you for any hints and answers.

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").

Here’s something similar. It takes the contents of a nrrd as the body of an http POST and converts it into a volume node.

1 Like

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) .

Any idea why i can’t add this node ?

I tried following the example to create an empty volume, but i got the same crash :

    vtkNew<vtkMRMLScalarVolumeNode> dicomNodeTest;
    vtkSmartPointer<vtkImageData> imageDataTest = vtkSmartPointer<vtkImageData>::New();
    imageDataTest->SetDimensions(512,512,512);
    imageDataTest->AllocateScalars(VTK_UNSIGNED_CHAR,1);

    vtkSmartPointer<vtkImageThreshold> imageThreshold = vtkSmartPointer<vtkImageThreshold>::New();
    imageThreshold->SetInputData(imageDataTest);
    imageThreshold->SetInValue(0);
    imageThreshold->SetOutValue(0);
    imageThreshold->Update();
    this->GetMRMLScene()->AddNewNodeByClass("vtkMRMLScalarVolumeNode", "dicomNodeTest");
    dicomNodeTest->SetOrigin(0,0,0);
    dicomNodeTest->SetSpacing(1,1,1);
    dicomNodeTest->SetIToRASDirection(1,0,0);
    dicomNodeTest->SetJToRASDirection(0,1,0);
    dicomNodeTest->SetKToRASDirection(0,0,1);
    dicomNodeTest->SetAndObserveImageData(imageThreshold->GetOutput());
    dicomNodeTest->CreateDefaultDisplayNodes();
    dicomNodeTest->CreateDefaultStorageNode();

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.

Are you running in a debugger so you can see where the crash happens?

https://www.slicer.org/wiki/Documentation/Nightly/Developers/Tutorials/Debug_Instructions

So i attached gdb and here what i got :

[New Thread 0x7f654bc10700 (LWP 11920)]
[New Thread 0x7f654b40f700 (LWP 11921)]
[New Thread 0x7f654ac0e700 (LWP 11925)]
[New Thread 0x7f654a40d700 (LWP 11926)]
[New Thread 0x7f6549c0c700 (LWP 11927)]
[New Thread 0x7f654940b700 (LWP 11928)]
[New Thread 0x7f6548c0a700 (LWP 11929)]
[Thread 0x7f654a40d700 (LWP 11926) exited]
[Thread 0x7f654ac0e700 (LWP 11925) exited]
[Thread 0x7f6549c0c700 (LWP 11927) exited]
[Thread 0x7f654940b700 (LWP 11928) exited]
[Thread 0x7f6548c0a700 (LWP 11929) exited]

Thread 12 “SlicerApp-real” received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7f654b40f700 (LWP 11921)]
0x00007f665d3f264d in std::vector<vtkMRMLNode*, std::allocator<vtkMRMLNode*> >::size (this=0x178)
at /usr/include/c++/7/bits/stl_vector.h:671
671 { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }

Hard to tell just from that, but if you single step through and check the stack trace you should be able to track which statement leads to the crash.

Here the end of the backTrace, seems that CreateNodeByClass try to allocate the node and somehow fail.

#0 0x00007fc42a29464d in std::vector<vtkMRMLNode*, std::allocator<vtkMRMLNode*> >::size() const (this=0x178)
at /usr/include/c++/7/bits/stl_vector.h:671
#1 0x00007fc41a717965 in vtkMRMLScene::CreateNodeByClass(char const*) (this=0x0, className=0x7fc30c2bb9b0 “vtkMRMLScalarVolumeNode”)
at /home/raphaelbahegne/Dev/Slicer/Libs/MRML/Core/vtkMRMLScene.cxx:449
#2 0x00007fc41a71cf2e in vtkMRMLScene::AddNewNodeByClass(std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::__cxx11::basic_string<char, std::char_traits, std::allocator >) (this=0x0, className=“vtkMRMLScalarVolumeNode”, nodeBaseName=“dicomNodeTest”) at /home/raphaelbahegne/Dev/Slicer/Libs/MRML/Core/vtkMRMLScene.cxx:1275

Well i tried this :

vtkMRMLScene* scene = this->GetMRMLScene();
if (!scene)
{
vtkErrorMacro(“RegisterNodes: Invalid MRML scene”);
return false;
}

It’s quite simple in fact, it’s not adding node that crash. It’s just that the scene is null. But i don’t know why it is null.

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 ?

OK mrml scene was not connected to the logic, i though automatic generation of the module had taken care of this but i was mistaken.

I fix this architecture problem and now i face a new one : I create the node with the correct imageData and then i get :

HasItemAttribute: Failed to find subject hierarchy item by ID 94424278946520

The node is created but when i try to look a it i get

Input port 0 of algorithm vtkImageMapToWindowLevelColors(0x55914d195a70) has 0 connections but is not optional.

Input port 0 of algorithm vtkImageThreshold(0x55914d19d860) has 0 connections but is not optional.

Any ideas ?

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.

Ok, well somehow the setup of the mrml scene is broken, when i try to CreateDefaultDisplayNodes i get :

vtkMRMLScalarVolumeNode::CreateDefaultDisplayNodes failed: scene is invalid

You need to add volume node to MRML scene before calling CreateDefaultDIsplayNodes().

Well it seems that the node just like the logic can’t find the scene by himself so i needed to do a

dicomNode->SetScene(this->GetMRMLScene());
this->GetMRMLScene()->AddNewNodeByClass(“vtkMRMLScalarVolumeNode”, “dicomNode”);

To be able to create a DisplayNode

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 ?

node->SetScene(scene) is an undocumented internal helper method. To add a node to a scene, use scene->AddNode(node) instead.

Do you see any error in the application log?
Can you load sample data sets using Sample Data module?

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.