[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);不然标尺不同就。 )

原文地址:https://www.cnblogs.com/dawnWind/p/3D_08.html