手动仿射变换


开发环境:

  1. Windows 11 家庭中文版
  2. Microsoft Visual Studio Community 2019
  3. VTK-9.3.0.rc0
  4. vtk-example
  5. 参考代码
  6. 目的:学习与总结

demo解决问题:通过仿射控件vtkAffineWidget对目标actor进行手动的拖拽的仿射变换

关键类:vtkAffineWidget

仿射变换概念参考链接
手动仿射变换_第1张图片

关键代码说明及效果展示:

  1. 获取仿射控件的transtorm,并设置到需要同等仿射变换的actor中
  this->AffineRep->GetTransform(this->Transform);
  this->Actor->SetUserTransform(this->Transform);
  1. SetUserTransform详细说明:(需要重点理解user的含义)
  /**
   * In addition to the instance variables such as position and orientation, you can add an additional transformation for your own use.  
   * This transformation is concatenated with the actor's internal transformation, which you implicitly create through the use of SetPosition(), SetOrigin() and SetOrientation().
   * If the internal transformation is identity (i.e. if you don't set the Position, Origin, or Orientation) then the actors final transformation will be the UserTransform, concatenated with the UserMatrix if the UserMatrix is present.
   */

/**
   * 除了位置和方向等实例变量外,您还可以添加额外的变换供自己使用。 
   * 此转换与 actor 的内部转换连接,通过使用 SetPosition()、SetOrigin() 和 SetOrientation() 隐式创建。

   * 如果内部转换是 identity(即,如果您没有设置 Position、Origin 或 Orientation),则 actor 的最终转换将是 UserTransform,如果存在 UserMatrix,则与 UserMatrix 串联。
   */

手动仿射变换_第2张图片
3. affineWidget添加观察者对象

  affineWidget->AddObserver(vtkCommand::InteractionEvent, affineCallback);
  affineWidget->AddObserver(vtkCommand::EndInteractionEvent, affineCallback);

  //这里可以考虑使用renderWindowInteractor进行回调,但是回调中需要判断操作对象是否为放射控件,比较繁琐
  //renderWindowInteractor->AddObserver(vtkCommand::InteractionEvent,affineCallback);
  //renderWindowInteractor->AddObserver(vtkCommand::EndInteractionEvent,affineCallback);
  1. 成员函数:SetRepresentationToWireframe()
    手动仿射变换_第3张图片

  2. GrandientBackgroundOn(开启渐变色)、SetBackground(底部颜色设置)、SetBackground2(顶部颜色设置)
    手动仿射变换_第4张图片
    手动仿射变换_第5张图片


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

namespace {
class vtkAffineCallback : public vtkCallbackCommand
{
public:
  static vtkAffineCallback* New()
  {
    return new vtkAffineCallback;
  }
  virtual void Execute(vtkObject* caller, unsigned long, void*);
  vtkAffineCallback() : Actor(0), AffineRep(0)
  {
    this->Transform = vtkTransform::New();
  }
  ~vtkAffineCallback()
  {
    this->Transform->Delete();
  }
  vtkActor* Actor;
  vtkAffineRepresentation2D* AffineRep;
  vtkTransform* Transform;
};
} // namespace

