医学四视图-002-四视图实现
Posted DreamLife.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了医学四视图-002-四视图实现相关的知识,希望对你有一定的参考价值。
本篇文章将参考大神们的足迹,模仿这实现四视图。
1 参考资料
其实说四视图是不是很不专业,是不是应该叫多平面重建及三维切片显示呀。参考资料如下:
参考:https://blog.csdn.net/hit1524468/article/details/113446783
https://www.cnblogs.com/fuzhuoxin/p/12513872.html
https://blog.csdn.net/weixin_38500110/article/details/78807196
2 参考代码
#ifndef QtVTKRenderWindows_H
#define QtVTKRenderWindows_H
#include "vtkSmartPointer.h"
#include "vtkResliceImageViewer.h"
#include "vtkImagePlaneWidget.h"
#include "vtkDistanceWidget.h"
#include "vtkResliceImageViewerMeasurements.h"
#include <QMainWindow>
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkInteractionStyle)
VTK_MODULE_INIT(vtkRenderingFreeType)
// Forward Qt class declarations
class Ui_QtVTKRenderWindows;
class QtVTKRenderWindows : public QMainWindow
{
Q_OBJECT
public:
// Constructor/Destructor
QtVTKRenderWindows(int argc, char *argv[]);
~QtVTKRenderWindows() override {}
public slots:
virtual void slotExit();
virtual void resliceMode(int);
virtual void thickMode(int);
virtual void SetBlendModeToMaxIP();
virtual void SetBlendModeToMinIP();
virtual void SetBlendModeToMeanIP();
virtual void SetBlendMode(int);
virtual void ResetViews();
virtual void Render();
virtual void AddDistanceMeasurementToView1();
virtual void AddDistanceMeasurementToView( int );
protected:
vtkSmartPointer< vtkResliceImageViewer > riw[3];
vtkSmartPointer< vtkImagePlaneWidget > planeWidget[3];
vtkSmartPointer< vtkDistanceWidget > DistanceWidget[3];
vtkSmartPointer< vtkResliceImageViewerMeasurements > ResliceMeasurements;
protected slots:
private:
// Designer form
Ui_QtVTKRenderWindows *ui;
};
#endif // QtVTKRenderWindows_H
#include "ui_QtVTKRenderWindows.h"
#include "QtVTKRenderWindows.h"
#include "vtkBoundedPlanePointPlacer.h"
#include "vtkCellPicker.h"
#include "vtkCommand.h"
#include "vtkDICOMImageReader.h"
#include "vtkDistanceRepresentation.h"
#include "vtkDistanceRepresentation2D.h"
#include "vtkDistanceWidget.h"
#include <vtkGenericOpenGLRenderWindow.h>
#include "vtkHandleRepresentation.h"
#include "vtkImageData.h"
#include "vtkImageMapToWindowLevelColors.h"
#include "vtkImageSlabReslice.h"
#include "vtkInteractorStyleImage.h"
#include "vtkLookupTable.h"
#include "vtkPlane.h"
#include "vtkPlaneSource.h"
#include "vtkPointHandleRepresentation2D.h"
#include "vtkPointHandleRepresentation3D.h"
#include "vtkProperty.h"
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include "vtkRenderWindowInteractor.h"
#include "vtkResliceImageViewer.h"
#include "vtkResliceCursorLineRepresentation.h"
#include "vtkResliceCursorThickLineRepresentation.h"
#include "vtkResliceCursorWidget.h"
#include "vtkResliceCursorActor.h"
#include "vtkResliceCursorPolyDataAlgorithm.h"
#include "vtkResliceCursor.h"
#include "vtkMetaImageReader.h"
#include "vtkResliceImageViewerMeasurements.h"
//----------------------------------------------------------------------------
class vtkResliceCursorCallback : public vtkCommand
{
public:
static vtkResliceCursorCallback *New()
{ return new vtkResliceCursorCallback; }
void Execute( vtkObject *caller, unsigned long ev,
void *callData ) override
{
if (ev == vtkResliceCursorWidget::WindowLevelEvent ||
ev == vtkCommand::WindowLevelEvent ||
ev == vtkResliceCursorWidget::ResliceThicknessChangedEvent)
{
// Render everything
for (int i = 0; i < 3; i++)
{
this->RCW[i]->Render();
}
this->IPW[0]->GetInteractor()->GetRenderWindow()->Render();
return;
}
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());
// Although the return value is not used, we keep the get calls
// in case they had side-effects
rep->GetResliceCursorActor()->GetCursorAlgorithm()->GetResliceCursor();
for (int i = 0; i < 3; i++)
{
vtkPlaneSource *ps = static_cast< vtkPlaneSource * >(
this->IPW[i]->GetPolyDataAlgorithm());
ps->SetOrigin(this->RCW[i]->GetResliceCursorRepresentation()->
GetPlaneSource()->GetOrigin());
ps->SetPoint1(this->RCW[i]->GetResliceCursorRepresentation()->
GetPlaneSource()->GetPoint1());
ps->SetPoint2(this->RCW[i]->GetResliceCursorRepresentation()->
GetPlaneSource()->GetPoint2());
// If the reslice plane has modified, update it on the 3D widget
this->IPW[i]->UpdatePlacement();
}
}
// Render everything
for (int i = 0; i < 3; i++)
{
this->RCW[i]->Render();
}
this->IPW[0]->GetInteractor()->GetRenderWindow()->Render();
}
vtkResliceCursorCallback() {}
vtkImagePlaneWidget* IPW[3];
vtkResliceCursorWidget *RCW[3];
};
QtVTKRenderWindows::QtVTKRenderWindows( int vtkNotUsed(argc), char *argv[])
{
this->ui = new Ui_QtVTKRenderWindows;
this->ui->setupUi(this);
#if 0
vtkSmartPointer< vtkDICOMImageReader > reader = vtkSmartPointer<vtkDICOMImageReader >::New();
// reader->SetDirectoryName(argv[1]);
reader->SetDirectoryName("/home/hsw/Qt_workSpace/build-RSVtkLearn_FourPaneViewer-Desktop_Qt_5_12_2_GCC_64bit-Debug/DCM/");
#else
vtkSmartPointer<vtkMetaImageReader> reader = vtkSmartPointer<vtkMetaImageReader>::New();
reader->SetFileName("/home/hsw/Downloads/brain/brain.mhd");
#endif
reader->Update();
int imageDims[3];
reader->GetOutput()->GetDimensions(imageDims);
for (int i = 0; i < 3; i++)
{
riw[i] = vtkSmartPointer< vtkResliceImageViewer >::New();
vtkNew<vtkGenericOpenGLRenderWindow> renderWindow;
riw[i]->SetRenderWindow(renderWindow);
}
this->ui->view1->SetRenderWindow(riw[0]->GetRenderWindow());
riw[0]->SetupInteractor(this->ui->view1->GetRenderWindow()->GetInteractor());
this->ui->view2->SetRenderWindow(riw[1]->GetRenderWindow());
riw[1]->SetupInteractor(this->ui->view2->GetRenderWindow()->GetInteractor());
this->ui->view3->SetRenderWindow(riw[2]->GetRenderWindow());
riw[2]->SetupInteractor(this->ui->view3->GetRenderWindow()->GetInteractor());
for (int i = 0; i < 3; i++)
{
// make them all share the same reslice cursor object.
vtkResliceCursorLineRepresentation *rep = vtkResliceCursorLineRepresentation::SafeDownCast(riw[i]->GetResliceCursorWidget()->GetRepresentation());
riw[i]->SetResliceCursor(riw[0]->GetResliceCursor());
rep->GetResliceCursorActor()->GetCursorAlgorithm()->SetReslicePlaneNormal(i);
riw[i]->SetInputData(reader->GetOutput());
riw[i]->SetSliceOrientation(i);
riw[i]->SetResliceModeToAxisAligned();
}
vtkSmartPointer<vtkCellPicker> picker = vtkSmartPointer<vtkCellPicker>::New();
picker->SetTolerance(0.005);
vtkSmartPointer<vtkProperty> ipwProp = vtkSmartPointer<vtkProperty>::New();
vtkSmartPointer< vtkRenderer > ren = vtkSmartPointer< vtkRenderer >::New();
vtkNew<vtkGenericOpenGLRenderWindow> renderWindow;
this->ui->view4->SetRenderWindow(renderWindow);
this->ui->view4->GetRenderWindow()->AddRenderer(ren);
vtkRenderWindowInteractor *iren = this->ui->view4->GetInteractor();
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);
color[0] /= 4.0;
color[1] /= 4.0;
color[2] /= 4.0;
riw[i]->GetRenderer()->SetBackground( 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);
planeWidget[i]->SetWindowLevel(1358, -27);
planeWidget[i]->On();
planeWidget[i]->InteractionOn();
}
vtkSmartPointer<vtkResliceCursorCallback> cbk = vtkSmartPointer<vtkResliceCursorCallback>::New();
for (int i = 0; i < 3; i++)
{
cbk->IPW[i] = planeWidget[i];
cbk->RCW[i] = riw[i]->GetResliceCursorWidget();
riw[i]->GetResliceCursorWidget()->AddObserver(
vtkResliceCursorWidget::ResliceAxesChangedEvent, cbk );
riw[i]->GetResliceCursorWidget()->AddObserver(
vtkResliceCursorWidget::WindowLevelEvent, cbk );
riw[i]->GetResliceCursorWidget()->AddObserver(
vtkResliceCursorWidget::ResliceThicknessChangedEvent, cbk );
riw[i]->GetResliceCursorWidget()->AddObserver(
vtkResliceCursorWidget::ResetCursorEvent, cbk );
riw[i]->GetInteractorStyle()->AddObserver(
vtkCommand::WindowLevelEvent, cbk );
// Make them all share the same color map.
riw[i]->SetLookupTable(riw[0]->GetLookupTable());
planeWidget[i]->GetColorMap()->SetLookupTable(riw[0]->GetLookupTable());
//planeWidget[i]->GetColorMap()->SetInput(riw[i]->GetResliceCursorWidget()->GetResliceCursorRepresentation()->GetColorMap()->GetInput());
planeWidget[i]->SetColorMap(riw[i]->GetResliceCursorWidget()->GetResliceCursorRepresentation()->GetColorMap());
}
this->ui->view1->show();
this->ui->view2->show();
this->ui->view3->show();
// Set up action signals and slots
connect(this->ui->actionExit, SIGNAL(triggered()), this, SLOT(slotExit()));
connect(this->ui->resliceModeCheckBox, SIGNAL(stateChanged(int)), this, SLOT(resliceMode(int)));
connect(this->ui->thickModeCheckBox, SIGNAL(stateChanged(int)), this, SLOT(thickMode(int)));
this->ui->thickModeCheckBox->setEnabled(0);
connect(this->ui->radioButton_Max, SIGNAL(pressed()), this, SLOT(SetBlendModeToMaxIP()));
connect(this->ui->radioButton_Min, SIGNAL(pressed()), this, SLOT(SetBlendModeToMinIP()));
connect(this->ui->radioButton_Mean, SIGNAL(pressed()), this, SLOT(SetBlendModeToMeanIP()));
this->ui->blendModeGroupBox->setEnabled(0);
connect(this->ui->resetButton, SIGNAL(pressed()), this, SLOT(ResetViews()));
connect(this->ui->AddDistance1Button, SIGNAL(pressed()), this, SLOT(AddDistanceMeasurementToView1()));
};
void QtVTKRenderWindows::slotExit()
{
qApp->exit();
}
void QtVTKRenderWindows::resliceMode(int mode)
{
this->ui->thickModeCheckBox->setEnabled(mode ? 1 : 0);
this->ui->blendModeGroupBox->setEnabled(mode ? 1 : 0);
for (int i = 0; i < 3; i++)
{
riw[i]->SetResliceMode(mode ? 1 : 0);
riw[i]->GetRenderer()->ResetCamera();
riw[i]->Render();
}
}
void QtVTKRenderWindows::thickMode(int mode)
{
for (int i = 0; i < 3; i++)
{
riw[i]->SetThickMode(mode ? 1 : 0);
riw[i]->Render();
}
}
void QtVTKRenderWindows::SetBlendMode(int m)
{
for (int i = 0; i < 3; i++)
{
vtkImageSlabReslice *thickSlabReslice = vtkImageSlabReslice::SafeDownCast(
vtkResliceCursorThickLineRepresentation::SafeDownCast(
riw[i]->GetResliceCursorWidget()->GetRepresentation())->GetReslice());
thickSlabReslice->SetBlendMode(m);
riw[i]->Render();
}
}
void QtVTKRenderWindows::SetBlendModeToMaxIP()
{
this->SetBlendMode(VTK_IMAGE_SLAB_MAX);
}
void QtVTKRenderWindows::SetBlendModeToMinIP()
{
this->SetBlendMode(VTK_IMAGE_SLAB_MIN);
}
void QtVTKRenderWindows::SetBlendModeToMeanIP()
{
this->SetBlendMode(VTK_IMAGE_SLAB_MEAN);
}
void QtVTKRenderWindows::ResetViews()
{
// Reset the reslice image views
for (int i = 0; i < 3; i++)
{
riw[i]->Reset();
}
// Also sync the Image plane widget on the 3D top right view with any
// changes to the reslice cursor.
for (int i = 0; i < 3; i++)
{
vtkPlaneSource *ps = static_cast< vtkPlaneSource * >(
planeWidget[i]->GetPolyDataAlgorithm());
ps->SetNormal(riw[0]->GetResliceCursor()->GetPlane(i)->GetNormal());
ps->SetCenter(riw[0]->GetResliceCursor()->GetPlane(i)->GetOrigin());
// If the reslice plane has modified, update it on the 3D widget
this->planeWidget[i]->UpdatePlacement();
}
// Render in response to changes.
this->Render();
}
void QtVTKRenderWindows::Render()
{
for (int i = 0; i < 3; i++)
{
riw[i]->Render();
}
this->ui->view3->GetRenderWindow()->Render();
}
void QtVTKRenderWindows::AddDistanceMeasurementToView1()
{
this->AddDistanceMeasurementToView(1);
}
void QtVTKRenderWindows::AddDistanceMeasurementToView(int i)
{
// remove existing widgets.
if (this->DistanceWidget[i])
{
this->DistanceWidget[i]->SetEnabled(0);
this->DistanceWidget[i] = nullptr;
}
// add new widget
this->DistanceWidget[i] = vtkSmartPointer< vtkDistanceWidget >::New();
this->DistanceWidget[i]->SetInteractor(
this->riw[i]->GetResliceCursorWidget()->GetInteractor());
// Set a priority higher than our reslice cursor widget
this->DistanceWidget[i]->SetPriority(
this->riw[i]->GetResliceCursorWidget()->GetPriority() + 0.01);
vtkSmartPointer< vtkPointHandleRepresentation2D > handleRep =
vtkSmartPointer< vtkPointHandleRepresentation2D >::New();
vtkSmartPointer< vtkDistanceRepresentation2D > distanceRep =
vtkSmartPointer< vtkDistanceRepresentation2D >::New();
distanceRep->SetHandleRepresentation(handleRep);
this->DistanceWidget[i]->SetRepresentation(distanceRep);
distanceRep->InstantiateHandleRepresentation();
distanceRep->GetPoint1Representation()->SetPointPlacer(riw[i]->GetPointPlacer());
distanceRep->GetPoint2Representation()->SetPointPlacer(riw[i]->GetPointPlacer());
// Add the distance to the list of widgets whose visibility is managed based
// on the reslice plane by the ResliceImageViewerMeasurements class
this->riw[i]->GetMeasurements()->AddItem(this->DistanceWidget[i]);
this->DistanceWidget[i]->CreateDefaultRepresentation();
this->DistanceWidget[i]->EnabledOn();
}
3 自己的代码
#ifndef IMAGEMANAGE_H
#define IMAGEMANAGE_H
#include <QWidget>
#include <QSplitter>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QResizeEvent>
#include <QtDebug>
#include "QVTKOpenGLWidget.h" //新版本,旧版QVTKWidget
#include "vtkAutoInit.h"
#include "vtkSmartPointer.h"
#include "vtkResliceImageViewer.h"
#include "vtkImagePlaneWidget.h"
#include "vtkDistanceWidget.h"
#include "vtkResliceImageViewerMeasurements.h"
#include "vtkBoundedPlanePointPlacer.h"
#include "vtkCellPicker.h"
#include "vtkCommand.h"
#include "vtkDICOMImageReader.h"
#include "vtkDistanceRepresentation.h"
#include "vtkDistanceRepresentation2D.h"
#include "vtkDistanceWidget.h"
#include <vtkGenericOpenGLRenderWindow.h>
#include "vtkHandleRepresentation.h"
#include "vtkImageData.h"
#include "vtkImageMapToWindowLevelColors.h"
#include "vtkImageSlabReslice.h"
#include "vtkInteractorStyleImage.h"
#include "vtkLookupTable.h"
#include "vtkPlane.h"
#include "vtkPlaneSource.h"
#include "vtkPointHandleRepresentation2D.h"
#include "vtkPointHandleRepresentation3D.h"
#include "vtkProperty.h"
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include "vtkRenderWindowInteractor.h"
#include "vtkResliceImageViewer.h"
#include "vtkResliceCursorLineRepresentation.h"
#include "vtkResliceCursorThickLineRepresentation.h"
#include "vtkResliceCursorWidget.h"
#include "vtkResliceCursorActor.h"
#include "vtkResliceCursorPolyDataAlgorithm.h"
#include "vtkResliceCursor.h"
#include "vtkResliceImageViewerMeasurements.h"
class vtkResliceCursorCallback;
namespace Ui {
class ImageManage;
}
class ImageManage : public QWidget
{
Q_OBJECT
public:
explicit ImageManage(QWidget *parent = nullptr);
~ImageManage();
void setCurrentTab(int temp =0);
public slots:
/**
* @brief slot_ReaderDICOMImage
* @param fn
* 读取DICOM文件
*/
void slot_ReaderDICOMImage(const char* fn);
protected:
void resizeEvent(QResizeEvent *event) override;
private:
Ui::ImageManage *ui;
QSplitter *mSplitterMain = nullptr;
QSplitter *mSplitterVertical = nullptr;
QSplitter *mSplitterUp = nullptr;
QSplitter *mSplitterDown = nullptr;
double color[3] = {0,0,0}; //颜色
vtkSmartPointer<vtkDICOMImageReader> reader = nullptr; //读取DICOM文件
int imageDims[3] = {0}; //暂时不理解
vtkSmartPointer< vtkResliceImageViewer > riw[3]; //三个二维视图
vtkSmartPointer< vtkImagePlaneWidget > planeWidget[3];
vtkSmartPointer< vtkDistanceWidget > DistanceWidget[3]; //测试距离的,暂时没有移植,无用
vtkSmartPointer< vtkResliceImageViewerMeasurements > ResliceMeasurements; //不知道干啥,没有用到
vtkSmartPointer<vtkProperty> ipwProp; //属性
vtkSmartPointer<vtkCellPicker> picker; //拾取器
vtkSmartPointer< vtkRenderer > ren; //3D渲染器
vtkSmartPointer<vtkResliceCursorCallback> cbk; //回调类
};
#endif // IMAGEMANAGE_H
#include "imagemanage.h"
#include "ui_imagemanage.h"
class vtkResliceCursorCallback : public vtkCommand
{
public:
static vtkResliceCursorCallback *New()
{ return new vtkResliceCursorCallback; }
void Execute( vtkObject *caller, unsigned long ev, void *callData ) override
{
if (ev == vtkResliceCursorWidget::WindowLevelEvent || ev == vtkCommand::WindowLevelEvent || ev == vtkResliceCursorWidget::ResliceThicknessChangedEvent)
{
// Render everything
for (int i = 0; i < 3; i++)
{
this->RCW[i]->Render();
}
this->IPW[0]->GetInteractor()->GetRenderWindow()->Render();
// return; //这里需要注释掉,不然呵呵呵,返回了,还搞个毛线
}
vtkImagePlaneWidget* ipw = dynamic_cast< vtkImagePlaneWidget* >( caller );
// qDebug() << "11" << caller << ipw;
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);
// qDebug() << "22" << caller << rcw;
if (rcw)
{
vtkResliceCursorLineRepresentation *rep = dynamic_cast<
vtkResliceCursorLineRepresentation * >(rcw->GetRepresentation());
// Although the return value is not used, we keep the get calls
// in case they had side-effects
rep->GetResliceCursorActor()->GetCursorAlgorithm()->GetResliceCursor();
for (int i = 0; i < 3; i++)
{
vtkPlaneSource *ps = static_cast< vtkPlaneSource * >(this->IPW[i]->GetPolyDataAlgorithm());
ps->SetOrigin(this->RCW[i]->GetResliceCursorRepresentation()->GetPlaneSource()->GetOrigin());
ps->SetPoint1(this->RCW[i]->GetResliceCursorRepresentation()-> GetPlaneSource()->GetPoint1());
ps->SetPoint2(this->RCW[i]->GetResliceCursorRepresentation()->GetPlaneSource()->GetPoint2());
// If the reslice plane has modified, update it on the 3D widget
this->IPW[i]->UpdatePlacement();
}
}
// Render everything
for (int i = 0; i < 3; i++)
{
this->RCW[i]->Render();
}
this->IPW[0]->GetInteractor()->GetRenderWindow()->Render();
}
vtkResliceCursorCallback() {}
vtkImagePlaneWidget* IPW[3];
vtkResliceCursorWidget *RCW[3];
};
static QPoint lastPos;
ImageManage::ImageManage(QWidget *parent) :QWidget(parent),ui(new Ui::ImageManage)
{
ui->setupUi(this);
/******************窗口大小分割*************************/
mSplitterMain = new QSplitter(Qt::Horizontal,this);
mSplitterVertical = new QSplitter(Qt::Vertical,mSplitterMain);
mSplitterUp = new QSplitter(Qt::Horizontal,mSplitterVertical);
mSplitterUp->addWidget(ui->widget_1);
mSplitterUp->addWidget(ui->widget_2);
mSplitterUp->setStretchFactor(0,1);
mSplitterUp->setStretchFactor(1,1);
mSplitterDown = new QSplitter(Qt::Horizontal,mSplitterVertical);
mSplitterDown->addWidget(ui->widget_3);
mSplitterDown->addWidget(ui->widget_4);
mSplitterDown->setStretchFactor(0,1);
mSplitterDown->setStretchFactor(1,1);
mSplitterMain->insertWidget(0,mSplitterVertical);
mSplitterMain->insertWidget(1,ui->widget_5);
mSplitterMain->setStretchFactor(0,1); //很魔性啊
}
ImageManage::~ImageManage()
{
delete ui;
}
void ImageManage::setCurrentTab(int temp)
{
Q_UNUSED(temp);
}
void ImageManage::slot_ReaderDICOMImage(const char *fn)
{
if(!reader)
{
reader = vtkSmartPointer<vtkDICOMImageReader>::New();
}
reader->SetDirectoryName(fn); //这里主要,是文件夹哈,不是文件名
reader->Update(); //得更新呀,惰性渲染
reader->GetOutput()->GetDimensions(imageDims); //还不理解,翻译为获取维度,注释掉以后三维中有影响
for (auto i = 0; i < 3; i++)
{
riw[i] = vtkSmartPointer< vtkResliceImageViewer >::New();
vtkNew<vtkGenericOpenGLRenderWindow> renderWindow;
riw[i]->SetRenderWindow(renderWindow);
}
// ui->widget_1->SetRenderWindow(riw[0]->GetRenderWindow());
riw[0]->SetupInteractor(ui->widget_1->GetRenderWindow()->GetInteractor());
riw[0]->SetRenderWindow(ui->widget_1->GetRenderWindow());
// ui->widget_2->SetRenderWindow(riw[1]->GetRenderWindow());
riw[1]->SetupInteractor(ui->widget_2->GetRenderWindow()->GetInteractor());
riw[1]->SetRenderWindow(ui->widget_2->GetRenderWindow());
// ui->widget_3->SetRenderWindow(riw[2]->GetRenderWindow());
riw[2]->SetRenderWindow(ui->widget_3->GetRenderWindow());
riw[2]->SetupInteractor(ui->widget_3->GetRenderWindow()->GetInteractor());
for (int i = 0; i < 3; i++)
{
// make them all share the same reslice cursor object.
vtkResliceCursorLineRepresentation *rep =vtkResliceCursorLineRepresentation::SafeDownCast(riw[i]->GetResliceCursorWidget()->GetRepresentation());
riw[i]->SetResliceCursor(riw[0]->GetResliceCursor());
rep->GetResliceCursorActor()->GetCursorAlgorithm()->SetReslicePlaneNormal(i);
riw[i]->SetInputData(reader->GetOutput());
riw[i]->SetSliceOrientation(i);
riw[i]->SetResliceModeToAxisAligned();
}
picker = vtkSmartPointer<vtkCellPicker>::New();
picker->SetTolerance(0.005);
ipwProp = vtkSmartPointer<vtkProperty>::New();
ren = vtkSmartPointer< vtkRenderer >::New();
ui->widget_4->GetRenderWindow()->AddRenderer(ren);
for (int i = 0; i < 3; i++)
{
planeWidget[i] = vtkSmartPointer<vtkImagePlaneWidget>::New();
planeWidget[i]->SetInteractor( ui->widget_4->GetInteractor() );
planeWidget[i]->SetPicker(picker);
planeWidget[i]->RestrictPlaneToVolumeOn();
color[0] = 0;
color[1] = 0;
color[2] = 0;
color[i] = 1;
planeWidget[i]->GetPlaneProperty()->SetColor(color);
color[0] = 0;
color[1] = 0;
color[2] = 0;
riw[i]->GetRenderer()->SetBackground( 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);
planeWidget[i]->SetWindowLevel(1358, -27);
planeWidget[i]->On();
planeWidget[i]->InteractionOn();
}
cbk = vtkSmartPointer<vtkResliceCursorCallback>::New();
for (int i = 0; i < 3; i++)
{
cbk->IPW[i] = planeWidget[i];
cbk->RCW[i] = riw[i]->GetResliceCursorWidget();
riw[i]->GetResliceCursorWidget()->AddObserver(vtkResliceCursorWidget::ResliceAxesChangedEvent, cbk );
riw[i]->GetResliceCursorWidget()->AddObserver(vtkResliceCursorWidget::WindowLevelEvent, cbk );
riw[i]->GetResliceCursorWidget()->AddObserver(vtkResliceCursorWidget::ResliceThicknessChangedEvent, cbk );
riw[i]->GetResliceCursorWidget()->AddObserver(vtkResliceCursorWidget::ResetCursorEvent, cbk );
riw[i]->GetInteractorStyle()->AddObserver(vtkCommand::WindowLevelEvent, cbk );
// Make them all share the same color map.
riw[i]->SetLookupTable(riw[0]->GetLookupTable());
planeWidget[i]->GetColorMap()->SetLookupTable(riw[0]->GetLookupTable());
//planeWidget[i]->GetColorMap()->SetInput(riw[i]->GetResliceCursorWidget()->GetResliceCursorRepresentation()->GetColorMap()->GetInput());
planeWidget[i]->SetColorMap(riw[i]->GetResliceCursorWidget()->GetResliceCursorRepresentation()->GetColorMap());
}
// ui->widget_1->GetRenderWindow()->Render();
// ui->widget_2->GetRenderWindow()->Render();
// ui->widget_3->GetRenderWindow()->Render();
// ui->widget_4->GetRenderWindow()->Render();
//十字线
for (int i = 0; i < 3; i++)
{
riw[i]->SetResliceMode(1);
riw[i]->GetRenderer()->ResetCamera();
riw[i]->Render();
}
// 还不知道干啥
// for (int i = 0; i < 3; i++)
// {
// riw[i]->SetThickMode(1);
// riw[i]->Render();
// }
// for (int i = 0; i < 3; i++)
// {
// vtkImageSlabReslice *thickSlabReslice = vtkImageSlabReslice::SafeDownCast(
// vtkResliceCursorThickLineRepresentation::SafeDownCast(
// riw[i]->GetResliceCursorWidget()->GetRepresentation())->GetReslice());
// thickSlabReslice->SetBlendMode(1);
// riw[i]->Render();
// }
}
void ImageManage::resizeEvent(QResizeEvent *event)
{
Q_UNUSED(event);
mSplitterMain->resize(this->size());
}
4 运行效果
☞ 源码
源码链接:https://github.com/DreamLife-Jianwei/Qt-Vtk
使用方法:☟☟☟
以上是关于医学四视图-002-四视图实现的主要内容,如果未能解决你的问题,请参考以下文章