VTK中體(vtkVolume)的裁剪能夠經過體數據映射器(vtkVolumeMapper)設置裁剪平面(vtkPlane)進行裁剪(AddClippingPlane )。該裁剪平面可經過參數設置其屬性,也可以使用平面窗口(vtkPlaneWidget)經過鼠標平移縮放旋轉至目標位置後,獲取該窗口包含的平面(GetPlane),並將其設置給提數據映射器(vtkVolumeMapper)進行裁剪。本文實現了經過鼠標操做平面窗口(vtkPlaneWidget)後進行體數據裁剪。app
main.cppide
#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 .hthis
#ifndef CVTKPLANECUT_H #define CVTKPLANECUT_H #include "QVTKWidget.h" #include "vtkSmartPointer.h" class vtkVolume; class vtkRenderWindow; class vtkPlaneWidget; class CVtkPlaneCut : public QVTKWidget { Q_OBJECT public: 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 .cppcode
#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(); }
初始界面
鼠標操做後界面
點擊"剪裁"按鈕後效果
orm