当前位置: 首页 > news >正文

[VTK]基于VTK的三维重建

https://www.cnblogs.com/dawnWind/archive/2013/02/17/3D_06.html

0. Background

很久很久以前记录了一下使用WPF进行三维重建的一些探索,后来了解到了VTK这个开发包,

觉得功能很强大,因此后续都在基于VTK进行三维重建,在前文中对于VTK的一些相关网站进行了介绍

http://www.cnblogs.com/dawnWind/archive/2013/01/14/3D_04.html

这里就不再累赘了,感兴趣的Google一下即可。

对于VTK感兴趣的还可能会认识到与之相关的几个开发包。

其一是ITK:http://www.itk.org/

ITK始于著名的(VHP)Visible Human Project

http://www.nlm.nih.gov/research/visible/visible_gallery.html

简要地说VHP就是使用现代技术使用医学扫描等方式(如X光、CT、CMR等)获得人体二维图片,并根据这些图片构建出三维模型,

当然这里说要求的精度以及细度都非常高。人体的三维模型在我们头脑中可能立马会闪现很多电影里面有的场景,

一个组织脉络都清晰可见的人体呈现在我们面前。可以说在那个时代美国提出的这一科技项目不仅是高屋建瓴实际上

也给后续相关技术的发展带来了巨大的推动。

不过ITK说关注的更多是三维数据的测量、切割等,如果要进行三维呈现通常可以和VTK进行协作,这两者之间的数据

互通也很方便。不过对于ITK的了解我也就到此为止,并没有安装并使用过。

国内对于ITK、VTK开发包类似的研究主要由田捷带领开发的MITK,它整合ITK、VTK,为了达到一致简洁的开发,主要针对的领域是医学处理。

背景知识就这么多,接下来说一下使用VTK进行三维重建的基本步骤。

 

1. 3D Reconstruction with VTK

    先上码。

复制代码
 // 读取文件夹下图片,将图像进行轮廓提取后再进行三维重建
int build3DViewFull()
{     
    vtkSmartPointer<vtkRenderer> aRenderer = vtkSmartPointer<vtkRenderer>::New();
    vtkSmartPointer<vtkRenderWindow> renWin = vtkSmartPointer<vtkRenderWindow>::New();
    renWin->AddRenderer(aRenderer);

    vtkSmartPointer<vtkRenderWindowInteractor> iren =
        vtkSmartPointer<vtkRenderWindowInteractor>::New();
    iren->SetRenderWindow(renWin);

    // 新建文件读取对象,常见的有vtkBMPReader、vtkDICOMImageReader、vtkJPEGReader等
    vtkSmartPointer<vtkJPEGReader> jpegReader =
        vtkSmartPointer<vtkJPEGReader>::New();  
    // 不同的reader需要设置的参数是不同的 因此本例仅适合jpegreader
    jpegReader->SetFilePrefix("C:/Users/DawnWind/Desktop/000/"); // 要打开的路径
    jpegReader->SetFilePattern("%s%d.jpg"); // 图片文件名格式,此处为 0.jpg 1.jpg ...
    jpegReader->SetDataByteOrderToLittleEndian();
    jpegReader->SetDataSpacing(1, 1, 1.4);  // 设置图片中像素比,我理解得不清楚,具体请百度之
    jpegReader->SetFileNameSliceSpacing(1); 

    jpegReader->SetDataExtent(0, 209, 0, 209, 0, 29);
    // 这里因为在000文件夹里面有0.jpg ~ 29.jpg,所以设置为 0,29
    // 每张图片的长宽为210 * 210 因此设置为0,209

    jpegReader->Update();  
    // update这里要注意一下,对于VTK在默认情况下是在最后操作时候才一次性刷新
    // 也就是说如果没有自动刷新的话,在一些中间过程中是无法获得到数据的,因为没update进去
    

    vtkSmartPointer<vtkContourFilter> skinExtractor =
        vtkSmartPointer<vtkContourFilter>::New();
    skinExtractor->SetInputConnection(jpegReader->GetOutputPort());
    skinExtractor->SetValue(200, 100);    //值越大,保留的部分越少。

    //重新计算法向量
    vtkSmartPointer<vtkPolyDataNormals> skinNormals =
        vtkSmartPointer<vtkPolyDataNormals>::New();
    skinNormals->SetInputConnection(skinExtractor->GetOutputPort());
    skinNormals->SetFeatureAngle(60.0);      
    //Specify the angle that defines a sharp edge. 
    //If the difference in angle across neighboring polygons is greater than this value, 
    //the shared edge is considered "sharp". 


    //create triangle strips and/or poly-lines 为了更快的显示速度
    vtkSmartPointer<vtkStripper> skinStripper =        
        vtkSmartPointer<vtkStripper>::New();
    skinStripper->SetInputConnection(skinNormals->GetOutputPort()); 

    vtkSmartPointer<vtkPolyDataMapper> skinMapper =
        vtkSmartPointer<vtkPolyDataMapper>::New();
    skinMapper->SetInputConnection(skinStripper->GetOutputPort());
    skinMapper->ScalarVisibilityOff();    //这样不会带颜色


    vtkSmartPointer<vtkActor> skin =
        vtkSmartPointer<vtkActor>::New();
    skin->SetMapper(skinMapper); 

    // An outline provides context around the data.
    // 一个围绕在物体的立体框,可以先忽略
    /*
    vtkSmartPointer<vtkOutlineFilter> outlineData =
        vtkSmartPointer<vtkOutlineFilter>::New();
    outlineData->SetInputConnection(dicomReader->GetOutputPort());

    vtkSmartPointer<vtkPolyDataMapper> mapOutline =
        vtkSmartPointer<vtkPolyDataMapper>::New();
    mapOutline->SetInputConnection(outlineData->GetOutputPort());

    vtkSmartPointer<vtkActor> outline =
        vtkSmartPointer<vtkActor>::New();
    outline->SetMapper(mapOutline);
    outline->GetProperty()->SetColor(0,0,0);
 
    aRenderer->AddActor(outline);
    */
    // It is convenient to create an initial view of the data. The FocalPoint
    // and Position form a vector direction. Later on (ResetCamera() method)
    // this vector is used to position the camera to look at the data in
    // this direction.
    vtkSmartPointer<vtkCamera> aCamera =
        vtkSmartPointer<vtkCamera>::New();
    aCamera->SetViewUp (0, 0, -1);
    aCamera->SetPosition (0, 1, 0);
    aCamera->SetFocalPoint (0, 0, 0);
    aCamera->ComputeViewPlaneNormal();
    aCamera->Azimuth(30.0);
    aCamera->Elevation(30.0);

    // Actors are added to the renderer. An initial camera view is created.
    // The Dolly() method moves the camera towards the FocalPoint,
    // thereby enlarging the image.
    aRenderer->AddActor(skin);
    aRenderer->SetActiveCamera(aCamera);
    aRenderer->ResetCamera ();
    aCamera->Dolly(1.5);

    // Set a background color for the renderer and set the size of the
    // render window (expressed in pixels).
    aRenderer->SetBackground(.2, .3, .4);
    renWin->SetSize(640, 480);

    // Note that when camera movement occurs (as it does in the Dolly()
    // method), the clipping planes often need adjusting. Clipping planes
    // consist of two planes: near and far along the view direction. The 
    // near plane clips out objects in front of the plane; the far plane
    // clips out objects behind the plane. This way only what is drawn
    // between the planes is actually rendered.
    aRenderer->ResetCameraClippingRange ();

    // Initialize the event loop and then start it.
    iren->Initialize();
    iren->Start();
    return 0;
}
复制代码

 

