日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

VTK修炼之道10:可视化管道的连接与执行

發布時間:2025/3/15 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 VTK修炼之道10:可视化管道的连接与执行 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.可視化管道綜述

vtkProp;? vtkAbstractMapper; vtkProperty;? vtkCamera;? vtkLight;? vtkRenderer;? vtkRenderWindow; vtkRenderWindowInteractor;? vtkTransform;? vtkLookupTable ……
我們發現,這些類都是與數據顯示或者說渲染相關的。用一個專業的詞匯來說,它們構成了VTK的渲染引擎(Rendering Engine)。渲染引擎主要負責數據的可視化表達,它是VTK里的兩個重要模塊之一,另外一個重要的模塊就是可視化管線(Visualization Pipeline)。
可視化管線是指用于獲取或創建數據,處理數據,以及把數據寫入文件或者把數據傳遞給渲染引擎進行顯示,這樣的一種結構在VTK里就稱之為可視化管線。數據對象(Data Object)處理對象(Process Object)數據流方向(Direction of Data Flow)是可視化管線的三個基本要素。每個VTK程序都會有可視化管線存在。


我們再來仔細研究一個稍微復雜點的可視化管線例子,這個例子也是有東靈組合首次開發的!在這個示例里,先讀入后綴為vtk的文件,然后用體繪制法(vtkMarchingCubes)提取等值面,最后把等值面數據經Mapper送往渲染引擎進行顯示,示例完整代碼如下:
#include <vtkAutoInit.h> VTK_MODULE_INIT(vtkRenderingOpenGL);#include<vtkSmartPointer.h> #include<vtkStructuredPointsReader.h> #include<vtkPolyDataMapper.h> #include<vtkMarchingCubes.h> #include<vtkActor.h> #include<vtkRenderer.h> #include<vtkRenderWindow.h> #include<vtkRenderWindowInteractor.h>int main(int argc, char* argv[]) {//讀入Structurered_Points類型的vtk文件vtkSmartPointer<vtkStructuredPointsReader> reader = vtkSmartPointer<vtkStructuredPointsReader>::New();reader->SetFileName("data/head.vtk");//路徑//體繪制方法提取等值面vtkSmartPointer<vtkMarchingCubes> marchingCubes = vtkSmartPointer<vtkMarchingCubes>::New();marchingCubes->SetInputConnection(reader->GetOutputPort());marchingCubes->SetValue(0,1500); //等值面應該是關心的解剖結構//將生成的等值面數據進行MappervtkSmartPointer<vtkPolyDataMapper> mapper =vtkSmartPointer<vtkPolyDataMapper>::New();mapper->SetInputConnection(marchingCubes->GetOutputPort());//送入到數據映射器中處理//把Mapper的輸出送入渲染引擎進行顯示/*************************渲染引擎******************************/vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();actor->SetMapper(mapper); //演員化妝vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();renderer->AddActor(actor);//演員放到舞臺上renderer->SetBackground(1.0, 0, 0);//設置舞臺背景vtkSmartPointer<vtkRenderWindow> renWin = vtkSmartPointer<vtkRenderWindow>::New();renWin->AddRenderer(renderer);//舞臺搬進戲院renWin->SetSize( 640, 480 );//戲院大小renWin->Render(); //戲院渲染renWin->SetWindowName("vtkPipelineDemo");//戲院起名vtkSmartPointer<vtkRenderWindowInteractor> interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();interactor->SetRenderWindow(renWin);//與看客交互interactor->Initialize();interactor->Start();return 0; }輸出結果: ? ? ? ? ??

2.可視化管道細節

和前面的試驗程序相比,可以知道,圖4.9多了一個vtkMarchingCubes用于處理讀入的數據。在VTK里,我們把與vtkMarchingCubes類似的對數據做處理的類稱為Filter。 更一般的VTK可視化管道流程如下所示:
Source是指用于創建數據(如vtkCylinderSource)或者讀取數據(如vtkBMPReader、vtkStructuredPointsReader等)的類的統稱,即VTK的數據源。Source輸出的數據作為Filter的輸入,經Filter處理以后(可以經多個Filter處理),生成新的數據。Filter的輸出可以直接寫入文件,或者經Mapper變換后送入渲染引擎進行渲染、顯示,結束可視化管線。
可視化管線的三要素分別是數據對象、處理對象和數據流方向,Source、Filter和Mapper一起就構成了處理對象,它們的區別是基于數據流的初始化、維持和終止。根據數據的生成方式,Source可以分為Procedural對象(如vtkCylinderSource,通過程序代碼生成相關的數據)和Reader對象(如vtkBMPReader,從外部文件中導入數據)。
關于Source、Filter和Mapper的區別可以簡單地通過下圖區分。Source沒有輸入,但至少有一個輸出Filter可以有一個或多個輸入,產生一個或多個輸出Mapper接受一個或多個的輸出,但沒有輸出,寫文件的Writer(如vtkBMPWriter)可以看作是Mapper,負責把數據寫入文件或者流(Stream)中,因此,Mapper是可視化管線的終點,同時也是可視化管線和渲染引擎(有時也稱之為圖形管線)的橋梁。

