[VTK]VTK的角度测量
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);不然标尺不同就。 )