ResetView and fitwindow for volume rendering.
This commit is contained in:
@@ -17,8 +17,23 @@
|
|||||||
#include <vtkPiecewiseFunction.h>
|
#include <vtkPiecewiseFunction.h>
|
||||||
#include <vtkColorTransferFunction.h>
|
#include <vtkColorTransferFunction.h>
|
||||||
#include <vtkCornerAnnotation.h>
|
#include <vtkCornerAnnotation.h>
|
||||||
|
#include <vtkPlane.h>
|
||||||
|
#include <vtkBoundingBox.h>
|
||||||
|
|
||||||
|
|
||||||
#include "Interaction/VolumeInteractorStyle.h"
|
#include "Interaction/VolumeInteractorStyle.h"
|
||||||
|
#include "IO/DICOM/ExtendMedicalImageProperties.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
enum ViewDirection{
|
||||||
|
Anterior,
|
||||||
|
Posterior,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Superior,
|
||||||
|
Inferior
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
vtkStandardNewMacro(VolumeRenderingViewer);
|
vtkStandardNewMacro(VolumeRenderingViewer);
|
||||||
|
|
||||||
@@ -30,7 +45,8 @@ VolumeRenderingViewer::VolumeRenderingViewer()
|
|||||||
, annotation(vtkCornerAnnotation::New())
|
, annotation(vtkCornerAnnotation::New())
|
||||||
, VolumeMapper(vtkFixedPointVolumeRayCastMapper::New())
|
, VolumeMapper(vtkFixedPointVolumeRayCastMapper::New())
|
||||||
, InteractorStyle(nullptr)
|
, InteractorStyle(nullptr)
|
||||||
, Interactor(nullptr){
|
, Interactor(nullptr)
|
||||||
|
, firstRender(true){
|
||||||
if (gpuMode){
|
if (gpuMode){
|
||||||
auto mapper = vtkGPUVolumeRayCastMapper::New();
|
auto mapper = vtkGPUVolumeRayCastMapper::New();
|
||||||
mapper->SetUseJittering(1);
|
mapper->SetUseJittering(1);
|
||||||
@@ -42,19 +58,21 @@ VolumeRenderingViewer::VolumeRenderingViewer()
|
|||||||
//设置线程数为核心数的两倍,为了可能用到超线程技术
|
//设置线程数为核心数的两倍,为了可能用到超线程技术
|
||||||
mapper->SetNumberOfThreads(2*mapper->GetNumberOfThreads());
|
mapper->SetNumberOfThreads(2*mapper->GetNumberOfThreads());
|
||||||
mapper->SetAutoAdjustSampleDistances(1);
|
mapper->SetAutoAdjustSampleDistances(1);
|
||||||
mapper->SetSampleDistance(1.0);
|
mapper->SetSampleDistance(0.25);
|
||||||
mapper->SetMaximumImageSampleDistance(4.0);
|
mapper->SetMaximumImageSampleDistance(4.0);
|
||||||
mapper->SetMinimumImageSampleDistance(1.0);
|
mapper->SetMinimumImageSampleDistance(1.0);
|
||||||
}
|
}
|
||||||
vtkNew<vtkColorTransferFunction> colorFun;
|
vtkNew<vtkColorTransferFunction> colorFun;
|
||||||
colorFun->SetScaleToLinear();
|
colorFun->SetScaleToLinear();
|
||||||
colorFun->AddRGBPoint(100.0,0.5,0.25,0.125);
|
colorFun->AddRGBPoint(110.0,0.0,0.0,0.0);
|
||||||
colorFun->AddRGBPoint(200.0,1.0,0.9,0.6);
|
colorFun->AddRGBPoint(121.0,0.5,0.25,0.125);
|
||||||
colorFun->AddRGBPoint(300.0,1.0,1.0,1.0);
|
|
||||||
|
colorFun->AddRGBPoint(453.0,1.0,1,1);
|
||||||
vtkNew<vtkPiecewiseFunction> opacityFun;
|
vtkNew<vtkPiecewiseFunction> opacityFun;
|
||||||
opacityFun->AddPoint(100.0, 0.0);
|
opacityFun->AddPoint(120.5, 0.0);
|
||||||
opacityFun->AddPoint(125.0, 0.5);
|
// opacityFun->AddPoint(121.0, 1.0);
|
||||||
opacityFun->AddPoint(200.0, 1.0);
|
// opacityFun->AddPoint(287.0, 1.0);
|
||||||
|
opacityFun->AddPoint(453.5, 1.0);
|
||||||
|
|
||||||
vtkNew<vtkVolumeProperty> volumeProperty;
|
vtkNew<vtkVolumeProperty> volumeProperty;
|
||||||
volumeProperty->ShadeOn();
|
volumeProperty->ShadeOn();
|
||||||
@@ -63,10 +81,10 @@ VolumeRenderingViewer::VolumeRenderingViewer()
|
|||||||
volumeProperty->SetScalarOpacity(opacityFun);
|
volumeProperty->SetScalarOpacity(opacityFun);
|
||||||
volumeProperty->SetScalarOpacityUnitDistance(1.0);
|
volumeProperty->SetScalarOpacityUnitDistance(1.0);
|
||||||
|
|
||||||
volumeProperty->SetAmbient(0.2);
|
volumeProperty->SetAmbient(0.1);
|
||||||
volumeProperty->SetDiffuse(0.7);
|
volumeProperty->SetDiffuse(0.7);
|
||||||
volumeProperty->SetSpecular(0.3);
|
volumeProperty->SetSpecular(0.2);
|
||||||
volumeProperty->SetSpecularPower(8.0);
|
volumeProperty->SetSpecularPower(10.0);
|
||||||
VolumeActor->SetProperty(volumeProperty);
|
VolumeActor->SetProperty(volumeProperty);
|
||||||
VolumeActor->SetMapper(VolumeMapper);
|
VolumeActor->SetMapper(VolumeMapper);
|
||||||
}
|
}
|
||||||
@@ -219,15 +237,16 @@ void VolumeRenderingViewer::SetRenderer(vtkRenderer *arg) {
|
|||||||
|
|
||||||
void VolumeRenderingViewer::Render() {
|
void VolumeRenderingViewer::Render() {
|
||||||
if (RenderWindow && Interactor){
|
if (RenderWindow && Interactor){
|
||||||
|
if (firstRender){
|
||||||
|
firstRender = false;
|
||||||
|
SetViewDirection(0);
|
||||||
|
}
|
||||||
Interactor->Render();
|
Interactor->Render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VolumeRenderingViewer::SetInputData(vtkImageData *in) {
|
void VolumeRenderingViewer::SetInputData(vtkImageData *in) {
|
||||||
if (in && in != this->VolumeMapper->GetInput()){
|
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);
|
this->VolumeMapper->SetInputData(in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,3 +270,102 @@ void VolumeRenderingViewer::SetInteractorStyleMode(int mode) {
|
|||||||
style->SetInteractionMode(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();
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
#define OMEGAV_VOLUMERENDERINGVIEWER_H
|
#define OMEGAV_VOLUMERENDERINGVIEWER_H
|
||||||
|
|
||||||
#include "vtkObject.h"
|
#include "vtkObject.h"
|
||||||
|
#include "vtkNew.h"
|
||||||
|
#include "vtkMatrix4x4.h"
|
||||||
|
|
||||||
class vtkAlgorithm;
|
class vtkAlgorithm;
|
||||||
|
|
||||||
class vtkImageData;
|
class vtkImageData;
|
||||||
@@ -27,6 +30,8 @@ class vtkVolumeMapper;
|
|||||||
|
|
||||||
class vtkCornerAnnotation;
|
class vtkCornerAnnotation;
|
||||||
|
|
||||||
|
class ExtendMedicalImageProperties;
|
||||||
|
|
||||||
class VolumeRenderingViewer:public vtkObject {
|
class VolumeRenderingViewer:public vtkObject {
|
||||||
public:
|
public:
|
||||||
static VolumeRenderingViewer *New();
|
static VolumeRenderingViewer *New();
|
||||||
@@ -43,6 +48,8 @@ public:
|
|||||||
|
|
||||||
virtual vtkImageData *GetInput();
|
virtual vtkImageData *GetInput();
|
||||||
|
|
||||||
|
void SetCoordsTransformMatrix(ExtendMedicalImageProperties *pSeries);
|
||||||
|
|
||||||
//@{
|
//@{
|
||||||
/**
|
/**
|
||||||
* Get the internal render window, renderer, image actor, and
|
* Get the internal render window, renderer, image actor, and
|
||||||
@@ -70,15 +77,24 @@ public:
|
|||||||
|
|
||||||
void SetInteractorStyleMode(int mode);
|
void SetInteractorStyleMode(int mode);
|
||||||
|
|
||||||
|
void SetViewDirection(int direction);
|
||||||
|
|
||||||
|
void ResetViewDirection(){
|
||||||
|
SetViewDirection(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetView(){
|
||||||
|
ResetViewDirection();
|
||||||
|
ResetZoomFitWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetZoomFitWindow();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
VolumeRenderingViewer();
|
VolumeRenderingViewer();
|
||||||
|
|
||||||
~VolumeRenderingViewer() override;
|
~VolumeRenderingViewer() override;
|
||||||
|
|
||||||
// vtkAlgorithm *GetInputAlgorithm();
|
|
||||||
//
|
|
||||||
// vtkInformation *GetInputInformation();
|
|
||||||
|
|
||||||
virtual void InstallPipeline();
|
virtual void InstallPipeline();
|
||||||
|
|
||||||
virtual void UnInstallPipeline();
|
virtual void UnInstallPipeline();
|
||||||
@@ -96,7 +112,9 @@ private:
|
|||||||
vtkInteractorStyle *InteractorStyle;
|
vtkInteractorStyle *InteractorStyle;
|
||||||
vtkRenderWindowInteractor *Interactor;
|
vtkRenderWindowInteractor *Interactor;
|
||||||
vtkCornerAnnotation* annotation;
|
vtkCornerAnnotation* annotation;
|
||||||
|
vtkNew<vtkMatrix4x4> OrientationMatrix;
|
||||||
bool gpuMode = false;
|
bool gpuMode = false;
|
||||||
|
bool firstRender = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,10 +6,15 @@
|
|||||||
|
|
||||||
#include <QToolButton>
|
#include <QToolButton>
|
||||||
#include <QButtonGroup>
|
#include <QButtonGroup>
|
||||||
|
#include <QActionGroup>
|
||||||
|
#include <QMenu>
|
||||||
|
|
||||||
VolumeRenderingToolBar::VolumeRenderingToolBar(QWidget *parent) : QToolBar(parent) {
|
VolumeRenderingToolBar::VolumeRenderingToolBar(QWidget *parent) : QToolBar(parent) {
|
||||||
auto btnReset = new QToolButton(this);
|
auto btnReset = new QToolButton(this);
|
||||||
addButton(btnReset, "reset");
|
addButton(btnReset, "reset");
|
||||||
|
connect(btnReset,&QToolButton::clicked,[=](){
|
||||||
|
emit resetView();
|
||||||
|
});
|
||||||
|
|
||||||
auto mBtnAnonymize = new QToolButton(this);
|
auto mBtnAnonymize = new QToolButton(this);
|
||||||
addButton(mBtnAnonymize, "anonymize");
|
addButton(mBtnAnonymize, "anonymize");
|
||||||
@@ -21,6 +26,24 @@ VolumeRenderingToolBar::VolumeRenderingToolBar(QWidget *parent) : QToolBar(paren
|
|||||||
addButton(btnFreeRotate, "freeRotate");
|
addButton(btnFreeRotate, "freeRotate");
|
||||||
btnFreeRotate->setCheckable(true);
|
btnFreeRotate->setCheckable(true);
|
||||||
btnFreeRotate->setChecked(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);
|
auto btnRotate = new QToolButton(this);
|
||||||
addButton(btnRotate, "planeRotate");
|
addButton(btnRotate, "planeRotate");
|
||||||
btnRotate->setCheckable(true);
|
btnRotate->setCheckable(true);
|
||||||
@@ -29,6 +52,15 @@ VolumeRenderingToolBar::VolumeRenderingToolBar(QWidget *parent) : QToolBar(paren
|
|||||||
btnPan->setCheckable(true);
|
btnPan->setCheckable(true);
|
||||||
auto btnZoom = new QToolButton(this);
|
auto btnZoom = new QToolButton(this);
|
||||||
addButton(btnZoom, "zoom");
|
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);
|
btnZoom->setCheckable(true);
|
||||||
auto btnWindow = new QToolButton(this);
|
auto btnWindow = new QToolButton(this);
|
||||||
addButton(btnWindow, "window");
|
addButton(btnWindow, "window");
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ public:
|
|||||||
~VolumeRenderingToolBar() override;
|
~VolumeRenderingToolBar() override;
|
||||||
signals:
|
signals:
|
||||||
void modeButtonClicked(int id);
|
void modeButtonClicked(int id);
|
||||||
|
void viewDirectionChanged(int id);
|
||||||
|
void resetView();
|
||||||
|
void fitWindow();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QAction* addButton(QToolButton* button, const char* objectName);
|
QAction* addButton(QToolButton* button, const char* objectName);
|
||||||
|
|||||||
@@ -37,19 +37,31 @@ VolumeRenderingWindow::VolumeRenderingWindow(QWidget *parent , Qt::WindowFlags f
|
|||||||
layout->addWidget(widget);
|
layout->addWidget(widget);
|
||||||
setMinimumSize(680,500);
|
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){
|
connect(toolBar, &VolumeRenderingToolBar::modeButtonClicked,[=](int mode){
|
||||||
printf("mode:%d \r\n", mode);
|
|
||||||
mViewer->SetInteractorStyleMode(mode);
|
mViewer->SetInteractorStyleMode(mode);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(toolBar, &VolumeRenderingToolBar::viewDirectionChanged, [=](int direction){
|
||||||
|
mViewer->SetViewDirection(direction);
|
||||||
|
mViewer->Render();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
VolumeRenderingWindow::~VolumeRenderingWindow() {
|
VolumeRenderingWindow::~VolumeRenderingWindow() {
|
||||||
mViewer->Delete();
|
mViewer->Delete();
|
||||||
qDebug() << "delete VolumeRenderingWindow";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VolumeRenderingWindow::loadData(SeriesImageSet* series){
|
void VolumeRenderingWindow::loadData(SeriesImageSet* series){
|
||||||
mViewer->SetupInteractor(mRenderWin->GetInteractor());
|
mViewer->SetupInteractor(mRenderWin->GetInteractor());
|
||||||
mViewer->SetInputData(series->GetData());
|
mViewer->SetInputData(series->GetData());
|
||||||
|
mViewer->SetCoordsTransformMatrix(series->GetProperty());
|
||||||
mViewer->Render();
|
mViewer->Render();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user