3.如何連接可視化管道?

可視化管線里各個模塊的連接是通過接口SetInputConnection()GetOutputPort()來完成的。
marchingCubes->SetInputConnection(reader->GetOutputPort());
上行代碼把reader的輸出(由GetOutputPort()得到)作為marchingCubes的輸入(SetInputConnection()設置其輸入)
vtkMarchingCubes作為Filter只接受一個輸入,Filter概括起來有以下三種類型:單個輸入,產生單個輸出;多個輸入,產生單個輸出,但輸出的數據可有多種用途,比如,我們讀入數據以后,可以對其作等值面提取,另外還可以針對讀入的數據生成輪廓線(Outline);第三種Filter是單個輸入,產生多個輸出。

使用SetInputConnection()和GetOutputPort()連接可視化管線時,還要求連接的兩部分之間的數據類型必須一樣。由于管線是運行時才執行的,如果連接的兩部分類型不匹配,程序運行時就會報錯。比如,vtkMarchingCubes要求輸入的是vtkImageData類型的數據,如果我們給它輸入的是vtkPolyData類型的,程序運行時就會報誤。

4.可視化管道是如何執行的?

可視化管線連接完成后,必須有一種機制來控制管線的執行。比如某些時候,對某一部分數據做了改變,我們希望得到的結果是:改變的這部分數據在可視化管線里作更新,而其他沒做改變的數據則不要去驚動它。如下圖,假如Filter D的輸入發生了變化,E和F是依賴于D的輸入的,所以紅色虛線框內的部分是需要重新執行的管線,而C和G是另外一個分支,D輸入改變不影響C和G,所以,為了節省運行時間,C和G是不需要重新執行的。畢竟對于三維的應用程序來說,一般所處理的數據都是大得驚人的,如果真能做到這樣,也有利于提高程序的運行速率。

VTK采用一種叫做“惰性賦值”(LazyEvaluation)的方案來控制管線的執行,惰性賦值是指根據每個對象的內部修改時間來決定什么時候執行管線,只有當你或者程序發出“請求數據”時,管線才會被執行(前面提到vtkObject里有一個重要的成員變量MTime,管線里的每個從vtkObject派生的類的對象都會跟蹤自己的內部修改時間,當遇到“請求數據”時,該對象會比較這個修改時間,如果發現修改時間發生了改變,對象就會執行)。換言之,VTK是采用命令驅動(Demand Driven)的方法來控制管線的執行,這種方法的好處是,當對數據對象作了更改時,不必立即作計算,只有當發出請求時才開始處理,這樣能最小化計算所需的時間,以便更流暢地與數據進行交互。

解釋代碼如下: vtkSmartPointer<vtkBMPReader> reader =vtkSmartPointer<vtkBMPReader>::New(); reader->SetFileName("../doling.bmp");vtkImageData* imageData =reader->GetOutput(); int extent[6]; imageData->GetWholeExtent(extent); std::cout<<"Extent of image:"<<extent[0]<<" "<<extent[1]<<" "<<extent[2]<<""<<extent[3]<<" "<<extent[4]<<" "<<extent[5]<<""<<std::endl;我們先讀入一幅BMP圖像,然后把reader的輸出值賦給imageData,接著我們想知道讀入的圖像到底有多長多寬多高,調用的方法是vtkImageData里的GetWholeExtent()。但是我們卻得不到我們想要的結果,輸出為:“Extent of image: 0 -10 -1 0 -1”,而我們讀入的圖像是640×480大小,輸出結果應該是:“Extent of image: 0 640 0 480 0 0”才對。這就是因為我們沒有“請求數據”(RequestData()),在reader->GetOutput()之后,調用reader->Update(),就會迫使管線的執行,也就是reader才會從磁盤中讀取數據,從而才可以獲取imageData里的相關信息

通常,我們不用顯性地去調用Update()函數,因為在渲染引擎的最后,當我們調用Render()函數的時候,Actor就會收到渲染請求,接著Actor會請求Mapper給它發送數據,而Mapper又會請求上一層的Filter的數據,Filter最后去請求Source給它數據,于是,整條管線就被執行。除非像上面的代碼段里列出的,讀入數據以后,中間想要輸出某些信息,在得到這些信息之前,你就應該顯性地調用Update()函數。管線的執行過程大致如下圖所示。

5.參考資料

《More Effective C++》
《C++ primer》
《The VTK User’s Guide – 11thEdition》
《The Visualization Toolkit – AnObject-Oriented Approach To 3D Graphics (4th Edition)》

總結

以上是生活随笔為你收集整理的VTK修炼之道10:可视化管道的连接与执行的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。