通过上面代码的可以看出,对于一个三维重建是有一些必须步骤要走的。

一是要有输入源(上文中是reader读入的数据)通过处理构成的模型actor、二是要有相机(camera)、三要有用于展示的窗口(window)

其他的就是将其中的脉络理清了,可以仿照上面代码所述进行理解,具体理论可以去查找一下OpenGL的三维模型结构,其实与我前面说的

WPF三维模型相关理论是相通的。

可以获得类似下图结果:

号外:关于VTK的设置之类就没有多说了,假设大家已经可以运行VTK的示例

转载于:https://www.cnblogs.com/jukan/p/9036476.html

相关文章:

  • str的常用操作
  • MySQL数据库安装配置步骤详解
  • app测试测什么?
  • 两个比较快的DNS
  • linux下安装以及升级npm,node的方法
  • 对json的简单认识
  • Java的日期类和日期格式化类
  • 共享锁与排它锁区别(转)
  • netty6---序列化与反序列化
  • Loadrunner解决启动浏览器后页面显示空白
  • 将.py文件转换成.exe文件
  • Linux服务器系统安全
  • 分布式之数据库和缓存双写一致性方案解析
  • 【NOIP2008】【Vijos1493】传纸条
  • Mac 如何安装 chromedriver
  • 【5+】跨webview多页面 触发事件(二)
  • 10个最佳ES6特性 ES7与ES8的特性
  • angular2 简述
  • Apache Pulsar 2.1 重磅发布
  • canvas 绘制双线技巧
  • extract-text-webpack-plugin用法
  • JAVA之继承和多态
  • laravel 用artisan创建自己的模板
  • Python十分钟制作属于你自己的个性logo
  • rabbitmq延迟消息示例
  • 成为一名优秀的Developer的书单
  • 基于 Ueditor 的现代化编辑器 Neditor 1.5.4 发布
  • 深入浅出webpack学习(1)--核心概念
  • 跳前端坑前,先看看这个!!
  • 小程序上传图片到七牛云(支持多张上传,预览,删除)
  • 一些关于Rust在2019年的思考
  • 正则表达式小结
  • 《TCP IP 详解卷1:协议》阅读笔记 - 第六章
  • Spark2.4.0源码分析之WorldCount 默认shuffling并行度为200(九) ...
  • 移动端高清、多屏适配方案
  • # 手柄编程_北通阿修罗3动手评:一款兼具功能、操控性的电竞手柄
  • #define MODIFY_REG(REG, CLEARMASK, SETMASK)
  • #if #elif #endif
  • #我与Java虚拟机的故事#连载12:一本书带我深入Java领域
  • (02)vite环境变量配置
  • (10)工业界推荐系统-小红书推荐场景及内部实践【排序模型的特征】
  • (2)(2.4) TerraRanger Tower/Tower EVO(360度)
  • (6)添加vue-cookie
  • (Java岗)秋招打卡!一本学历拿下美团、阿里、快手、米哈游offer
  • (八)c52学习之旅-中断实验
  • (附源码)php投票系统 毕业设计 121500
  • (附源码)计算机毕业设计大学生兼职系统
  • (十)c52学习之旅-定时器实验
  • (一) storm的集群安装与配置
  • (一)为什么要选择C++
  • *1 计算机基础和操作系统基础及几大协议
  • .h头文件 .lib动态链接库文件 .dll 动态链接库
  • .Net Core缓存组件(MemoryCache)源码解析
  • .NET 编写一个可以异步等待循环中任何一个部分的 Awaiter
  • .net 无限分类