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