VTK: 三維體數據的平面裁剪

簡述

  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_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 .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();
}

效果

初始界面
VTK: 三維體數據的平面裁剪
鼠標操作後界面
VTK: 三維體數據的平面裁剪
點擊"剪裁"按鈕後效果
VTK: 三維體數據的平面裁剪

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章