ResetView and fitwindow for volume rendering.

This commit is contained in:
Krad
2022-08-26 10:05:09 +08:00
parent ea04c5e9a0
commit b909435490
5 changed files with 203 additions and 20 deletions

View File

@@ -17,8 +17,23 @@
#include <vtkPiecewiseFunction.h>
#include <vtkColorTransferFunction.h>
#include <vtkCornerAnnotation.h>
#include <vtkPlane.h>
#include <vtkBoundingBox.h>
#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<vtkColorTransferFunction> 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<vtkPiecewiseFunction> 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<vtkVolumeProperty> 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();
}

View File

@@ -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<vtkMatrix4x4> OrientationMatrix;
bool gpuMode = false;
bool firstRender = true;
};

View File

@@ -6,10 +6,15 @@
#include <QToolButton>
#include <QButtonGroup>
#include <QActionGroup>
#include <QMenu>
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");

View File

@@ -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);

View File

@@ -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();
}