梁博 曾齊紅 劉遠(yuǎn)剛 鄧帆 邵燕林
摘要:針對露頭影像裂縫特征識別與矢量化問題,提出基于c++與MATLAB混合編程的裂縫識別及矢量化方法。調(diào)用MATLAB中的圖像裂縫識別函數(shù)快速提取露頭裂縫,同時采用一種改進(jìn)的八鄰域追蹤算法實現(xiàn)裂縫線狀要素的矢量化。實驗結(jié)果表明,該方法將c++與MATLAB二者優(yōu)勢互補,兼顧了程序的開發(fā)效率與執(zhí)行效率;改進(jìn)的八鄰域追蹤算法,在追蹤過程中自動簡化線要素,既壓縮了裂縫矢量數(shù)據(jù)的存儲空間,也提高了八鄰域追蹤算法的效率。
關(guān)鍵詞:混合編程;MATLAB;C++;八鄰域追蹤;矢柵轉(zhuǎn)換
中圖分類號:P208 文獻(xiàn)標(biāo)識碼:A 文章編號:1006-8228(2020)07-72-04
0引言
露頭作為探索地下礦物油藏、反映地質(zhì)運動的有利憑證,在地質(zhì)研究中起到關(guān)鍵性作用,對露頭表面裂縫線狀要素進(jìn)行自動識別與矢量化對露頭數(shù)字模型建立和露頭表面裂縫特征分析具有重要意義。MATLAB憑借其強大的數(shù)值計算能力被廣泛應(yīng)用于數(shù)字圖像處理、數(shù)值分析、算法開發(fā)等眾多領(lǐng)域,將MATLAB應(yīng)用于露頭表面裂縫識別,可大大提高開發(fā)效率。其作為一門解釋性編程語言,MATLAB也存在諸多短板,例如代碼執(zhí)行效率低、源代碼保密性較差、界面開發(fā)能力較差等。而c++作為一門面向?qū)ο蟮某绦蛟O(shè)計語言,執(zhí)行效率較高,程序開發(fā)較為靈活且易于維護(hù),但與MATLAB相比在圖像處理算法實現(xiàn)上較為復(fù)雜,若算法涉及大量的工程計算,僅僅依靠c++進(jìn)行算法開發(fā)顯然要繁瑣許多,不僅降低了開發(fā)效率,而且增加了出錯的風(fēng)險。實際應(yīng)用中,若能將c++與MATLAB二者優(yōu)勢互補,將大大提高編程效率,同時也保證了程序的執(zhí)行效率與靈活性。
針對以上問題,筆者提出將c++與MATLAB混合編程應(yīng)用于露頭表面線狀要素識別及矢量化方法的研究。在前期研究工作中,已經(jīng)利用MATLAB開發(fā)了露頭表面裂縫線狀要素識別與提取算法,本文將具體介紹如何利用c++調(diào)用MATLAB所實現(xiàn)的算法,提取露頭圖像中的裂縫特征,并利用c++實現(xiàn)一種改進(jìn)的線狀要素矢量化方法完成裂縫特征的矢量化。
1C++與MATLAB混合編程實現(xiàn)露頭裂縫識別
本文采用的露頭裂縫識別算法,是一個在MATLAB中封裝好的函數(shù)——Beamlet函數(shù)。研究中,為了實現(xiàn)露頭裂縫的識別,采用c++與MATLAB混合編程的方式,將MATLAB中的Beamlet函數(shù)發(fā)布成C++函數(shù)庫,在VS2017集成開發(fā)環(huán)境中,以及OpenCV跨平臺視覺庫的支持下,通過c++調(diào)Beamlet函數(shù)。
1.1 MATLAB函數(shù)編譯成C++庫文件
(1)開發(fā)環(huán)境
本文所有試驗均在windows 10操作系統(tǒng)下完成。c++開發(fā)環(huán)境為Microsoft Visual Smdio 2017,Matlab編程環(huán)境為Matlab 2016b,程序中采用的OpenCV版本為3.2.0。
(2)生成C++函數(shù)庫文件
Matlab編譯器使用mcc命令能將一個M文件編譯成c++能夠調(diào)用的頭文件及其函數(shù)庫。因此,采用mcc命令將Matlab中的圖像裂縫識別函數(shù)(Beamlet函數(shù))編譯成供C++調(diào)用的函數(shù)庫。具體過程包括:①首先在Matlab中準(zhǔn)備裂縫識別程序,并命名為Beamlet.m,該函數(shù)的功能是對露頭表面圖像進(jìn)行裂縫線狀要素識別,識別結(jié)果以柵格數(shù)據(jù)的形式輸出;②打開MATLAB軟件的命令窗口,輸入mcc命令:mex-setup,在出現(xiàn)的相應(yīng)界面中點擊選項:mex-setupC++;③輸入編譯命令:mcc-W cpplib:Beamlet-Tlink:lib add,其中“Beamlet”表示想要生成庫文件的名稱,點擊確定,開始編譯;④提示編譯成功,即成功將M文件編譯成c++函數(shù)庫,其中Beamlet.h、Beamlet.1ib和Beamlet.dll可供c++程序訪問。
1.2調(diào)用Beamlet算法識別裂縫
(1)配置C++項目
在VS2017中配置vc++項目,為調(diào)用圖像裂縫線狀要素識別函數(shù)做準(zhǔn)備。具體過程如下:①在VS2017中創(chuàng)建c++項目;②進(jìn)入項目的屬性頁,配置vc++目錄中的包含目錄與庫目錄,包含目錄:[Matlab安裝目錄]kR2016a\externkinclude;庫目錄:[Matlab安裝目錄]kR2016a\extern\lib\win64kmicrosoft;③向項目中添Beamlet.h、Beamlet.1ib、Beamlet.dll這3個文件;④在項目中加載Beamlet.1ib文件,即在項目中需要調(diào)用Beamlet算法的文件頭部添加命令:#pragma comment(lib,”Beamlet.lib”),鏈接Beamlet.1ib庫文件;⑤添加c+斗頭文件,#include,運行測試,完成配置。
(2)調(diào)用Beamlet函數(shù)
下面重點說明在vc++項目中用c++語句調(diào)用MATLAB函數(shù)的具體方法,圖1為c++調(diào)用Beamlet函數(shù)方法流程圖。
流程圖中算法具體步驟如下:
步驟1c++讀取圖像。采用OpenCV中Mat類讀取圖像,存入矩陣。
string path=”E:\\data\\1.jpg”;
cv::Mat image=imread(path,1):
//實例化Mat對象image,讀取圖像存入矩陣image
步驟2設(shè)置函數(shù)兩個輸入?yún)?shù)a,b。double a[1]:double b[1]
//用double類型數(shù)組a、b存放兩個參數(shù)
步驟3參數(shù)c++類型轉(zhuǎn)化為MATLAB類型。MATLAB函數(shù)均是以矩陣的形式進(jìn)行參數(shù)的輸入,輸出,因此,在調(diào)用函數(shù)時,需將參數(shù)轉(zhuǎn)換為mwArray類型進(jìn)行傳輸。
步驟9采用cv::Mat類對象存儲Beamlet函數(shù)的處理結(jié)果。
步驟1 0函數(shù)處理結(jié)果圖像顯示。
結(jié)果如圖2所示。
2改進(jìn)的八鄰域追蹤矢量化算法
如圖2所示,調(diào)用Beamlet算法識別的露頭裂縫為一張細(xì)化的二值圖像,圖中裂縫被識別為寬度為一個像素的柵格線。在柵格數(shù)據(jù)中采用緊密相連的柵格像元來表示線狀要素,而在矢量數(shù)據(jù)中只需記錄曲線折點的相應(yīng)坐標(biāo)便可以精確的表示線狀要素。為了精確表達(dá)裂縫特征,需要將柵格圖像轉(zhuǎn)為矢量圖形。在柵格轉(zhuǎn)矢量的過程中,若完全保留每個柵格像元的坐標(biāo),則會造成大量的冗余點,這是算法需要避免的。本文借助C++中的雙向隊列deque來存儲矢量曲線的坐標(biāo)點,采用一種改進(jìn)的八鄰域追蹤算法實現(xiàn)裂縫柵格圖像的矢量化,同時盡量壓縮矢量圖形上的定點數(shù)。
2.1八鄰域追蹤算法基本思路
當(dāng)進(jìn)行線狀要素追蹤時,與當(dāng)前像素點相鄰的像素點則稱作該點的8個鄰接像素,如圖3所示,設(shè)定種子點P1左上角點為鄰域點1,按順時針方向?qū)肃徲螯c分別標(biāo)號為①、②、…、。八鄰域追蹤算法基本思路如下:①在二值圖像中找到一個裂縫點(圖2中白色像素點)作為追蹤起點;②按照八方向搜索機制檢索相鄰裂縫點,當(dāng)找到相鄰裂縫點時,記錄下來并將起點從影像中刪除(賦值為背景顏色),然后以該鄰接點為新的起點繼續(xù)搜索;③若起點的八方向均未搜索到裂縫點,則終止本次搜索,并轉(zhuǎn)入①,開始下一條線的追蹤。
2.2線狀要素矢量化實現(xiàn)
本文采用OpenCV中的Mat類對象存儲Beamlet函數(shù)處理結(jié)果,即讀取線狀要素柵格圖像并存入矩陣。設(shè)a(i,j)為當(dāng)前柵格像素(i,j)的灰度值,像素點為白色(a(i,j)=255))或黑色(a(i,j)=0),當(dāng)前像素(i,j)的3×3鄰域矩陣如圖3所示。圖中點Pl為追蹤起點,其像素值a(i,J)=255,該點的①號鄰域點P2的值a(i-1,j-1)=255,說明P2是追蹤線上的下一個點。
在八鄰域追蹤算法的基礎(chǔ)上,本文提出了一種改進(jìn),改進(jìn)算法流程見圖4。主要步驟包括:①確定柵格影像追蹤起點;②從起點開始向八方向搜索相鄰點,搜索成功時,將該點賦值為背景色,記錄檢索方向并保存;③判斷此方向與上一點處所保存的方向是否一致,若一致,且此點不為該條線的端點,則舍棄該點繼續(xù)追蹤下一點,否則保留該點,而后將其作為新起點;④若新起點的八方向均未檢索成功,表示一條線的搜索已完成,將此線對象保存;⑤搜索另一線對象,直到全部遍歷完成。
該算法具有兩個優(yōu)點:①每次成功搜索到新的鄰接點時,記錄方向,下一次搜索時會率先搜索此方向,這符合普遍規(guī)律下線條的延伸狀態(tài),大大減少檢索的次數(shù),提高效率;②只存儲同一條線段的首尾兩點,在保留曲線的特征點(折點)的同時實現(xiàn)矢量數(shù)據(jù)壓縮。
最后調(diào)用本文實現(xiàn)的矢量化算法將Matlab模塊提取的裂縫圖像矢量化,并輸出為Shapefile格式。如圖5所示,為矢量化的裂縫圖形與對應(yīng)的露頭圖像疊加顯示的效果。
3結(jié)束語
本文提出基于c++與Matlab混合編程的露頭表面裂縫識別與矢量化方法,給出了實驗方案的總體設(shè)計、實驗思路詳細(xì)分析、算法設(shè)計及具體實現(xiàn),提供了類似問題完整解決方案。實驗效果表明:借助c++與Matlab混合編程成功調(diào)用Matlab函數(shù),參數(shù)的輸入與輸出主要依賴C++程序?qū)崿F(xiàn),后臺圖像數(shù)據(jù)的處理與運算主要由Matlab模塊函數(shù)實現(xiàn),充分結(jié)合了c++與Matlab各自的優(yōu)點,兼顧了程序的開發(fā)效率與執(zhí)行效率;通過一種改進(jìn)的八鄰域追蹤算法對柵格數(shù)據(jù)進(jìn)行矢量化,減少在追蹤過程中的鄰近點搜索次數(shù),提高算法效率同時減少了線狀圖形中的冗余頂點,實現(xiàn)了結(jié)果數(shù)據(jù)的壓縮。