admin管理员组

文章数量:1794759

VTK教程3

VTK教程3

下面,本教程将介绍如何在MFC下打开vtk文件,最终的效果如图所示: 如果你看过一些三维重建相关的论文,那么一定对这个图像很熟悉。很多论文都会以这个图像作为例子讲解,好了,闲话少说,直接讲实现。 早期的vtk版本(比如vtk5.x.x),example里面自带MFC的三个例子(对话框,单文档,多文档),不知为何现在的新版本删除了,不过没有关系,重新实现一遍就行了,代码也不多。 首先,你需要保证你的vs2017能够创建MFC项目,如果不能,可以通过 visual studio installer安装,具体过程,请百度,这里不再赘述。 我们先来建立一个MFC应用程序,暂且命名为“vtkdlg”,后续将以这个名称产生的代码来讲解: 点击确认,然后选择“基于对话框”,点击“完成”: VTK是使用C++编写的,要使用VTK需要包含VTK发布的头文件,我们直接在vtkdlgDlg.h文件中添加以下代码:

#include "vtkDataSetMapper.h" #include "vtkDataSetReader.h" #include "vtkActor.h" #include "vtkMFCWindow.h" #include "vtkRenderer.h" #include "vtkProperty.h" #include "vtkWin32OpenGLRenderWindow.h"

点击“生成”,哎呀,找不到头文件!还记得教程1里面有个vtk-prefix文件夹吗?里面放着有,点击“项目”–>属性–>VC++目录–>包含目录,示意图如下: 修改确认后,再点击“生成”,成功了! 接下来,开始撸代码,在vtkdlgDlg.h头文件的CvtkdlgDlg类中添加以下代码,具体作用等写完所有代码后一并分析:

public: CString input_path; vtkMFCWindow* pvtkMFCWindow; vtkActor* pvtkActor; vtkDataSetMapper* pvtkDataSetMapper; vtkDataSetReader* pvtkDataSetReader; vtkRenderer* pvtkRenderer; vtkRenderWindow* pvtkRenderWindow; POINT ptBorder; void execute_pipeline();

在vtkdlgDlg.cpp文件中,找到CvtkdlgDlg的构造函数,修改如下:

CvtkdlgDlg::CvtkdlgDlg(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_VTKDLG_DIALOG, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); this->pvtkActor = vtkActor::New(); this->pvtkDataSetMapper = vtkDataSetMapper::New(); this->pvtkDataSetReader = nullptr; this->pvtkRenderer = vtkRenderer::New(); this->pvtkMFCWindow = nullptr; this->ptBorder = CPoint(0, 0); }

在vtkdlgDlg.cpp中添加execute_pipeline函数的实现:

void CvtkdlgDlg::execute_pipeline() { if (this->pvtkDataSetReader) { this->pvtkDataSetMapper->SetInputConnection(this->pvtkDataSetReader->GetOutputPort()); this->pvtkActor->SetMapper(this->pvtkDataSetMapper); this->pvtkActor->GetProperty()->SetColor(0.0, 0.0, 1.0); this->pvtkRenderer->SetBackground(1.0, 1.0, 1.0); this->pvtkRenderer->AddActor(this->pvtkActor); } else { this->pvtkRenderer->SetBackground(1.0, 1.0, 1.0); } this->pvtkRenderer->ResetCamera(); }

在CvtkdlgDlg::OnInitDialog()函数中添加以下代码,这部分代码写在//TODO后,return TRUE之前:

// TODO: 在此添加额外的初始化代码 this->pvtkMFCWindow = new vtkMFCWindow(this->GetDlgItem(IDC_STATIC)); CRect cRectClient; this->pvtkMFCWindow->GetClientRect(&cRectClient); this->pvtkMFCWindow->GetRenderWindow()->AddRenderer(this->pvtkRenderer); execute_pipeline();

下面切换到“资源视图”,我们来编辑对话框,只需要两步,很简单。 (1)删除其余控件,只留下“确认”,把“确认”改成“打开”。 (2)添加一个Picture Control空间。 这一步的效果图如下: 双击“打开”按钮,修改为以下代码,并在文件开头添加包含头文件#include string:

void CvtkdlgDlg::OnBnClickedOk() { // TODO: 在此添加控件通知处理程序代码 //CDialogEx::OnOK(); CString sz = _T("MyType Files (*.vtk)|*.vtk"); CFileDialog dlg(true, _T(".*"), NULL, OFN_FILEMUSTEXIST | OFN_HIDEREADONLY, sz, this); if (IDOK == dlg.DoModal()) { this->input_path = dlg.GetPathName(); UpdateData(false); this->pvtkRenderer->RemoveActor(this->pvtkActor); std::string str(CT2A(dlg.GetPathName())); if (!this->pvtkDataSetReader) this->pvtkDataSetReader = vtkDataSetReader::New(); this->pvtkDataSetReader->SetFileName(str.c_str()); execute_pipeline(); if (this->pvtkMFCWindow) this->pvtkMFCWindow->RedrawWindow(); } }

然后在类向导里面重载虚函数PostNcDestory,添加OnDestory的消处理 代码修改如下:

void CvtkdlgDlg::PostNcDestroy() { // TODO: 在此添加专用代码和/或调用基类 delete this; CDialogEx::PostNcDestroy(); } void CvtkdlgDlg::OnDestroy() { CDialogEx::OnDestroy(); // TODO: 在此处添加消处理程序代码 if (this->pvtkMFCWindow != nullptr) delete this->pvtkMFCWindow; this->pvtkRenderer->Delete(); this->pvtkDataSetMapper->Delete(); if (this->pvtkDataSetReader != nullptr) this->pvtkDataSetReader->Delete(); this->pvtkDataSetReader = nullptr; this->pvtkActor->Delete(); }

主要代码已经写好了,再次点击“生成”。完了!有一大堆无法解析的外部符号。再次回到之前的vtk-prefix文件夹,里面有lib库。点击“项目”–>属性–>链接器–>输入–>附件依赖项,将所有的lib都添加,用通配符的写法就是*.lib: 依旧没有解决问题,其实这里需要编译64位的版本,如下修改即可: 好了,编译成功!我们来运行一下,失败了,没完没了吗!在这里还有最后一步,将vtk-prefix文件夹中的bin文件夹下的所有dll文件拷贝到编译工程下即可,另外还有一个中方法,拷贝到system路径下(这种方式会对所有的程序都生效),我使用的是拷贝到编译工程下: 再次运行,弹出了错误,这已经不是代码的问题了,是新版本的vtk代码还需要有一个环境初始化过程,在以前的版本(5.x.x)是没有这个问题的,在vtkdlgDlg.h文件中添加以下代码:

#include "vtkAutoInit.h" VTK_MODULE_INIT(vtkRenderingOpenGL2); // VTK was built with vtkRenderingOpenGL2 VTK_MODULE_INIT(vtkInteractionStyle);

最后,你可能还会遇到依旧不能运行的情况,如果单步执行下去,定位到是这行代码出问题:

this->pvtkMFCWindow = new vtkMFCWindow(this->GetDlgItem(IDC_STATIC));

可以进行如下修改: 修改成“使用多字节字符集”。 再次运行,you got it! 怎么和说好的不一样,那是还没有打开文件,限于篇幅太长,讲在下一讲打开文件和分析代码。 更多VTK教程,请VX搜索CodeKit。

本文标签: 教程VTK