简述

  VTK中体(vtkVolume)的裁剪可以通过体数据映射器(vtkVolumeMapper)设置裁剪平面(vtkPlane)进行裁剪(AddClippingPlane )。该裁剪平面可通过参数设置其属性,也可使用平面窗口(vtkPlaneWidget)通过鼠标平移缩放旋转至目标位置后,获取该窗口包含的平面(GetPlane),并将其设置给提数据映射器(vtkVolumeMapper)进行裁剪。本文实现了通过鼠标操作平面窗口(vtkPlaneWidget)后进行体数据裁剪。

代码

main.cpp

#include <QtWidgets/QApplication>#include <QWidget>#include <QPushButton>#include <QGridLayout>#include "CVtkPlaneCut.h"int main( int argc, char *argv[] ){ QApplication a( argc, argv ); QWidget* pWidget = new QWidget; CVtkPlaneCut* pPlaneCut = new CVtkPlaneCut( pWidget ); QPushButton* pBtnClip = new QPushButton( "Clip" ); pBtnClip->setFixedHeight( 30 ); QObject::connect( pBtnClip, SIGNAL( clicked() ), pPlaneCut, SLOT( slotClipVolume() ) ); QVBoxLayout* pMainLayout = new QVBoxLayout; pMainLayout->addWidget( pPlaneCut ); pMainLayout->addWidget( pBtnClip ); pWidget->setLayout( pMainLayout ); pWidget->show(); return a.exec();}

CVtkPlaneCut .h

#ifndef CVTKPLANECUT_H#define CVTKPLANECUT_H#include "QVTKWidget.h"#include "vtkSmartPointer.h"class vtkVolume;class vtkRenderWindow;class vtkPlaneWidget;class CVtkPlaneCut : public QVTKWidget{ Q_OBJECTpublic: CVtkPlaneCut( QWidget *parent = 0 );protected slots: void slotClipVolume();private: vtkSmartPointer<vtkVolume> m_pVolume; vtkSmartPointer<vtkRenderWindow> m_pRenderWindow; vtkSmartPointer<vtkPlaneWidget> m_pPlaneWidget;};#endif // CVTKPLANECUT_H

CVtkPlaneCut .cpp