int main(int, char*[])
{
  vtkNew<vtkNamedColors> colors;

  // Create two spheres: a larger one and a smaller one on top of the larger one
  // to show a reference point while rotating
  vtkNew<vtkSphereSource> sphereSource;//大球
  sphereSource->Update();
  std::cout << "sphereSource radius: " <<  sphereSource->GetRadius() << std::endl;//0.5
  std::cout << "sphereSource center: " 
            << sphereSource->GetCenter()[0] << " "
            << sphereSource->GetCenter()[1] << " "
            << sphereSource->GetCenter()[2] << " "
            << std::endl; // 0 0 0

  vtkNew<vtkSphereSource> sphereSource2;//小球(中心刚好位于大球正上方边缘处)
  sphereSource2->SetRadius(0.075);
  sphereSource2->SetCenter(0, 0.5, 0);
  sphereSource2->Update();

  // Append the two spheres into one vtkPolyData
  vtkNew<vtkAppendPolyData> append;
  append->AddInputConnection(sphereSource->GetOutputPort());
  append->AddInputConnection(sphereSource2->GetOutputPort());

  // Create a plane centered over the larger sphere with 4x4 sub sections
  vtkNew<vtkPlaneSource> planeSource;
  planeSource->SetXResolution(4);
  planeSource->SetYResolution(4);
  planeSource->SetOrigin(-1, -1, 0);    //左下角
  planeSource->SetPoint1(1, -1, 0);     //右下角
  planeSource->SetPoint2(-1, 1, 0);     //左上角

  // Create a mapper and actor for the plane: show it as a wireframe
  vtkNew<vtkPolyDataMapper> planeMapper;
  planeMapper->SetInputConnection(planeSource->GetOutputPort());
  vtkNew<vtkActor> planeActor;
  planeActor->SetMapper(planeMapper);
  planeActor->GetProperty()->SetRepresentationToWireframe();//设置表现形式为线形边框;否则为面板
  planeActor->GetProperty()->SetColor(colors->GetColor3d("Red").GetData());//设置线形边框为欸红色

  // Create a mapper and actor for the spheres
  vtkNew<vtkPolyDataMapper> mapper;
  mapper->SetInputConnection(append->GetOutputPort());
  vtkNew<vtkActor> actor;
  actor->SetMapper(mapper);
  actor->GetProperty()->SetRepresentationToWireframe(); //只有线构成的球体

  // Create a renderer and render window
  vtkNew<vtkRenderer> renderer;
  vtkNew<vtkRenderWindow> renderWindow;
  renderWindow->AddRenderer(renderer);
  renderWindow->SetWindowName("AffineWidget");

  renderer->AddActor(actor);
  renderer->AddActor(planeActor);
  renderer->GradientBackgroundOn();                                         // 开启渐变色背景设置
  renderer->SetBackground(colors->GetColor3d("LightSkyBlue").GetData());    // 设置页面底部颜色值
  renderer->SetBackground2(colors->GetColor3d("MidnightBlue").GetData());   // 设置页面顶部颜色值

  // Create an interactor
  vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
  renderWindowInteractor->SetRenderWindow(renderWindow);
  dynamic_cast<vtkInteractorStyleSwitch*>(
      renderWindowInteractor->GetInteractorStyle())
      ->SetCurrentStyleToTrackballCamera();//设置交互对象是相机,形式是trackball

  // Create an affine widget to manipulate the actor
  // the widget currently only has a 2D representation and therefore applies
  // transforms in the X-Y plane only
  vtkNew<vtkAffineWidget> affineWidget;
  affineWidget->SetInteractor(renderWindowInteractor);
  affineWidget->CreateDefaultRepresentation();
  dynamic_cast<vtkAffineRepresentation2D*>(affineWidget->GetRepresentation())
      ->PlaceWidget(actor->GetBounds());//设置放射操作控件的位置在actor的外接矩形正中间

  //定义仿射控件交互事件对应的回调对象,并添加到观察者列表中,交互时进行通知
  vtkNew<vtkAffineCallback> affineCallback;
  affineCallback->Actor = actor;
  affineCallback->AffineRep = dynamic_cast<vtkAffineRepresentation2D*>(
      affineWidget->GetRepresentation());

  affineWidget->AddObserver(vtkCommand::InteractionEvent, affineCallback);
  affineWidget->AddObserver(vtkCommand::EndInteractionEvent, affineCallback);

  //这里可以考虑使用renderWindowInteractor进行回调,但是回调中需要判断操作对象是否为放射控件,比较繁琐
  //renderWindowInteractor->AddObserver(vtkCommand::InteractionEvent,affineCallback);
  //renderWindowInteractor->AddObserver(vtkCommand::EndInteractionEvent,affineCallback);

  renderWindow->Render();
  renderWindowInteractor->Initialize();
  renderWindow->Render();
  affineWidget->On();

  // begin mouse interaction
  renderWindowInteractor->Start();

  return EXIT_SUCCESS;
}

namespace {
void vtkAffineCallback::Execute(vtkObject*, unsigned long vtkNotUsed(event),
                                void*)
{
  this->AffineRep->GetTransform(this->Transform);
  this->Actor->SetUserTransform(this->Transform);
}
} // namespace

你可能感兴趣的:(vtk,计算机视觉,c++)