VTK模型重建后可能需要角度測量這樣一個小功能。
對於角度測量首先需要擁有一個角度,而這個角度通常由兩條線段組成,VTK的角度測量里面也有直接應用該方法可實現的。
也就是說通過定義兩天線段,線段有兩個端點(兩個線段共用其中一個),移動其中端點就會響應一定事件並對點信息進行更新以及計算,最后將結果顯示。
下面先看對移動端點顯示部分代碼:
// 這里定義了2個全局的lineWidget
vtkLineWidget *lineWidget1; vtkLineWidget *lineWidget2; class vtkLWCallback : public vtkCommand { public: static vtkLWCallback *New() { return new vtkLWCallback; } virtual void Execute(vtkObject *caller, unsigned long, void*) { vtkLineWidget *lineWidget = reinterpret_cast<vtkLineWidget*>(caller); double O[3], A[3], B[3];
//重新設置兩條線段到同一個端點 lineWidget->GetPoint1 (O); lineWidget1->SetPoint1 (O); lineWidget2->SetPoint1 (O); lineWidget1->GetPoint2 (A); lineWidget2->GetPoint2 (B); double OA,OB,AB; AB=sqrt((A[0]-B[0])*(A[0]-B[0]) + (A[1]-B[1])*(A[1]-B[1]) + (A[2]-B[2])*(A[2]-B[2])); OA=sqrt((A[0]-O[0])*(A[0]-O[0]) + (A[1]-O[1])*(A[1]-O[1]) + (A[2]-O[2])*(A[2]-O[2])); OB=sqrt((O[0]-B[0])*(O[0]-B[0]) + (O[1]-B[1])*(O[1]-B[1]) + (O[2]-B[2])*(O[2]-B[2])); double cosAOB = (OA*OA + OB*OB - AB*AB) / (2*OA*OB); double angle; angle = acos(cosAOB) * 180 / 3.14159; char cAct[100]; sprintf((char *)cAct, "%.4f", angle); this->Text->SetInput (cAct); } vtkLWCallback():Text(0) {} public: vtkTextMapper *Text;
//如果不想定義全局的 vtkLineWidget也可以在這里定義局部變量並從調用函數傳遞初始化之 };
在調用函數部分則需要初始化兩線段,並進行一些構建模型的基礎操作,直接上碼:
#include "vtkActor.h" #include "vtkCommand.h" #include "vtkInteractorEventRecorder.h" #include "vtkLineWidget.h" #include "vtkDICOMImageReader.h" #include "vtkRenderWindowInteractor.h" #include <vtkPolyDataMapper.h> #include <vtkImageData.h> #include <vtkSphereSource.h> #include <vtkActor2D.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkImageActor.h> #include <vtkImageShiftScale.h> #include <vtkProperty.h> #include <vtkScaledTextActor.h> #include <vtkTextMapper.h> #include <math.h> #include <string.h> int degreeVTKExample() { vtkSphereSource *sphere = vtkSphereSource::New(); sphere->SetThetaResolution(12); sphere->SetPhiResolution(12); sphere->SetRadius(100); vtkPolyDataMapper *innerMapper = vtkPolyDataMapper::New(); innerMapper->SetInput(sphere->GetOutput()); vtkActor *innerSphere = vtkActor::New(); innerSphere->SetMapper(innerMapper); innerSphere->GetProperty()->SetColor (1,1,1); innerSphere->GetProperty()->SetOpacity (0.5); vtkTextMapper *textMapper=vtkTextMapper::New(); textMapper->SetInput ("Welcome you!");//所要顯示的注釋文字 vtkScaledTextActor *mmm=vtkScaledTextActor::New(); vtkSmartPointer<vtkTextMapper> vtkTMapper = vtkTextMapper::New(); mmm->SetMapper((vtkPolyDataMapper2D*)textMapper); mmm->SetDisplayPosition(100, 10 );//設定注釋位置 vtkRenderer *ren1 = vtkRenderer::New(); vtkRenderWindow *renWin = vtkRenderWindow::New(); renWin->AddRenderer(ren1); vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New(); iren->SetRenderWindow(renWin); vtkLWCallback *myCallback1 = vtkLWCallback::New(); myCallback1->Text = textMapper; lineWidget1 = vtkLineWidget::New(); lineWidget1->SetInteractor(iren); lineWidget1->SetInput(sphere->GetOutput()); lineWidget1->SetAlignToYAxis(); lineWidget1->PlaceWidget(); lineWidget1->GetLineProperty()->SetColor(1,0,0); lineWidget1->GetHandleProperty()->SetColor(0,0,1); lineWidget1->AddObserver(vtkCommand::InteractionEvent, myCallback1); lineWidget1->On(); vtkLWCallback *myCallback2 = vtkLWCallback::New(); myCallback2->Text = textMapper; lineWidget2 = vtkLineWidget::New(); lineWidget2->SetInteractor(iren); lineWidget2->SetInput(sphere->GetOutput()); lineWidget2->PlaceWidget(); lineWidget2->GetLineProperty()->SetColor(1,0,0); lineWidget2->GetHandleProperty()->SetColor(0,0,1); lineWidget2->AddObserver(vtkCommand::InteractionEvent, myCallback2); lineWidget2->SetPoint1(lineWidget1->GetPoint1 ()); lineWidget2->On(); ren1->AddActor(innerSphere); ren1->AddActor(mmm);//顯示注釋文字 ren1->SetBackground(0, 0, 0); renWin->SetSize(600, 600); ren1->InteractiveOff(); iren->Initialize(); renWin->Render(); iren->InvokeEvent(vtkCommand::CharEvent,NULL); ren1->InteractiveOff(); iren->Start(); myCallback1->Delete(); lineWidget1->Delete(); myCallback2->Delete(); lineWidget2->Delete(); sphere->Delete(); iren->Delete(); renWin->Delete(); ren1->Delete(); return 0; }
最終的結果如下圖所示:
PS: 其實VTK本身就有求取角度的widget也就是vtkAngleWidget
http://www.vtk.org/doc/nightly/html/classvtkAngleWidget.html#details
發現實例爽歪歪:
http://www.vtk.org/Wiki/VTK/Examples/Cxx/Widgets/vtkAngleWidget
http://www.vtk.org/Wiki/VTK/Examples/Cxx/Widgets/vtkAngleWidget_2D
不過這個例子有點簡單,不過還是可以具體地分析下,接下來將他們應用到我的程序里面
這里是默認的效果,注意左下角的圖標確實出現了角度測量的功能,但是當用鼠標隨意滾動時候會出現角度的3個點
不隨着圖形變動的想象。
而上面2個例子的效果都差不了多少。
但如果將實例2的相關代碼修改成:
/*vtkSmartPointer<vtkAngleRepresentation2D> rep = vtkSmartPointer<vtkAngleRepresentation2D>::New();*/ vtkSmartPointer<vtkAngleRepresentation3D> rep = vtkSmartPointer<vtkAngleRepresentation3D>::New(); rep->ArcVisibilityOff(); vtkSmartPointer<vtkAngleWidget> angleWidget = vtkSmartPointer<vtkAngleWidget>::New(); angleWidget->SetRepresentation(rep); angleWidget->SetInteractor(iren); angleWidget->CreateDefaultRepresentation();
可以看出其會隨着鼠標的滾動、縮放等更新變換。
有可能是前面的vtkAngleRepresentation2D是只適應於2D平面的情況,而這里的模型是3D的因此就會這樣的效果。
但這樣好歹也知道了3D平面做角度求取的簡單方法了罷:)
What's more
http://www.vtk.org/Wiki/VTK/Examples/Cxx
實例里面擁有許多的例子從點間距離到點采集、圖像拷貝、存儲、CenterOfMass、ExtractSelection、SeedWidget等可以說是一個大寶藏
坑爹的是例子都只配了一張圖,除非自己copy代碼運行否則效果也太難看出來鳥~~
如下面的vtkDistanceWidget也是個好東東,加上
vtkSmartPointer<vtkDistanceRepresentation3D> rep3D = vtkSmartPointer<vtkDistanceRepresentation3D>::New();
vtkSmartPointer<vtkDistanceWidget> distanceWidget =
vtkSmartPointer<vtkDistanceWidget>::New();
distanceWidget->SetInteractor(renderWindowInteractor);
distanceWidget->SetRepresentation(rep3D);
distanceWidget->CreateDefaultRepresentation();
就可以有3維可用的距離測量!
(當然記得設置好自己的dicomReader->SetDataSpacing(2.0 / 3, 2.0 / 3, 1);不然標尺不同就。 )