#include <vtkAutoInit.h> VTK_MODULE_INIT( vtkRenderingOpenGL );VTK_MODULE_INIT( vtkInteractionStyle );#define vtkRenderingCore_AUTOINIT 4(vtkInteractionStyle,vtkRenderingFreeType,vtkRenderingFreeTypeOpenGL,vtkRenderingOpenGL)#define vtkRenderingVolume_AUTOINIT 1(vtkRenderingVolumeOpenGL) #include "CVtkPlaneCut.h"#include <QFile>#include "vtkImageData.h"#include "vtkRenderer.h"#include "vtkRenderWindow.h"#include "vtkVolume.h"#include "vtkVolumeProperty.h"#include "vtkPiecewiseFunction.h"#include "vtkSmartVolumeMapper.h"#include "vtkColorTransferFunction.h"#include "vtkCamera.h"#include "vtkPlane.h"#include "vtkPlaneWidget.h"#include "vtkImageShiftScale.h"#include "vtkProperty.h"CVtkPlaneCut::CVtkPlaneCut( QWidget *parent ) : QVTKWidget( parent ){ /*Init RenderWindow*/ vtkSmartPointer<vtkRenderer> pRenderer = vtkSmartPointer<vtkRenderer>::New(); m_pRenderWindow = vtkSmartPointer<vtkRenderWindow>::New(); m_pVolume = vtkSmartPointer<vtkVolume>::New(); m_pRenderWindow->AddRenderer( pRenderer ); this->SetRenderWindow( m_pRenderWindow ); /*Create Image Data*/ int nDims[ 3 ] = { 1 }; nDims[ 0 ] = 512; nDims[ 1 ] = 512; nDims[ 2 ] = 262; double dSpacing[ 3 ] = { 0.1 }; dSpacing[ 0 ] = 0.78; dSpacing[ 1 ] = 0.78; dSpacing[ 2 ] = 3.27; double dOrigin[ 3 ] = { 0.0 }; vtkSmartPointer<vtkImageData> pImageData = vtkSmartPointer<vtkImageData>::New(); pImageData->SetSpacing( dSpacing ); pImageData->SetDimensions( nDims ); pImageData->SetOrigin( dOrigin ); /*Read Data*/ QString strFilePath = "../TestData/CT_Body_512_512_262_0.78_0.78_3.27_2048_short.HU"; QFile file( strFilePath ); if( !file.open( QIODevice::ReadOnly ) ) return; file.seek( 2048 ); int nSizeOfShot = sizeof( short ); long lLength = nDims[ 0 ] * nDims[ 1 ] * nDims[ 2 ]; char* pRawData = new char[ lLength * nSizeOfShot ]; long lRead = 0; while( lRead < lLength * nSizeOfShot ) lRead += file.read( pRawData, lLength * nSizeOfShot ); pImageData->AllocateScalars( VTK_SHORT, 1 ); short* pScalarPointer = (short*)pImageData->GetScalarPointer(); short* pData = (short*)pRawData; memcpy( pScalarPointer, pData, lLength ); file.close(); /* Volume Property */ //设置体绘制相关属性 vtkSmartPointer<vtkVolumeProperty> volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New(); volumeProperty->SetInterpolationTypeToLinear(); //设置线性插值方式 volumeProperty->ShadeOn();//开启阴影属性 volumeProperty->SetAmbient( 0.4 );//设置环境温度 volumeProperty->SetDiffuse( 0.6 );//设置漫反射系数 volumeProperty->SetSpecular( 2 );//设置镜面反射系数 //添加灰度不透明度属性 vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity = vtkSmartPointer<vtkPiecewiseFunction>::New(); compositeOpacity->AddPoint( -15591, 0.0 ); compositeOpacity->AddPoint( 4876, 0.001 ); compositeOpacity->AddPoint( 7961, 1 ); compositeOpacity->AddPoint( 11110, 0.001 ); compositeOpacity->AddPoint( 32767, 0 ); volumeProperty->SetScalarOpacity(compositeOpacity); //添加梯度不同明度属性 vtkSmartPointer<vtkPiecewiseFunction> gradientOpacity = vtkSmartPointer<vtkPiecewiseFunction>::New(); gradientOpacity->AddPoint( 0, 0.0 ); gradientOpacity->AddPoint( 200, 0.4 ); gradientOpacity->AddPoint( 500, 0.1 ); gradientOpacity->AddPoint( 800, 0.5 ); gradientOpacity->AddPoint( 1000, 0.6 ); volumeProperty->SetGradientOpacity(gradientOpacity); //添加颜色传输 vtkSmartPointer<vtkColorTransferFunction> color = vtkSmartPointer<vtkColorTransferFunction>::New(); color->AddRGBPoint( 0, 0, 0, 0 ); color->AddRGBPoint( 200, 0.5, 0.3, 0 ); color->AddRGBPoint( 500, 0, 1.0, 0 ); color->AddRGBPoint( 600, 0, 0.5, 0.5 ); color->AddRGBPoint( 1000, 0.20, 0.5, 0.20 ); volumeProperty->SetColor( color ); /*Volume*/ vtkSmartPointer<vtkSmartVolumeMapper> volumeMapper = vtkSmartPointer<vtkSmartVolumeMapper>::New(); volumeMapper->SetInputData( pImageData ); m_pVolume->SetMapper( volumeMapper ); m_pVolume->SetProperty( volumeProperty ); m_pVolume->SetOrigin( m_pVolume->GetCenter() ); /*Render Window*/ pRenderer->AddVolume( m_pVolume ); pRenderer->ResetCamera(); m_pRenderWindow->Modified(); m_pRenderWindow->Render(); /*Clipping Plane Widget*/ m_pPlaneWidget = vtkSmartPointer<vtkPlaneWidget>::New(); m_pPlaneWidget->SetInteractor( m_pRenderWindow->GetInteractor() );//与交互器关联 m_pPlaneWidget->SetInputData( pImageData );//设置数据集,用于初始化平面,可以不设置 m_pPlaneWidget->SetResolution( 50 );//即:设置网格数 m_pPlaneWidget->GetPlaneProperty()->SetColor( .2, .8, 0.1 );//设置颜色 m_pPlaneWidget->GetPlaneProperty()->SetOpacity( 0.5 );//设置透明度 m_pPlaneWidget->GetHandleProperty()->SetColor( 0, .4, .7 );//设置平面顶点颜色 m_pPlaneWidget->GetHandleProperty()->SetLineWidth( 1.5 );//设置平面线宽 m_pPlaneWidget->NormalToZAxisOn();//初始法线方向平行于Z轴 m_pPlaneWidget->SetRepresentationToWireframe();//平面显示为网格属性 m_pPlaneWidget->SetCenter( m_pVolume->GetCenter() );//设置平面坐标 m_pPlaneWidget->PlaceWidget();//放置平面 m_pPlaneWidget->On();//显示平面}void CVtkPlaneCut::slotClipVolume(){ //进行裁剪 vtkSmartPointer<vtkPlane> clippingPlane = vtkSmartPointer<vtkPlane>::New(); m_pPlaneWidget->GetPlane( clippingPlane ); m_pVolume->GetMapper()->AddClippingPlane( clippingPlane ); m_pVolume->Modified(); m_pRenderWindow->Modified(); m_pRenderWindow->Render();}效果

初始界面

鼠标操作后界面

点击"剪裁"按钮后效果