Re: Problem with displaying cross-hairs on 2D views when using vtkImageResliceMapper -> vtkImageSlice -> vtkImageStack pipeline
Andras Lasso <[email protected]>
| Newsgroups | gmane.comp.lib.vtk.user |
|---|---|
| Message-ID | <YTXPR0101MB1870ABE4ABBF6595CEEDB4FDD8BE0@YTXPR0101MB1870.CANPRD01.PROD.OUTLOOK.COM> |
It is great that you are interested in medical imaging and has chosen to work with VTK. I would recommend to put your talent and effort into contributing to an existing open-source medical image viewer instead of spending time with redeveloping basic features. You could work on more interesting things, develop new features, and you would very quickly become a useful, valued member of a community. If you are interested in answers to your question (and your future questions) you can have a look at source code of existing VTK-based open-source medical image viewers, such as 3D Slicer, MITK, medInria, Horos, Ibis, CustusX, CamiTK, Invesalius, etc. Andras -----Original Message----- From: vtkusers <[email protected]> On Behalf Of ochampao Sent: Tuesday, December 18, 2018 1:41 PM To: [email protected] Subject: [vtkusers] Problem with displaying cross-hairs on 2D views when using vtkImageResliceMapper -> vtkImageSlice -> vtkImageStack pipeline Hi vtkUsers, I am developing a four-pane viewer for displaying medical images. The 3 views display slices of the volumes in the 3 standard anatomical views (axial, coronal, sagittal) whereas the 4th one displays some 3D surface rendering of the volume. For now, I will only focus on the 2D views. The 2D views use the following pipeline: vtkImageResliceMapper -> vtkImageSlice -> vtkImageStack. This allows the application to overlay slices from multiple volumes simultaneously. The attached code is a minimal example of the 2D pipeline I use in my application. The slices displayed are determined by the focal point of the camera in each 2D view. What I would like to do is display a set of cross-hairs on each of the 2D views, but I don't know how to achieve this using the pipeline I am currently using. I am aware of the classes: vtkResliceCursorWidget, vtkResliceCursor, vtkResliceCursorLineRepresentation, vtkImagePlaneWidget, vtkResliceImageViewer I have tried using these classes (see commented code in attached source code), but they don't seem compatible with my current pipeline. For example, when using vtkResliceCursorWidget the cross-hairs are visible and I can interact with them but slicing stops working. I also see some weird artefacts around the border of the slice. Also, to use these classes I need to specify the volume which the reslice cursor will be slicing (vtkResliceCursor->SetImage(imageData)), but in my case I have multiple volumes. I am also aware of and tried using vtkCursor2D/vtkCursor3D. Although they are close to what I have in mind, they allow very limited customization of their look. Essentially what I would like to implement is something that looks like the cursor of vtkResliceCursorWidget/vtkImagePlaneWidget/vtkResliceImageViewer but does not handle slicing. Can someone recommend how can I achieve this, or point me to some classes/examples? Is their a way of using vtkResliceCursorWidget/vtkImagePlaneWidget/vtkResliceImageViewer with my current pipeline, or would I need to change it? Thanks a lot for your help. Panos ======================================================== Basic Pipeline Minimal Example ======================================================== #include <vtkCamera.h> #include <vtkDICOMImageReader.h> #include <vtkImageChangeInformation.h> #include <vtkImageData.h> #include <vtkImageProperty.h> #include <vtkImageResliceMapper.h> #include <vtkImageSlice.h> #include <vtkImageStack.h> #include <vtkInteractorStyleImage.h> #include <vtkMath.h> #include <vtkNIFTIImageReader.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> #include <vtkSmartPointer.h> #include <vtkResliceCursor.h> #include <vtkResliceCursorActor.h> #include <vtkResliceCursorLineRepresentation.h> #include <vtkResliceCursorPolyDataAlgorithm.h> #include <vtkResliceCursorWidget.h> void setupCamera(vtkCamera* camera); vtkSmartPointer<vtkImageData> loadDicom(const char* filename); vtkSmartPointer<vtkImageData> loadNifti(const char* filename); int main(int, char*[]) { // Setup renderer vtkNew<vtkRenderer> renderer; renderer->SetBackground(0.0, 0.0, 0.0); renderer->GetActiveCamera()->ParallelProjectionOn(); renderer->ResetCameraClippingRange(); renderer->ResetCamera(); // Setup renderWindow vtkNew<vtkRenderWindow> renderWindow; renderWindow->AddRenderer(renderer); // Setup interaction style vtkNew<vtkInteractorStyleImage> interactorStyle; interactorStyle->SetInteractionModeToImageSlicing(); // Setup window interactor vtkNew<vtkRenderWindowInteractor> renderWindowInteractor; renderWindowInteractor->SetRenderWindow(renderWindow); renderWindowInteractor->SetInteractorStyle(interactorStyle); // Setup camera setupCamera(renderer->GetActiveCamera()); // Load data from DICOM series // vtkSmartPointer<vtkImageData> imageData = // loadDicom("<path_to_DICOM_series>""); // Load data from Nifti file vtkSmartPointer<vtkImageData> imageData = loadNifti("<path_to_nii_file>"); // setup slice mapper vtkNew<vtkImageResliceMapper> resliceMapper; resliceMapper->SetInputData(imageData); resliceMapper->SliceFacesCameraOn(); resliceMapper->SliceAtFocalPointOn(); resliceMapper->JumpToNearestSliceOn(); resliceMapper->BorderOff(); // Set to full window and centered level: double window = imageData->GetScalarRange()[1] - imageData->GetScalarRange()[0]; double level = imageData->GetScalarRange()[0] + window / 2.0; // Setup prop holding the slice vtkNew<vtkImageSlice> imageSlice; imageSlice->SetMapper(resliceMapper); imageSlice->GetProperty()->SetColorWindow(window); imageSlice->GetProperty()->SetColorLevel(level); imageSlice->GetProperty()->SetLayerNumber(0); imageSlice->GetProperty()->SetInterpolationTypeToNearest(); // Setup prop holding the multiple slices vtkNew<vtkImageStack> imageStack; imageStack->SetActiveLayer(imageSlice->GetProperty()->GetLayerNumber()); imageStack->AddImage(imageSlice); // add slice vtkNew<vtkResliceCursor> resliceCursor; resliceCursor->SetCenter(imageData->GetCenter()); resliceCursor->SetThickMode(0); resliceCursor->SetImage(imageData); vtkNew<vtkResliceCursorLineRepresentation> cursorRepresentation; cursorRepresentation->GetResliceCursorActor()-> GetCursorAlgorithm()->SetResliceCursor(resliceCursor); cursorRepresentation->GetResliceCursorActor()-> BasicPipeline.cxx <https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fvtk.1045678.n5.nabble.com%2Ffile%2Ft341857%2FBasicPipeline.cxx&data=02%7C01%7Classo%40queensu.ca%7C80118413b7ba4ceb15d108d665185599%7Cd61ecb3b38b142d582c4efb2838b925c%7C1%7C1%7C636807552523602151&sdata=nT57nY7HqbSgYg8flXNrjvfhqXVDbvDHbyEOMCVE3V0%3D&reserved=0> GetCursorAlgorithm()->SetReslicePlaneNormal(2); vtkNew<vtkResliceCursorWidget> resliceCursorWidget; resliceCursorWidget->SetInteractor(renderWindowInteractor); resliceCursorWidget->SetDefaultRenderer(renderer); resliceCursorWidget->SetRepresentation(cursorRepresentation); resliceCursorWidget->SetManageWindowLevel(false); resliceCursorWidget->EnabledOn(); //resliceCursorWidget->ProcessEventsOff(); // Add actors to renderer renderer->AddViewProp(imageStack); renderer->ResetCamera(); // Start interaction renderWindowInteractor->Initialize(); renderWindow->Render(); renderWindowInteractor->Start(); return EXIT_SUCCESS; } void setupCamera(vtkCamera* camera) { double viewUp[3] = { 0, 1, 0 }; double leftToRight[3] = { 1, 0, 0 }; // compute the view plane normal double normal[3]; vtkMath::Cross(leftToRight, viewUp, normal); // get the camera focus double focus[3]; camera->GetFocalPoint(focus); // get the camera distance from the focus double d = camera->GetDistance(); // position the camera on view plane normal keeping the focus and the distance from it fixed camera->SetPosition( focus[0] + d*normal[0], focus[1] + d*normal[1], focus[2] + d*normal[2]); // make sure focus is the same camera->SetFocalPoint(focus); // setup view up vector camera->SetViewUp(viewUp); camera->OrthogonalizeViewUp(); } vtkSmartPointer<vtkImageData> loadDicom(const char* filename) { vtkNew<vtkDICOMImageReader> reader; reader->FileLowerLeftOn(); reader->SetDirectoryName(filename); reader->UpdateInformation(); vtkNew<vtkImageChangeInformation> imageInfo; imageInfo->SetOutputOrigin(0.0, 0.0, 0.0); imageInfo->SetOutputSpacing(reader->GetPixelSpacing()); imageInfo->SetInputConnection(reader->GetOutputPort()); imageInfo->Update(); return imageInfo->GetOutput(); } vtkSmartPointer<vtkImageData> loadNifti(const char* filename) { vtkNew<vtkNIFTIImageReader> niftiiReader; niftiiReader->SetFileName(filename); vtkNew<vtkImageChangeInformation> imageInfo; imageInfo->SetOutputOrigin(0.0, 0.0, 0.0); imageInfo->SetInputConnection(niftiiReader->GetOutputPort()); imageInfo->Update(); return imageInfo->GetOutput();//data; } -- Sent from: https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fvtk.1045678.n5.nabble.com%2FVTK-Users-f1224199.html&data=02%7C01%7Classo%40queensu.ca%7C80118413b7ba4ceb15d108d665185599%7Cd61ecb3b38b142d582c4efb2838b925c%7C1%7C1%7C636807552523602151&sdata=y%2FPL7RWRxL9djen9OHHFpV8mML1l8tDDID8vwEPDzr4%3D&reserved=0 _______________________________________________ Powered by https://na01.safelinks.protection.outlook.com/?url=www.kitware.com&data=02%7C01%7Classo%40queensu.ca%7C80118413b7ba4ceb15d108d665185599%7Cd61ecb3b38b142d582c4efb2838b925c%7C1%7C1%7C636807552523602151&sdata=a5wXXUd01fJsRRfeOlVc%2Bk6JcNbeRrCaawzEeOBEpIQ%3D&reserved=0 Visit other Kitware open-source projects at https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.kitware.com%2Fopensource%2Fopensource.html&data=02%7C01%7Classo%40queensu.ca%7C80118413b7ba4ceb15d108d665185599%7Cd61ecb3b38b142d582c4efb2838b925c%7C1%7C1%7C636807552523602151&sdata=GTPQfYrm85nLVvMYqtzwxYrfNS%2BHK2U5E%2F8%2FXjTuyGQ%3D&reserved=0 Please keep messages on-topic and check the VTK FAQ at: https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.vtk.org%2FWiki%2FVTK_FAQ&data=02%7C01%7Classo%40queensu.ca%7C80118413b7ba4ceb15d108d665185599%7Cd61ecb3b38b142d582c4efb2838b925c%7C1%7C1%7C636807552523602151&sdata=3OkV0h9SM82LHRbPbSKbfXkZuLWSqAjPyULJuBV%2FrGQ%3D&reserved=0 Search the list archives at: https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fmarkmail.org%2Fsearch%2F%3Fq%3Dvtkusers&data=02%7C01%7Classo%40queensu.ca%7C80118413b7ba4ceb15d108d665185599%7Cd61ecb3b38b142d582c4efb2838b925c%7C1%7C1%7C636807552523602151&sdata=ydyX30Af9G0j8PwVigfaCkucOiFqv0SdNKwyi7vx56Y%3D&reserved=0 Follow this link to subscribe/unsubscribe: https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpublic.kitware.com%2Fmailman%2Flistinfo%2Fvtkusers&data=02%7C01%7Classo%40queensu.ca%7C80118413b7ba4ceb15d108d665185599%7Cd61ecb3b38b142d582c4efb2838b925c%7C1%7C1%7C636807552523602151&sdata=zYNgte5262YQQDT42ydJgSd1qTiDwQBW4DeWwgOlCzE%3D&reserved=0 _______________________________________________ Powered by www.kitware.com Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Please keep messages on-topic and check the VTK FAQ at: http://www.vtk.org/Wiki/VTK_FAQ Search the list archives at: http://markmail.org/search/?q=vtkusers Follow this link to subscribe/unsubscribe: https://public.kitware.com/mailman/listinfo/vtkusers