简述
VTK中体(vtkVolume)的裁剪可以通过体数据映射器(vtkVolumeMapper)设置裁剪平面(vtkPlane)进行裁剪(AddClippingPlane )。该裁剪平面可通过参数设置其属性,也可使用平面窗口(vtkPlaneWidget)通过鼠标平移缩放旋转至目标位置后,获取该窗口包含的平面(GetPlane),并将其设置给提数据映射器(vtkVolumeMapper)进行裁剪。本文实现了通过鼠标操作平面窗口(vtkPlaneWidget)后进行体数据裁剪。
代码
main.cpp
#include
#include
#include
#include
#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_OBJECT
public:
CVtkPlaneCut( QWidget *parent = 0 );
protected slots:
void slotClipVolume();
private:
vtkSmartPointer m_pVolume;
vtkSmartPointer m_pRenderWindow;
vtkSmartPointer m_pPlaneWidget;
};
#endif // CVTKPLANECUT_H
CVtkPlaneCut .cpp
#include
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
#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 pRenderer = vtkSmartPointer::New();
m_pRenderWindow = vtkSmartPointer::New();
m_pVolume = vtkSmartPointer::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 pImageData = vtkSmartPointer::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 volumeProperty = vtkSmartPointer::New();
volumeProperty->SetInterpolationTypeToLinear(); //设置线性插值方式
volumeProperty->ShadeOn();//开启阴影属性
volumeProperty->SetAmbient( 0.4 );//设置环境温度
volumeProperty->SetDiffuse( 0.6 );//设置漫反射系数
volumeProperty->SetSpecular( 2 );//设置镜面反射系数
//添加灰度不透明度属性
vtkSmartPointer compositeOpacity = vtkSmartPointer::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 gradientOpacity = vtkSmartPointer::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 color = vtkSmartPointer::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 volumeMapper = vtkSmartPointer::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::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 clippingPlane = vtkSmartPointer::New();
m_pPlaneWidget->GetPlane( clippingPlane );
m_pVolume->GetMapper()->AddClippingPlane( clippingPlane );
m_pVolume->Modified();
m_pRenderWindow->Modified();
m_pRenderWindow->Render();
}