[vtkusers] Problem with displaying cross-hairs on 2D views when using vtkImageResliceMapper -> vtkImageSlice -> vtkImageStack pipeline
ochampao
ochampao at hotmail.com
Tue Dec 18 13:40:46 EST 2018
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
<http://vtk.1045678.n5.nabble.com/file/t341857/BasicPipeline.cxx>
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: http://vtk.1045678.n5.nabble.com/VTK-Users-f1224199.html
More information about the vtkusers
mailing list