diff --git a/src/src/Rendering/Viewer/VolumeRenderingViewer.cpp b/src/src/Rendering/Viewer/VolumeRenderingViewer.cpp index 34c6c6d..790cf4e 100644 --- a/src/src/Rendering/Viewer/VolumeRenderingViewer.cpp +++ b/src/src/Rendering/Viewer/VolumeRenderingViewer.cpp @@ -17,8 +17,23 @@ #include #include #include +#include +#include + #include "Interaction/VolumeInteractorStyle.h" +#include "IO/DICOM/ExtendMedicalImageProperties.h" + +namespace { + enum ViewDirection{ + Anterior, + Posterior, + Left, + Right, + Superior, + Inferior + }; +} vtkStandardNewMacro(VolumeRenderingViewer); @@ -30,7 +45,8 @@ VolumeRenderingViewer::VolumeRenderingViewer() , annotation(vtkCornerAnnotation::New()) , VolumeMapper(vtkFixedPointVolumeRayCastMapper::New()) , InteractorStyle(nullptr) -, Interactor(nullptr){ +, Interactor(nullptr) +, firstRender(true){ if (gpuMode){ auto mapper = vtkGPUVolumeRayCastMapper::New(); mapper->SetUseJittering(1); @@ -42,19 +58,21 @@ VolumeRenderingViewer::VolumeRenderingViewer() //设置线程数为核心数的两倍,为了可能用到超线程技术 mapper->SetNumberOfThreads(2*mapper->GetNumberOfThreads()); mapper->SetAutoAdjustSampleDistances(1); - mapper->SetSampleDistance(1.0); + mapper->SetSampleDistance(0.25); mapper->SetMaximumImageSampleDistance(4.0); mapper->SetMinimumImageSampleDistance(1.0); } vtkNew colorFun; colorFun->SetScaleToLinear(); - colorFun->AddRGBPoint(100.0,0.5,0.25,0.125); - colorFun->AddRGBPoint(200.0,1.0,0.9,0.6); - colorFun->AddRGBPoint(300.0,1.0,1.0,1.0); + colorFun->AddRGBPoint(110.0,0.0,0.0,0.0); + colorFun->AddRGBPoint(121.0,0.5,0.25,0.125); + + colorFun->AddRGBPoint(453.0,1.0,1,1); vtkNew opacityFun; - opacityFun->AddPoint(100.0, 0.0); - opacityFun->AddPoint(125.0, 0.5); - opacityFun->AddPoint(200.0, 1.0); + opacityFun->AddPoint(120.5, 0.0); +// opacityFun->AddPoint(121.0, 1.0); +// opacityFun->AddPoint(287.0, 1.0); + opacityFun->AddPoint(453.5, 1.0); vtkNew volumeProperty; volumeProperty->ShadeOn(); @@ -63,10 +81,10 @@ VolumeRenderingViewer::VolumeRenderingViewer() volumeProperty->SetScalarOpacity(opacityFun); volumeProperty->SetScalarOpacityUnitDistance(1.0); - volumeProperty->SetAmbient(0.2); + volumeProperty->SetAmbient(0.1); volumeProperty->SetDiffuse(0.7); - volumeProperty->SetSpecular(0.3); - volumeProperty->SetSpecularPower(8.0); + volumeProperty->SetSpecular(0.2); + volumeProperty->SetSpecularPower(10.0); VolumeActor->SetProperty(volumeProperty); VolumeActor->SetMapper(VolumeMapper); } @@ -219,15 +237,16 @@ void VolumeRenderingViewer::SetRenderer(vtkRenderer *arg) { void VolumeRenderingViewer::Render() { if (RenderWindow && Interactor){ + if (firstRender){ + firstRender = false; + SetViewDirection(0); + } Interactor->Render(); } } void VolumeRenderingViewer::SetInputData(vtkImageData *in) { if (in && in != this->VolumeMapper->GetInput()){ - double spacing[3]={0.0, 0.0, 0.0}; - in->GetSpacing(spacing); - printf("set input, spacing: %f, %f, %f\r\n", spacing[0], spacing[1], spacing[2]); this->VolumeMapper->SetInputData(in); } } @@ -251,3 +270,102 @@ void VolumeRenderingViewer::SetInteractorStyleMode(int mode) { style->SetInteractionMode(mode); } } + +void VolumeRenderingViewer::SetCoordsTransformMatrix(ExtendMedicalImageProperties *pSeries) { + OrientationMatrix->DeepCopy(pSeries->GetOrientationMatrix()); + //change to WToM + OrientationMatrix->Invert(); +} + +void VolumeRenderingViewer::SetViewDirection(int direction) { + double position[4] = {.0, .0, .0, 1.}; + double ViewUp[4] = {.0, .0, .0, 1.}; + switch (direction){ + case Anterior:{ + position[1] = -1.0; + ViewUp[2] = 1.0; + break; + } + case Posterior:{ + position[1] = 1.0; + ViewUp[2] = 1.0; + break; + } + case Left:{ + position[0] = 1.0; + ViewUp[2] = 1.0; + break; + } + case Right:{ + position[0] = -1.0; + ViewUp[2] = 1.0; + break; + } + case Superior:{ + position[2] = 1.0; + ViewUp[1] = 1.0; + break; + } + case Inferior:{ + position[2] = -1.0; + ViewUp[1] = -1.0; + break; + } + } + OrientationMatrix->MultiplyPoint(position,position); + OrientationMatrix->MultiplyPoint(ViewUp,ViewUp); + vtkCamera* camera = Renderer->GetActiveCamera(); + camera->SetFocalPoint(.0, .0, .0); + camera->SetPosition(position); + camera->SetViewUp(ViewUp); + Renderer->ResetCamera(); +} + +void VolumeRenderingViewer::ResetZoomFitWindow() { + auto data = VolumeMapper->GetInput(); + if (!data) return; + double* bounds = data->GetBounds(); + vtkBoundingBox boundingBox; + boundingBox.SetBounds(bounds); + double center[3]={0}; + boundingBox.GetCenter(center); + auto camera = Renderer->GetActiveCamera(); + double projNorm[3] = {.0, .0, .0}; + camera->ComputeViewPlaneNormal(); + camera->GetViewPlaneNormal(projNorm); + //move view projection to pass center, without projection normal change + double distance = camera->GetDistance(); + camera->SetFocalPoint(center); + camera->SetPosition(center[0]+projNorm[0]*distance, + center[1]+projNorm[1]*distance, + center[2]+projNorm[2]*distance); + //use display point to cal dolly factor + double halfDisX = 0.0; + double halfDisY = 0.0; + double projOnPlane[3] ={.0}; + for (int i = 0; i < 8; ++i) { + double corner[3] = {0}; + boundingBox.GetCorner(i, corner); + Renderer->SetWorldPoint(corner); + Renderer->WorldToView(); + Renderer->GetViewPoint(corner); + if (fabs(corner[0]) > halfDisX){ + halfDisX = fabs(corner[0]); + } + if (fabs(corner[1]) > halfDisY){ + halfDisY = fabs(corner[1]); + } + } + + double *aspect = Renderer->GetAspect(); + double volumeAspect = halfDisX/halfDisY; + if (volumeAspect>aspect[0]){ + camera->Dolly(0.99/halfDisX); + } + else{ + //use 1.97 to avoid border out of screen + camera->Dolly(0.99/halfDisY); + } + + Renderer->ResetCameraClippingRange(); +} diff --git a/src/src/Rendering/Viewer/VolumeRenderingViewer.h b/src/src/Rendering/Viewer/VolumeRenderingViewer.h index 510f0ec..9a1a566 100644 --- a/src/src/Rendering/Viewer/VolumeRenderingViewer.h +++ b/src/src/Rendering/Viewer/VolumeRenderingViewer.h @@ -6,6 +6,9 @@ #define OMEGAV_VOLUMERENDERINGVIEWER_H #include "vtkObject.h" +#include "vtkNew.h" +#include "vtkMatrix4x4.h" + class vtkAlgorithm; class vtkImageData; @@ -27,6 +30,8 @@ class vtkVolumeMapper; class vtkCornerAnnotation; +class ExtendMedicalImageProperties; + class VolumeRenderingViewer:public vtkObject { public: static VolumeRenderingViewer *New(); @@ -43,6 +48,8 @@ public: virtual vtkImageData *GetInput(); + void SetCoordsTransformMatrix(ExtendMedicalImageProperties *pSeries); + //@{ /** * Get the internal render window, renderer, image actor, and @@ -70,15 +77,24 @@ public: void SetInteractorStyleMode(int mode); + void SetViewDirection(int direction); + + void ResetViewDirection(){ + SetViewDirection(0); + } + + void ResetView(){ + ResetViewDirection(); + ResetZoomFitWindow(); + } + + void ResetZoomFitWindow(); + protected: VolumeRenderingViewer(); ~VolumeRenderingViewer() override; -// vtkAlgorithm *GetInputAlgorithm(); -// -// vtkInformation *GetInputInformation(); - virtual void InstallPipeline(); virtual void UnInstallPipeline(); @@ -96,7 +112,9 @@ private: vtkInteractorStyle *InteractorStyle; vtkRenderWindowInteractor *Interactor; vtkCornerAnnotation* annotation; + vtkNew OrientationMatrix; bool gpuMode = false; + bool firstRender = true; }; diff --git a/src/src/UI/Widget/ToolBar/VolumeRenderingToolBar.cpp b/src/src/UI/Widget/ToolBar/VolumeRenderingToolBar.cpp index 53752be..7c94b00 100644 --- a/src/src/UI/Widget/ToolBar/VolumeRenderingToolBar.cpp +++ b/src/src/UI/Widget/ToolBar/VolumeRenderingToolBar.cpp @@ -6,10 +6,15 @@ #include #include +#include +#include VolumeRenderingToolBar::VolumeRenderingToolBar(QWidget *parent) : QToolBar(parent) { auto btnReset = new QToolButton(this); addButton(btnReset, "reset"); + connect(btnReset,&QToolButton::clicked,[=](){ + emit resetView(); + }); auto mBtnAnonymize = new QToolButton(this); addButton(mBtnAnonymize, "anonymize"); @@ -21,6 +26,24 @@ VolumeRenderingToolBar::VolumeRenderingToolBar(QWidget *parent) : QToolBar(paren addButton(btnFreeRotate, "freeRotate"); btnFreeRotate->setCheckable(true); btnFreeRotate->setChecked(true); + auto menu = new QMenu(this); + auto actionGroup = new QActionGroup(this); + actionGroup->addAction(menu->addAction(tr("Anterior"))); + actionGroup->addAction(menu->addAction(tr("Posterior"))); + actionGroup->addAction(menu->addAction(tr("Left"))); + actionGroup->addAction(menu->addAction(tr("Right"))); + actionGroup->addAction(menu->addAction(tr("Superior"))); + actionGroup->addAction(menu->addAction(tr("Inferior"))); + + connect(actionGroup, &QActionGroup::triggered,[=](QAction* action){ + int idx = actionGroup->actions().indexOf(action); + emit viewDirectionChanged(idx); + }); + btnFreeRotate->setMenu(menu); + btnFreeRotate->setPopupMode(QToolButton::MenuButtonPopup); + btnFreeRotate->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + btnFreeRotate->setToolTip(tr("3D Rotate")); + auto btnRotate = new QToolButton(this); addButton(btnRotate, "planeRotate"); btnRotate->setCheckable(true); @@ -29,6 +52,15 @@ VolumeRenderingToolBar::VolumeRenderingToolBar(QWidget *parent) : QToolBar(paren btnPan->setCheckable(true); auto btnZoom = new QToolButton(this); addButton(btnZoom, "zoom"); + menu = new QMenu(this); + btnZoom->setMenu(menu); + btnZoom->setPopupMode(QToolButton::MenuButtonPopup); + btnZoom->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + btnZoom->setToolTip(tr("Zoom")); + menu->addAction(tr("Fit window"),[=](){ + emit fitWindow(); + }); + btnZoom->setCheckable(true); auto btnWindow = new QToolButton(this); addButton(btnWindow, "window"); diff --git a/src/src/UI/Widget/ToolBar/VolumeRenderingToolBar.h b/src/src/UI/Widget/ToolBar/VolumeRenderingToolBar.h index 756f23d..4282ba3 100644 --- a/src/src/UI/Widget/ToolBar/VolumeRenderingToolBar.h +++ b/src/src/UI/Widget/ToolBar/VolumeRenderingToolBar.h @@ -17,6 +17,9 @@ public: ~VolumeRenderingToolBar() override; signals: void modeButtonClicked(int id); + void viewDirectionChanged(int id); + void resetView(); + void fitWindow(); private: QAction* addButton(QToolButton* button, const char* objectName); diff --git a/src/src/UI/Window/VolumeRenderingWindow.cpp b/src/src/UI/Window/VolumeRenderingWindow.cpp index aae266b..7b5071f 100644 --- a/src/src/UI/Window/VolumeRenderingWindow.cpp +++ b/src/src/UI/Window/VolumeRenderingWindow.cpp @@ -37,19 +37,31 @@ VolumeRenderingWindow::VolumeRenderingWindow(QWidget *parent , Qt::WindowFlags f layout->addWidget(widget); setMinimumSize(680,500); + connect(toolBar, &VolumeRenderingToolBar::resetView,[=](){ + mViewer->ResetView(); + mViewer->Render(); + }); + connect(toolBar, &VolumeRenderingToolBar::fitWindow,[=](){ + mViewer->ResetZoomFitWindow(); + mViewer->Render(); + }); connect(toolBar, &VolumeRenderingToolBar::modeButtonClicked,[=](int mode){ - printf("mode:%d \r\n", mode); mViewer->SetInteractorStyleMode(mode); }); + + connect(toolBar, &VolumeRenderingToolBar::viewDirectionChanged, [=](int direction){ + mViewer->SetViewDirection(direction); + mViewer->Render(); + }); } VolumeRenderingWindow::~VolumeRenderingWindow() { mViewer->Delete(); - qDebug() << "delete VolumeRenderingWindow"; } void VolumeRenderingWindow::loadData(SeriesImageSet* series){ mViewer->SetupInteractor(mRenderWin->GetInteractor()); mViewer->SetInputData(series->GetData()); + mViewer->SetCoordsTransformMatrix(series->GetProperty()); mViewer->Render(); }