生活随笔
收集整理的這篇文章主要介紹了
基于VTK的MFC应用程序开发(2)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
基于VTK的MFC應用程序開發(2)
分類: VTK應用示例 2013-03-29 13:03 6647人閱讀 收藏 舉報
MFCVTK圖像重采樣
目錄(?)[+]
現在基于VTK的MFC程序框架已經搭建起來。這一節我們來對上節的程序進行擴展,實現圖像的重采樣。重采樣是圖像處理中的一個常見功能,尤其是在醫學圖像處理中,一些三維圖像數據量非常大,對于內存的要求比較高,在處理時為了時間和空間效率的平衡,對圖像進行重采樣(降采樣);另外還有的應用如配準中,為了保持圖像的維數一致,還可能對圖像進行升采樣。但是在目前常使用到的醫學圖像處理軟件中,并沒有提供重采樣的功能。這個也是本程序開發的初衷,在講述重采樣的原理的同時,提供一個方便的圖像重采樣軟件。
關于圖像重采樣的內容在VTK在圖像處理中的應用(5)一文中也已經介紹過。圖像重采樣實際上是一個插值的過程。原圖像的像素可以看做一些規則分布的離散點,而重采樣則意味在這些離散點的基礎上通過插值的方式來計算新的離散點的灰度值。最簡單的差值方式為最近鄰法,即取原圖像中距離當前采樣點最近的像素值作為當前采樣點的輸出,這種方式計算簡單,但是誤差比較大,圖像失真比較嚴重;第二種也是一個最常用的方式是線性差值方式,二維圖像對應雙線性插值(利用當前新采樣點周圍的四個原圖像像素點進行線性插值),三維圖像則是利用周圍的8個像素點進行三次線性插值。采用線性插值方式計算相對也比較簡單,但是同樣會對圖像具有平滑效果。另外還有三次多項式插值,B樣條插值等方式,這種方式計算量比較大,但是精度比較高。這些方式可以根據不同的需要進行選擇。
本篇內容將以線性插值方式為主,實現一個圖像重采樣應用程序,利用該程序可以方便的進行圖像的重采樣;同時,在本篇中還會介紹怎樣利用CMake在MFC框架添加一個新類。關于如果搭建基于VTK的單文檔程序,請參閱基于VTK的MFC應用程序開發(1)。
?
1.??添加一個對話框資源
?
?
添加相應的控件,設置對話框及控件ID。界面設計如上。用戶首先需要選擇改變圖像的維數或者圖像的像素間隔。這兩個參數是相互關聯的,即在每個方向上修改其中一個時,另一個也會隨之改變,而兩者的乘積保持不變。因此這里用戶可以選擇修改圖像的維數還是像素間隔來進行重采樣。采樣參數共有6個,分別為X方向維數,Y方向維數,Z方向維數,X方向像素間隔,Y方向像素間隔和Z方向像素間隔。像素間隔在醫學圖像中是一個很重要的參數,表示像素的物理尺寸,普通圖像較少使用,默認值為1。維數或者圖像像素間隔,每次只能一項。當圖像的某個方向的維數為1時,則不能進行重采樣。
?
2.? 將對話框添加為類
?
設置類的名字CResampleDialog,并選擇基類為CDialog。這里需要注意的是,由于MFC工程通常代碼文件與工程文件是在一個路徑下,這里添加對話框類文件后,這些文件的路徑將會是在工程路徑下即bin目錄中。而我們采用CMake來管理工程,代碼文件與工程文件是分離的,因此這里不妨將.h文件和.cpp文件的路徑設置為代碼路徑下,如下圖所示紅色區域顯示:
?
?
點擊完成后,可以發現在代碼路徑中多出了兩個文件,即新添加的類文件。與此同時,在工程的解決方案中,同樣會多出了兩個文件,如下圖中所示。
?
?
這樣為了使用CMake進行管理,將兩個文件從工程的解決方案中刪除,并添加至CMakeLists.txt文件中,此時該工程的CMakeLists.txt文件內容如下。使用CMake對MFC工程進行管理時,添加類的過程相對比較麻煩。不知道是否還有更方便的方法,如果有,也歡迎各位賜教。
[plain] view plaincopy
#----------------------------------------------------------------------------------????cmake_minimum_required(?VERSION?2.8?)????project(?vtkSDI?)????#----------------------------------------------------------------------------------????#?查找并包含VTK工具包????find_package(?VTK?)????if?(VTK_FOUND)??????include?(${VTK_USE_FILE})????else?(VTK_FOUND)??????message?(FATAL_ERROR?"Cannot?build?without?VTK.?Please?set?VTK_DIR")????endif(?VTK_FOUND?)????#----------------------------------------------------------------------------------????#?這里添加本工程的文件????#?主要分為兩部分:????#?一是新建的單文檔程序中的非工程文件????#?二是用戶后續添加的類文件????SET(?PROJECT_SRCS????????MainFrm.h????????MainFrm.cpp???????????stdafx.h????????stdafx.cpp???????????vtkSDI.h????????vtkSDI.cpp???????????vtkSDIDoc.h????????vtkSDIDoc.cpp???????????vtkSDIView.h????????vtkSDIView.cpp???????????ResampleDialog.h????????ResampleDialog.cpp???????????targetver.h????????Resource.h????????vtkSDI.rc??????????????res/vtkSDI.rc2????????res/vtkSDI.ico????????res/vtkSDIDoc.ico????????res/Toolbar.bmp????????res/Toolbar256.bmp????????)??#----------------------------------------------------------------------------------????#?設置工程包含的vtk模塊,這里根據需要加載對應的模塊????include("${VTK_DIR}/GUISupport/MFC/VTKMFCSettings.cmake")????set(?VTK_LIBS?${vtk_libraries}???????????????????vtkMFC??????????????????vtkIO??????????????????vtkRendering???????????????????vtkGraphics???????????????????vtkHybrid???????????????????vtkFiltering???????????????????vtkCommon???????????????????vtkImaging????????)????VTK_MFC_ADD_DELAYLOAD_FLAGS(CMAKE_EXE_LINKER_FLAGS????????vtkMFC.dll????????vtkIO.dll????????vtkRendering.dll????????vtkGraphics.dll????????vtkHybrid.dll????????vtkFiltering.dll????????vtkCommon.dll????????vtkImaging.dll????????)??#----------------------------------------------------------------------------------????ADD_EXECUTABLE(?vtkSDI?WIN32??${PROJECT_SRCS}?)????TARGET_LINK_LIBRARIES?(?vtkSDI?${VTK_LIBS}?)??#----------------------------------------------------------------------------------??
?
3.??實現圖像重采樣對話框類
?
主要實現構造函數,初始化函數,Radio消息響應,文本框消息響應,確定和取消按鈕消息響應。由于維數與間隔兩個參數是互斥的,在修改一個同時另外一個要隨之改變。例如一個圖像X方向的維數為200,像素間隔為1.0,當用戶改變其維數為100時,像素間隔就要相應的變為2.0。
?
4.??實現圖像動態加載
?
為了盡可能多的支持圖像類型,而不是單一的支持一種圖像,對圖像加載函數進行修改。代碼中出現了一個新的類vtkImageReader2Factory,該類能夠根據設置的圖像路徑名字來返回一個可用的圖像讀取類對象,找不到則返回NULL。這樣的話便能夠根據不同的圖像類型自適應讀取圖像。
?
[cpp] view plaincopy
void?CvtkSDIDoc::OnFileOpen()??{????????????CString?FilePathName;??????m_pImageData?=?NULL;????????CFileDialog?dlg(TRUE,?NULL,?NULL,??????????????????OFN_HIDEREADONLY?|?OFN_OVERWRITEPROMPT,??????????????????(LPCTSTR)_TEXT("All?Files?(*.*)|*.*||"),??????????????????????NULL);????????if(dlg.DoModal()==IDOK)??????{??????????FilePathName=dlg.GetPathName();??????????????????????????????vtkSmartPointer<vtkImageReader2Factory>?readerFactory?=??????????????vtkSmartPointer<vtkImageReader2Factory>::New();??????????vtkImageReader2?*?reader?=???????????????readerFactory->CreateImageReader2(FilePathName.GetBuffer(0));??????????if?(reader)??????????{??????????????reader->SetFileName(FilePathName.GetBuffer(0));??????????????reader->Update();????????????????m_pImageData?=?reader->GetOutput();??????????????reader->Delete();????????????????UpdateAllViews(0);??????????}??????????else??????????{??????????????AfxMessageBox("Image?Format?is?not?supported?now!");??????????}??????}??????else??????{??????????return;??????}??}??
?
5. ?添加圖像重采樣菜單及響應
?
?
將菜單的響應函數響應到CvtkSDIDoc類中。當用戶調用該菜單時,彈出重采樣設置對話框,由用戶設置參數。根據用戶設置的參數對圖像進行重采樣,代碼如下。
?
[cpp] view plaincopy
void?CvtkSDIDoc::OnSizeResample()????{?????????????????????????????int?dims[3];????????m_pImageData->GetDimensions(dims);?????????????double?spaces[3];????????m_pImageData->GetSpacing(spaces);?????????????CResampleDialog?dlg(dims[0],?dims[1],?dims[2],?spaces[0],?spaces[1],?spaces[2]);????????if(dlg.DoModal()?==?IDOK)????????{????????????????????????int?dx?=?dlg.m_iDx;????????????int?dy?=?dlg.m_iDy;????????????int?dz?=?dlg.m_iDz;?????????????????float?sx?=?dlg.m_fSx;????????????float?sy?=?dlg.m_fSy;????????????float?sz?=?dlg.m_fSz;?????????????????vtkSmartPointer<vtkImageResample>?resample?=?????????????????vtkSmartPointer<vtkImageResample>::New();?????????????????resample->SetInput(m_pImageData);????????????resample->SetAxisOutputSpacing(0,?sx);????????????resample->SetAxisOutputSpacing(1,?sy);????????????resample->SetAxisOutputSpacing(2,?sz);????????????resample->SetInterpolationModeToLinear();????????????resample->Update();?????????????????m_pImageData?=?NULL;????????????m_pImageData?=?resample->GetOutput();????????????UpdateAllViews(0);????????}????}??
首先根據當前圖像的維數和像素間隔信息初始化重采樣對話框,當用戶設置完畢新的圖像維數和間隔并確定后,開始執行重采樣。重采樣采用vtkImageResample,該類繼承自vtkImageReslice。vtkImageReslice在圖像處理章節中介紹過,可以提取圖像的任意切面,是一個功能非常強大的類。vtkImageResample中通過SetAxisOutputSpacing()函數設置坐標軸的像素寬度,如0對應x軸,1對應y軸,2對應z軸。而函數SetInterpolationModeToLinear()則可以設置采樣的插值函數類型,這里采用線性插值方式。最后將執行的結果進行保存,并更新視圖顯示新的采樣圖像。但是,當更新視圖后,我們發現圖像顯示的大小并沒有發生變化。這是因為,在改變圖像維數的時候,像素間隔也隨之改變。維數增大,像素間隔變小;反之,像素間隔增大。而圖像的物理大小(維數*像素間隔)是不變的,所以在顯示的時候,圖像是沒有改變的。這與一般的圖像采樣有所區別。不過,當我們把圖像保存為一般的圖像格式時,便可以看出變化了。
?
6.? 保存圖像
?
重新響應菜單File中的Save菜單,實現保存當前圖像。這里對保存圖像進行分析,獲取文件的后綴,根據不同的格式調用相應的類進行保存,主要支持bmp,jpg,png,tif,mhd和mha。
?
[cpp] view plaincopy
void?CvtkSDIDoc::OnFileSave()??{??????????????if(m_pImageData?==?NULL)?return;????????CString?FilePathName;????????CFileDialog?dlg(FALSE,?NULL,?NULL,??????????OFN_HIDEREADONLY?|?OFN_OVERWRITEPROMPT,??????????(LPCTSTR)_TEXT("All?Files?(*.*)|*.*||"),??????????NULL);????????if(dlg.DoModal()==IDOK)??????{??????????FilePathName=dlg.GetPathName();??????????m_ImageFormat?=???FilePathName.Right(FilePathName.GetLength()-FilePathName.ReverseFind('.')-1);??????????if(m_ImageFormat?==?"")?m_ImageFormat?=?"mhd";????????????if(m_ImageFormat.Compare("bmp")?==?0)??????????{??????????????vtkSmartPointer<vtkBMPWriter>?writer???=?vtkSmartPointer<vtkBMPWriter>::New();??????????????writer->SetFileName(FilePathName.GetBuffer(0));??????????????writer->SetInput(m_pImageData);??????????????writer->Write();??????????}????????????if(m_ImageFormat.Compare("jpg")?==?0)??????????{??????????????vtkSmartPointer<vtkJPEGWriter>?writer???=?vtkSmartPointer<vtkJPEGWriter>::New();??????????????writer->SetFileName(FilePathName.GetBuffer(0));??????????????writer->SetInput(m_pImageData);??????????????writer->?Write?();??????????}????????????if(m_ImageFormat.Compare("tif")?==?0)??????????{??????????????vtkSmartPointer<vtkTIFFWriter>?writer???=?vtkSmartPointer<vtkTIFFWriter>::New();??????????????writer->SetFileName(FilePathName.GetBuffer(0));??????????????writer->SetInput(m_pImageData);??????????????writer->?Write?();??????????}????????????if(m_ImageFormat.Compare("png")?==?0)??????????{??????????????vtkSmartPointer<vtkPNGWriter>?writer???=?vtkSmartPointer<vtkPNGWriter>::New();??????????????writer->SetFileName(FilePathName.GetBuffer(0));??????????????writer->SetInput(m_pImageData);??????????????writer->Update();??????????}????????????if(m_ImageFormat.Compare("mhd")?==?0)??????????{??????????????vtkSmartPointer<vtkMetaImageWriter>?writer???=?vtkSmartPointer<vtkMetaImageWriter>::New();??????????????writer->SetFileName(FilePathName.GetBuffer(0));??????????????writer->SetInput(m_pImageData);??????????????writer->?Write?();??????????}????????}??????else??????{??????????return;??????}??}??
下圖中左側圖像的大小為1024*768,采用本篇的程序進行重采樣為512*768,保存的結果如右圖所示。可以看出圖像在X方向上維數減少一半。
?
?? ??
?
到此,基于VTK的圖像重采樣程序已經實現完畢。該程序支持基本的圖像格式,并可以將當前圖像根據需要進行存儲,存儲格式目前支持bmp,jpg,png,tif,mhd和mha。對圖像進行重采樣時,需要選擇改變維數或者改變像素間隔,滿足用戶不同的需求。程序執行效果如下。
?
?
==========歡迎轉載,轉載時請保留該聲明信息==========
版權歸@東靈工作室所有,更多信息請訪問東靈工作室
教程系列導航:http://blog.csdn.net/www_doling_net/article/details/8763686
================================================
總結
以上是生活随笔為你收集整理的基于VTK的MFC应用程序开发(2)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。