|
vtkResliceCursorWidget和vtkResliceCursor类实现交互式图像切分,vtkResliceCursorWidget对象中需要定义相对应的vtkResliceCursor对象。vtkResliceCursorWidget定义十字坐标轴为用户提供便捷的切分和交互方式,支持坐标轴的旋转和平移;当坐标轴发生改变时,调用vtkResliceCursor来进行图像切分并更新到vtkRenderer对象中。
调整层厚的效果
- // SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill
- // Lorensen SPDX-License-Identifier: BSD-3-Clause
- #include "vtkRegressionTestImage.h"
- #include "vtkSmartPointer.h"
- #include "vtkActor.h"
- #include "vtkBiDimensionalWidget.h"
- #include "vtkCamera.h"
- #include "vtkCellPicker.h"
- #include "vtkCommand.h"
- #include "vtkDICOMImageReader.h"
- #include "vtkImageActor.h"
- #include "vtkImageData.h"
- #include "vtkImageMapToColors.h"
- #include "vtkImagePlaneWidget.h"
- #include "vtkImageReader.h"
- #include "vtkImageReslice.h"
- #include "vtkInteractorEventRecorder.h"
- #include "vtkInteractorStyleImage.h"
- #include "vtkLookupTable.h"
- #include "vtkOutlineFilter.h"
- #include "vtkPlane.h"
- #include "vtkPlaneSource.h"
- #include "vtkPointData.h"
- #include "vtkPolyDataMapper.h"
- #include "vtkProperty.h"
- #include "vtkRenderWindow.h"
- #include "vtkRenderWindowInteractor.h"
- #include "vtkRenderer.h"
- #include "vtkResliceCursor.h"
- #include "vtkResliceCursorActor.h"
- #include "vtkResliceCursorLineRepresentation.h"
- #include "vtkResliceCursorPolyDataAlgorithm.h"
- #include "vtkResliceCursorThickLineRepresentation.h"
- #include "vtkResliceCursorWidget.h"
- #include "vtkVolume16Reader.h"
- #include "vtkTestUtilities.h"
- //------------------------------------------------------------------------------
- class vtkResliceCursorCallback3 : public vtkCommand
- {
- public:
- static vtkResliceCursorCallback3* New()
- {
- return new vtkResliceCursorCallback3;
- }
- void Execute(vtkObject* caller, unsigned long /*ev*/, void* callData) override
- {
- vtkImagePlaneWidget* ipw = dynamic_cast<vtkImagePlaneWidget*>(caller);
- if (ipw)
- {
- double* wl = static_cast<double*>(callData);
- if (ipw == this->IPW[0])
- {
- this->IPW[1]->SetWindowLevel(wl[0], wl[1], 1);
- this->IPW[2]->SetWindowLevel(wl[0], wl[1], 1);
- }
- else if (ipw == this->IPW[1])
- {
- this->IPW[0]->SetWindowLevel(wl[0], wl[1], 1);
- this->IPW[2]->SetWindowLevel(wl[0], wl[1], 1);
- }
- else if (ipw == this->IPW[2])
- {
- this->IPW[0]->SetWindowLevel(wl[0], wl[1], 1);
- this->IPW[1]->SetWindowLevel(wl[0], wl[1], 1);
- }
- }
- vtkResliceCursorWidget* rcw = dynamic_cast<vtkResliceCursorWidget*>(caller);
- if (rcw)
- {
- vtkResliceCursorLineRepresentation* rep =
- dynamic_cast<vtkResliceCursorLineRepresentation*>(
- rcw->GetRepresentation());
- vtkResliceCursor* rc = rep->GetResliceCursorActor()
- ->GetCursorAlgorithm()
- ->GetResliceCursor();
- for (int i = 0; i < 3; i++)
- {
- vtkPlaneSource* ps =
- static_cast<vtkPlaneSource*>(this->IPW[i]->GetPolyDataAlgorithm());
- ps->SetNormal(rc->GetPlane(i)->GetNormal());
- ps->SetCenter(rc->GetPlane(i)->GetOrigin());
- // If the reslice plane has modified, update it on the 3D widget
- this->IPW[i]->UpdatePlacement();
- // std::cout << "Updating placement of plane: " << i << " " <<
- // rc->GetPlane(i)->GetNormal()[0] << " " <<
- // rc->GetPlane(i)->GetNormal()[1] << " " <<
- // rc->GetPlane(i)->GetNormal()[2] << std::endl;
- // this->IPW[i]->GetReslice()->Print(cout);
- // rep->GetReslice()->Print(cout);
- // std::cout << "---------------------" << std::endl;
- }
- }
- // Render everything
- this->RCW[0]->Render();
- }
- vtkResliceCursorCallback3() = default;
- vtkImagePlaneWidget* IPW[3];
- vtkResliceCursorWidget* RCW[3];
- };
- //------------------------------------------------------------------------------
- int main(int argc, char* argv[])
- {
- vtkSmartPointer<vtkDICOMImageReader> reader =
- vtkSmartPointer<vtkDICOMImageReader>::New();
- reader->SetDirectoryName("D:/Data/two/SE1");
- reader->Update();
- vtkSmartPointer<vtkOutlineFilter> outline =
- vtkSmartPointer<vtkOutlineFilter>::New();
- outline->SetInputConnection(reader->GetOutputPort());
- vtkSmartPointer<vtkPolyDataMapper> outlineMapper =
- vtkSmartPointer<vtkPolyDataMapper>::New();
- outlineMapper->SetInputConnection(outline->GetOutputPort());
- vtkSmartPointer<vtkActor> outlineActor = vtkSmartPointer<vtkActor>::New();
- outlineActor->SetMapper(outlineMapper);
- vtkSmartPointer<vtkRenderer> ren[4];
- vtkSmartPointer<vtkRenderWindow> renWin =
- vtkSmartPointer<vtkRenderWindow>::New();
- renWin->SetMultiSamples(0);
- for (int i = 0; i < 4; i++)
- {
- ren[i] = vtkSmartPointer<vtkRenderer>::New();
- renWin->AddRenderer(ren[i]);
- }
- vtkSmartPointer<vtkRenderWindowInteractor> iren =
- vtkSmartPointer<vtkRenderWindowInteractor>::New();
- iren->SetRenderWindow(renWin);
- vtkSmartPointer<vtkCellPicker> picker = vtkSmartPointer<vtkCellPicker>::New();
- picker->SetTolerance(0.005);
- vtkSmartPointer<vtkProperty> ipwProp = vtkSmartPointer<vtkProperty>::New();
- // assign default props to the ipw's texture plane actor
- vtkSmartPointer<vtkImagePlaneWidget> planeWidget[3];
- int imageDims[3];
- reader->GetOutput()->GetDimensions(imageDims);
- for (int i = 0; i < 3; i++)
- {
- planeWidget[i] = vtkSmartPointer<vtkImagePlaneWidget>::New();
- planeWidget[i]->SetInteractor(iren);
- planeWidget[i]->SetPicker(picker);
- planeWidget[i]->RestrictPlaneToVolumeOn();
- double color[3] = {0, 0, 0};
- color[i] = 1;
- planeWidget[i]->GetPlaneProperty()->SetColor(color);
- planeWidget[i]->SetTexturePlaneProperty(ipwProp);
- planeWidget[i]->TextureInterpolateOff();
- planeWidget[i]->SetResliceInterpolateToLinear();
- planeWidget[i]->SetInputConnection(reader->GetOutputPort());
- planeWidget[i]->SetPlaneOrientation(i);
- planeWidget[i]->SetSliceIndex(imageDims[i] / 2);
- planeWidget[i]->DisplayTextOn();
- planeWidget[i]->SetDefaultRenderer(ren[3]);
- planeWidget[i]->SetWindowLevel(1358, -27);
- planeWidget[i]->On();
- planeWidget[i]->InteractionOn();
- }
- planeWidget[1]->SetLookupTable(planeWidget[0]->GetLookupTable());
- planeWidget[2]->SetLookupTable(planeWidget[0]->GetLookupTable());
- vtkSmartPointer<vtkResliceCursorCallback3> cbk =
- vtkSmartPointer<vtkResliceCursorCallback3>::New();
- // Create the reslice cursor, widget and rep
- vtkSmartPointer<vtkResliceCursor> resliceCursor =
- vtkSmartPointer<vtkResliceCursor>::New();
- resliceCursor->SetCenter(reader->GetOutput()->GetCenter());
- resliceCursor->SetThickMode(1);
- resliceCursor->SetThickness(10, 10, 10);
- resliceCursor->SetImage(reader->GetOutput());
- vtkSmartPointer<vtkResliceCursorWidget> resliceCursorWidget[3];
- vtkSmartPointer<vtkResliceCursorThickLineRepresentation> resliceCursorRep[3];
- double viewUp[3][3] = {{0, 0, -1}, {0, 0, 1}, {0, 1, 0}};
- for (int i = 0; i < 3; i++)
- {
- resliceCursorWidget[i] = vtkSmartPointer<vtkResliceCursorWidget>::New();
- resliceCursorWidget[i]->SetInteractor(iren);
- resliceCursorRep[i] =
- vtkSmartPointer<vtkResliceCursorThickLineRepresentation>::New();
- resliceCursorWidget[i]->SetRepresentation(resliceCursorRep[i]);
- resliceCursorRep[i]
- ->GetResliceCursorActor()
- ->GetCursorAlgorithm()
- ->SetResliceCursor(resliceCursor);
- resliceCursorRep[i]
- ->GetResliceCursorActor()
- ->GetCursorAlgorithm()
- ->SetReslicePlaneNormal(i);
- const double minVal = reader->GetOutput()->GetScalarRange()[0];
- if (vtkImageReslice* reslice =
- vtkImageReslice::SafeDownCast(resliceCursorRep[i]->GetReslice()))
- {
- reslice->SetBackgroundColor(minVal, minVal, minVal, minVal);
- }
- resliceCursorWidget[i]->SetDefaultRenderer(ren[i]);
- resliceCursorWidget[i]->SetEnabled(1);
- ren[i]->GetActiveCamera()->SetFocalPoint(0, 0, 0);
- double camPos[3] = {0, 0, 0};
- camPos[i] = 1;
- ren[i]->GetActiveCamera()->SetPosition(camPos);
- ren[i]->GetActiveCamera()->ParallelProjectionOn();
- ren[i]->GetActiveCamera()->SetViewUp(viewUp[i]);
- ren[i]->ResetCamera();
- // ren[i]->ResetCameraClippingRange();
- // Tie the Image plane widget and the reslice cursor widget together
- cbk->IPW[i] = planeWidget[i];
- cbk->RCW[i] = resliceCursorWidget[i];
- resliceCursorWidget[i]->AddObserver(
- vtkResliceCursorWidget::ResliceAxesChangedEvent, cbk);
- // Initialize the window level to a sensible value
- double range[2];
- reader->GetOutput()->GetScalarRange(range);
- resliceCursorRep[i]->SetWindowLevel(range[1] - range[0],
- (range[0] + range[1]) / 2.0);
- planeWidget[i]->SetWindowLevel(range[1] - range[0],
- (range[0] + range[1]) / 2.0);
- // Make them all share the same color map.
- resliceCursorRep[i]->SetLookupTable(resliceCursorRep[0]->GetLookupTable());
- planeWidget[i]->GetColorMap()->SetLookupTable(
- resliceCursorRep[0]->GetLookupTable());
- // clang-format off
- // Workaround VTK issue #18441
- // Make sure vtkResliceCursorActor is visible by forcing its representation to wireframe.
- // vtkResliceCursorActor is a quad with a normal parallel to the camera view up vector.
- // When represented as a surface, it has a thickness of 0 pixels. The class internally turns
- // edge visibility on to workaround the problem, which does not seem to be enough.
- resliceCursorRep[i]->GetResliceCursorActor()->GetCenterlineProperty(0)->SetRepresentationToWireframe();
- resliceCursorRep[i]->GetResliceCursorActor()->GetCenterlineProperty(1)->SetRepresentationToWireframe();
- resliceCursorRep[i]->GetResliceCursorActor()->GetCenterlineProperty(2)->SetRepresentationToWireframe();
- resliceCursorRep[i]->GetResliceCursorActor()->GetThickSlabProperty(0)->SetRepresentationToWireframe();
- resliceCursorRep[i]->GetResliceCursorActor()->GetThickSlabProperty(1)->SetRepresentationToWireframe();
- resliceCursorRep[i]->GetResliceCursorActor()->GetThickSlabProperty(2)->SetRepresentationToWireframe();
- // Workaround rendering artefacts with Intel chipsets and osmesa, where lines are rendered
- // black if perfectly aligned with the camera viewup (see #18453)
- resliceCursorRep[i]->GetResliceCursorActor()->GetCenterlineProperty(0)->RenderLinesAsTubesOn();
- resliceCursorRep[i]->GetResliceCursorActor()->GetCenterlineProperty(1)->RenderLinesAsTubesOn();
- resliceCursorRep[i]->GetResliceCursorActor()->GetCenterlineProperty(2)->RenderLinesAsTubesOn();
- resliceCursorRep[i]->GetResliceCursorActor()->GetCenterlineProperty(0)->SetLineWidth(2);
- resliceCursorRep[i]->GetResliceCursorActor()->GetCenterlineProperty(1)->SetLineWidth(2);
- resliceCursorRep[i]->GetResliceCursorActor()->GetCenterlineProperty(2)->SetLineWidth(2);
- resliceCursorRep[i]->GetResliceCursorActor()->GetThickSlabProperty(0)->RenderLinesAsTubesOn();
- resliceCursorRep[i]->GetResliceCursorActor()->GetThickSlabProperty(1)->RenderLinesAsTubesOn();
- resliceCursorRep[i]->GetResliceCursorActor()->GetThickSlabProperty(2)->RenderLinesAsTubesOn();
- resliceCursorRep[i]->GetResliceCursorActor()->GetThickSlabProperty(0)->SetLineWidth(2);
- resliceCursorRep[i]->GetResliceCursorActor()->GetThickSlabProperty(1)->SetLineWidth(2);
- resliceCursorRep[i]->GetResliceCursorActor()->GetThickSlabProperty(2)->SetLineWidth(2);
- // clang-format on
- }
- // Add the actors
- //
- ren[0]->SetBackground(0.3, 0.1, 0.1);
- ren[1]->SetBackground(0.1, 0.3, 0.1);
- ren[2]->SetBackground(0.1, 0.1, 0.3);
- ren[3]->AddActor(outlineActor);
- ren[3]->SetBackground(0.1, 0.1, 0.1);
- renWin->SetSize(600, 600);
- // renWin->SetFullScreen(1);
- ren[0]->SetViewport(0, 0, 0.5, 0.5);
- ren[1]->SetViewport(0.5, 0, 1, 0.5);
- ren[2]->SetViewport(0, 0.5, 0.5, 1);
- ren[3]->SetViewport(0.5, 0.5, 1, 1);
- // Set the actors' positions
- //
- renWin->Render();
- ren[3]->GetActiveCamera()->Elevation(110);
- ren[3]->GetActiveCamera()->SetViewUp(0, 0, -1);
- ren[3]->GetActiveCamera()->Azimuth(45);
- ren[3]->GetActiveCamera()->Dolly(1.15);
- ren[3]->ResetCameraClippingRange();
- vtkSmartPointer<vtkInteractorStyleImage> style =
- vtkSmartPointer<vtkInteractorStyleImage>::New();
- iren->SetInteractorStyle(style);
- iren->Initialize();
- iren->Start();
- return 1;
- }
复制代码
|
|