郭斯羽 溫和 孟志強(qiáng)
摘 要: 針對(duì)學(xué)生對(duì)《數(shù)字圖像處理》課程內(nèi)容感到抽象,對(duì)編程存在一定畏難情緒的狀況,提出利用可視化編程來提高學(xué)生對(duì)數(shù)字圖像處理實(shí)踐的參與程度。為此設(shè)計(jì)了一種基于XML的圖像處理可視化編程語言,為圖像處理任務(wù)的可視化編程打下了基礎(chǔ)。語言定義了圖像處理功能模塊和程序的結(jié)構(gòu),以包含可視化實(shí)現(xiàn)圖像處理流程的必要信息;給出了針對(duì)該語言的翻譯器的基本原理與關(guān)鍵步驟,能將可視化程序翻譯為m文件,從而能在MATLAB環(huán)境中執(zhí)行。基于所設(shè)計(jì)的語言和翻譯器能夠?qū)崿F(xiàn)可視化圖像處理程序設(shè)計(jì)軟件,并可引入不同難度層次的圖像處理編程訓(xùn)練,有助于學(xué)生掌握和運(yùn)用《數(shù)字圖像處理》課程的相關(guān)方法和技術(shù)。
關(guān)鍵詞: 數(shù)字圖像處理;可視化編程;XML;MATLAB
中圖分類號(hào): G434 文獻(xiàn)標(biāo)志碼:A 文章編號(hào):1673-8454(2017)08-0093-04
一、可視化圖像處理編程語言的設(shè)計(jì)目的
《數(shù)字圖像處理》是電子信息類專業(yè)一門重要的專業(yè)課,因其與機(jī)器視覺具有密切關(guān)系,在我國制造業(yè)升級(jí)的大環(huán)境下,該課程的教學(xué)更具有了重要的意義?!稊?shù)字圖像處理》實(shí)踐性強(qiáng),因此針對(duì)本課程的演示實(shí)驗(yàn)和學(xué)生動(dòng)手的課程實(shí)驗(yàn),已經(jīng)有許多研究者基于諸如Visual C++[1]、OpenCV[2,3]、ImageJ[4]、DSP[5,6]以及MATLAB[7-9]等不同軟件和技術(shù)提出了實(shí)驗(yàn)教學(xué)的方案。但從學(xué)生實(shí)際情況來看,若僅提供操作界面,通過菜單和按鈕操作來觀察圖像處理方法的效果,雖然能適應(yīng)多數(shù)學(xué)生的水平,也能幫助直觀了解有關(guān)方法的效果,但對(duì)方法的編程實(shí)現(xiàn)訓(xùn)練不足;但若使用某種編程語言來進(jìn)行實(shí)驗(yàn),哪怕是使用OpenCV或MATLAB這類直接支持圖像處理的語言,仍會(huì)使相當(dāng)部分的學(xué)生產(chǎn)生畏難情緒,且在實(shí)現(xiàn)過程中易于陷入語言本身的細(xì)節(jié)問題,難以專注于對(duì)特定圖像處理應(yīng)用的整體框架性理解。
在多年的教學(xué)過程中,學(xué)生普遍對(duì)可視化的編程工具表現(xiàn)出新奇感,較少產(chǎn)生畏難情緒,實(shí)驗(yàn)的參與度普遍較高。除此之外,可視化編程本身的框圖特性,能夠直觀便捷地描述出算法的主要步驟和流程。因此,本文設(shè)計(jì)了一種MATLAB環(huán)境下用于數(shù)字圖像處理的可視化編程語言xGIPL(XML-based Graphical Image Processing Language),它將相關(guān)實(shí)現(xiàn)代碼封裝為圖像處理“功能模塊”,使學(xué)生可以將注意力集中在整體算法步驟的理解上,而不用擔(dān)心語言細(xì)節(jié)?;谠撜Z言,可以開發(fā)面向圖像處理的可視化編程軟件,其用戶界面和操作類似于Simulink,即通過圖形化模塊設(shè)計(jì)界面或直接書寫所需要的XML模塊文件,來預(yù)先實(shí)現(xiàn)好所需的圖像處理步驟的功能,如圖像的二值化、顏色空間轉(zhuǎn)換、常用的濾波操作、區(qū)域標(biāo)記和特征提取等等,然后由用戶在可視化編程界面中通過拖放、刪除、連接模塊以及圖形化的設(shè)置模塊參數(shù)等操作,實(shí)現(xiàn)完整的圖像處理任務(wù)的編程,之后可視化編程軟件將負(fù)責(zé)分析和解釋所實(shí)現(xiàn)的圖形化程序,將其翻譯為MATLAB m文件函數(shù),并自動(dòng)在MATLAB執(zhí)行程序和返回處理結(jié)果。
二、圖像處理功能模塊的設(shè)計(jì)
圖像處理功能模塊(Image Processing Module,IPM)是具有輸入和輸出、完成特定圖像處理步驟的基本編程單元。在可視化編程界面中,每個(gè)IPM就是一個(gè)可獨(dú)立增減、拖拽并能夠與程序的其他部分通過連線相連接的實(shí)體。IPM的定義由IPM文件給出。我們用XML語言來定義模塊,因?yàn)閄ML語言本身具有靈活性和易讀性,能夠自由地定義所需的內(nèi)容;XML的編輯很方便,通過普通的文本編輯器即可進(jìn)行;此外在很多開發(fā)環(huán)境中,都有現(xiàn)成的XML解析器可用,從而大大方便了IPM和可視化圖像處理程序的翻譯過程。
1.IPM的具體設(shè)計(jì)
每個(gè)IPM的XML結(jié)構(gòu)中包含一個(gè)名為“ipmod”的根節(jié)點(diǎn),其下包含如下子節(jié)點(diǎn):①mod_name節(jié)點(diǎn)。給出了每個(gè)IPM在模塊庫中的全局唯一的標(biāo)識(shí),且與IPM的XML文件名相同;②mod_help節(jié)點(diǎn)。提供了本IPM的幫助信息,可在可視化編程界面中為用戶提供模塊的用法;③glyph節(jié)點(diǎn)。用于指定一個(gè)圖片文件路徑,以便在可視化編程界面中提供更加直觀和美觀的模塊外觀;④parent_group節(jié)點(diǎn)。用于以樹狀結(jié)構(gòu)組織和管理眾多IPM構(gòu)成的模塊庫;⑤port_pos節(jié)點(diǎn)。用于指定可視化界面中IPM的輸入輸出端口出現(xiàn)的位置。port_pos又包含兩個(gè)子節(jié)點(diǎn):inport_pos節(jié)點(diǎn)和outport_pos節(jié)點(diǎn),分別指定了輸入端口和輸出端口的位置;⑥inputs節(jié)點(diǎn)和outputs節(jié)點(diǎn)。分別用于定義與IPM的輸入和輸出有關(guān)的信息。在inputs節(jié)點(diǎn)和outputs節(jié)點(diǎn)之下,又分別可包含一個(gè)或多個(gè)inport節(jié)點(diǎn)和outport節(jié)點(diǎn),它們具體定義了每個(gè)輸入端口和輸出端口,其結(jié)構(gòu)稍后介紹。inputs節(jié)點(diǎn)和outputs節(jié)點(diǎn)為可選節(jié)點(diǎn),即一個(gè)IPM可以沒有輸入(沒有inputs節(jié)點(diǎn))或沒有輸出(沒有outputs節(jié)點(diǎn)),但不能兩者均無;⑦implement節(jié)點(diǎn)。給出了實(shí)現(xiàn)本IPM的處理功能的MATLAB代碼。
inputs節(jié)點(diǎn)下的inport節(jié)點(diǎn)及outputs節(jié)點(diǎn)下的outport節(jié)點(diǎn)定義了IPM的各輸入、輸出端口,相當(dāng)于IPM的輸入和輸出參數(shù)。inport節(jié)點(diǎn)和outport節(jié)點(diǎn)均包含如下子節(jié)點(diǎn):
(1)port_name節(jié)點(diǎn)。給出了該端口在IPM內(nèi)的唯一名稱,并且在IPM的implement代碼中通過“%port_name”的方式加以引用。
(2)port_help節(jié)點(diǎn)。給出了該端口的幫助性文本。
此外,inport節(jié)點(diǎn)還包含:
(3)可選的value_range節(jié)點(diǎn)。當(dāng)一個(gè)inport節(jié)點(diǎn)包含value_range節(jié)點(diǎn)時(shí),表示該端口的取值有一定的范圍限制,因此在可視化界面中可以采用適當(dāng)?shù)姆绞剑ㄈ鐫L動(dòng)條或下拉菜單等)更方便地加以設(shè)定。輸入端口的取值范圍又可采用如下三種形式之一:①整數(shù)取值范圍。用value_range節(jié)點(diǎn)下的int_range子節(jié)點(diǎn)表示,而int_range下又含一個(gè)max子節(jié)點(diǎn)和一個(gè)min子節(jié)點(diǎn),分別給出可選的整數(shù)值的上下限;②實(shí)數(shù)取值范圍。用real_range子節(jié)點(diǎn)表示,其下同樣包含一個(gè)max和一個(gè)min子節(jié)點(diǎn)來給出上下限;③類別型取值范圍。用cat_set字節(jié)點(diǎn)表示,其下包含若干cat子節(jié)點(diǎn),每個(gè)cat子節(jié)點(diǎn)的值一般為一個(gè)MATLAB字符串。
(4)可選的default節(jié)點(diǎn)。表明當(dāng)該輸入端口未與其他模塊的輸出端口相連,也沒有通過用戶編輯來設(shè)置一個(gè)值時(shí),該端口的缺省取值。若存在default節(jié)點(diǎn),則表明該輸入是可選參數(shù),否則輸入是必選參數(shù),必須由用戶通過上述兩種方式之一為其提供所需的值。
2.IPM示例
下面以一個(gè)示例性的ReadImage IPM的XML文件來說明所定義的結(jié)構(gòu)。ReadImage模塊定義的代碼如下,為簡(jiǎn)潔起見,其中略去了mod_help、glyph、port_pos、parent_group和port_help等非核心節(jié)點(diǎn):
...
if strcmp(%Format, 'Auto-determined')
%ImageData = imread(%Path);
else
%ImageData = imread(%Path, %Format);
end
由上述代碼可見,ReadImage模塊包含兩個(gè)輸入端口——Path端口和Format端口。Path端口用于指定待讀取的圖像文件的路徑,是必選端口,需要用戶在可視化編程的模塊編輯界面中輸入或通過其他模塊傳入;Format端口用于指定圖像文件的格式,具有類別型的取值范圍,指出了模塊支持的圖像文件格式,而缺省值為“Auto-determined”,即模塊根據(jù)文件后綴名自動(dòng)確定圖像文件格式。輸出端口只有一個(gè),即ImageData端口,是所讀取到的圖像數(shù)據(jù)矩陣。在implement節(jié)點(diǎn)中可以看到模塊功能的實(shí)現(xiàn)代碼。
三、可視化圖像處理程序的結(jié)構(gòu)設(shè)計(jì)
1.圖像處理程序的設(shè)計(jì)
在可視化編程界面上放置、拖拽和連接IPM的實(shí)例,即可構(gòu)成圖像處理程序(Image Processing Program,IPP)。我們同樣利用XML來作為程序源代碼的組織方式。圖像處理程序的XML根節(jié)點(diǎn)是“ipprog”節(jié)點(diǎn),其下包括1個(gè)memo節(jié)點(diǎn)和若干個(gè)block節(jié)點(diǎn)。memo節(jié)點(diǎn)僅是對(duì)IPP的描述和介紹,而構(gòu)成IPP實(shí)質(zhì)功能的部分是block節(jié)點(diǎn)。
block節(jié)點(diǎn)包含如下子節(jié)點(diǎn):
(1)block_name節(jié)點(diǎn)。block_name是程序中每個(gè)IPM實(shí)例在IPP范圍內(nèi)的唯一標(biāo)識(shí)。一個(gè)IPM可能在一個(gè)IPP中有多個(gè)實(shí)例,但這些實(shí)例必須具有不同的block_name。
(2)module節(jié)點(diǎn)。儲(chǔ)存了該IPM實(shí)例所使用的IPM的名字,即IPM定義中的mod_name。
(3)inputs節(jié)點(diǎn)。儲(chǔ)存了該IPM實(shí)例的輸入值的信息。inputs節(jié)點(diǎn)下包含一個(gè)或多個(gè)inport節(jié)點(diǎn),每個(gè)inport節(jié)點(diǎn)描述了相應(yīng)的輸入端口的輸入值信息,由如下子節(jié)點(diǎn)構(gòu)成:①port_name節(jié)點(diǎn)。輸入端口的端口名,即IPM定義中的port_name;②value_type節(jié)點(diǎn)。value_type節(jié)點(diǎn)的可能取值為“internal”或“external”。internal表示該端口的輸入值是由用戶在模塊編輯界面中輸入而來,并非來自其他IPM實(shí)例的輸出;external則表示該端口的輸入值由其他IPM實(shí)例的輸出所提供;③value節(jié)點(diǎn)。當(dāng)value_type為internal時(shí),用戶提供的輸入值儲(chǔ)存于value節(jié)點(diǎn)中;當(dāng)value_type為external時(shí),則不應(yīng)出現(xiàn)value節(jié)點(diǎn);④src_block節(jié)點(diǎn)和src_outport節(jié)點(diǎn)。當(dāng)value_type為external時(shí),src_block節(jié)點(diǎn)儲(chǔ)存了該輸入端口的輸入所來自的那個(gè)IPM實(shí)例的名字,即前述的block_name;src_outport節(jié)點(diǎn)指出了所來自的該IPM實(shí)例的具體輸出端口名。通過src_block和src_outport便隱含地描述了IPM間的連接情況。當(dāng)value_type為internal時(shí),不應(yīng)出現(xiàn)src_block和src_outport節(jié)點(diǎn)。
2.IPP示例
我們通過如下示例IPP來進(jìn)行說明:
這個(gè)簡(jiǎn)單的程序包括兩個(gè)IPM實(shí)例:reader和writer。reader模塊是一個(gè)ReadImage IPM,在程序的輸入設(shè)置下由“image.jpg”文件讀入圖像;writer模塊是一個(gè)SaveImage IPM,在程序的輸出設(shè)置下將reader讀入的圖像數(shù)據(jù)再保存為圖像文件“result.jpg”。
四、可視化圖像處理程序翻譯器
可視化圖像處理程序翻譯器的作用,是將IPP自動(dòng)轉(zhuǎn)為可在MATLAB中執(zhí)行的.m函數(shù)文件。翻譯器的基本工作思路是首先對(duì)IPM和IPP的XML文件進(jìn)行解析,獲取各個(gè)XML節(jié)點(diǎn)信息,然后以系統(tǒng)性的編碼和命名方式來產(chǎn)生所需的.m文件。
在完成XML文件解析后,先根據(jù)程序所用各IPM的implement元素,以子函數(shù)形式封裝這些代碼。封裝的主要思路是,利用IPM名作為子函數(shù)名,采用系統(tǒng)性的方法定義輸入輸出的變量名,例如對(duì)于第1個(gè)輸入,可以定義為“in1__”。在定義了輸入輸出的變量名后,將implement代碼中以%port_name形式給出的輸入輸出變量替換為所生成的變量名。
整個(gè)IPP的翻譯則首先需要對(duì)IPM實(shí)例按調(diào)用的邏輯順序進(jìn)行排序。程序要能夠執(zhí)行,要求每個(gè)IPM實(shí)例(所對(duì)應(yīng)的子函數(shù))在被調(diào)用前,其輸入都已確定。因此我們需要對(duì)IPM實(shí)例排序。考慮到IPM實(shí)例數(shù)量通常不大,我們重復(fù)地遍歷這些IPM實(shí)例,并對(duì)它們進(jìn)行標(biāo)號(hào)。開始時(shí),所有IPM實(shí)例的標(biāo)號(hào)均為0。如果一個(gè)IPM實(shí)例的某個(gè)輸入端口的value_type為internal,或者該端口為external,但與其連接的src_block IPM實(shí)例已經(jīng)被標(biāo)號(hào),那么這個(gè)輸入端口的值就已經(jīng)確定;如果一個(gè)IPM實(shí)例沒有輸入端口,或者所有輸入端口的值均已確定,那么就用一個(gè)大于0的整數(shù)值標(biāo)號(hào)該IPM實(shí)例。當(dāng)所有IPM實(shí)例均被標(biāo)號(hào),或者在一次遍歷中沒有IPM實(shí)例被標(biāo)號(hào),那么整個(gè)排序過程即告完成。
之后,按標(biāo)號(hào)由小到大的順序?qū)⒚總€(gè)IPM實(shí)例轉(zhuǎn)為對(duì)相應(yīng)子函數(shù)的調(diào)用代碼,并采用系統(tǒng)性的方法來命名IPM實(shí)例的輸入輸出端口對(duì)應(yīng)的變量,最后以程序文件名作為函數(shù)名,為翻譯好的代碼加上MATLAB函數(shù)定義頭,并保存為同名的.m文件,便完成了翻譯。
例如,經(jīng)過翻譯之后,由第二節(jié)中示例IPM所得的子函數(shù)以及第三節(jié)中示例IPP對(duì)該子函數(shù)進(jìn)行調(diào)用的MATLAB代碼如下:
function example()
reader_Path_in__ = 'image1.jpg';
Reader_Format_in__ = 'Auto-determined';
[reader_ImageData_out__] = ReadImage
(reader_Path_in__,reader_Format_in__);
function [out1__] = ReadImage(in1__, in2__)
if strcmp(in2__, 'Auto-determined')
out1__ = imread(in1__);
else
out1__ = imread(in1__, in2__);
end
五、開展圖像處理編程訓(xùn)練的若干層次
利用本文所設(shè)計(jì)的xGIPL可視化圖像處理編程語言,可以開展不同層次的圖像處理編程訓(xùn)練。我們目前所能考慮到的就至少包括以下三個(gè)層次:
(1)使用xGIPL在已有模塊的基礎(chǔ)上進(jìn)行可視化編程。學(xué)生通過使用現(xiàn)成的IPM來進(jìn)行可視化編程,能夠了解和掌握解決特定圖像處理任務(wù)的整體性思路,并能夠直觀地感受處理的效果以及程序的性能。這一層次屬于較低的訓(xùn)練層次。
(2)通過MATLAB編程來自行實(shí)現(xiàn)關(guān)鍵的IPM,并通過可視化編程完成應(yīng)用的完整實(shí)現(xiàn)。在該訓(xùn)練層次下,學(xué)生應(yīng)對(duì)MATLAB語言編程有相當(dāng)程度地掌握,并且也能夠完成IPM的設(shè)計(jì),從而能夠針對(duì)特定的圖像處理問題自行實(shí)現(xiàn)其中的關(guān)鍵步驟,并完成IPM的封裝。這一層次屬于中等訓(xùn)練層次,能夠鍛煉學(xué)生對(duì)MATLAB這一高級(jí)編程語言的運(yùn)用。
(3)通過MATLAB的C/C++ MEX編程來實(shí)現(xiàn)關(guān)鍵的、對(duì)于計(jì)算性能有較高要求的圖像處理功能,從而能夠更高效地完成整個(gè)圖像處理任務(wù)。這一訓(xùn)練層次要求學(xué)生不但熟悉xGIPL和MATLAB語言,而且也熟悉C/C++編程,并且能夠使用C/C++語言進(jìn)行圖像處理算法的低層級(jí)編程,因此屬于最高的訓(xùn)練層次。
參考文獻(xiàn):
[1]翁花群,林元國.基于Visual C++的數(shù)字圖像處理實(shí)驗(yàn)教學(xué)軟件開發(fā)[J].廊坊師范學(xué)院學(xué)報(bào)(自然科學(xué)版),2015(1):24-28.
[2]李志欣,卓亞琦.基于OpenCV的數(shù)字圖像處理實(shí)驗(yàn)教學(xué)研究[J].大學(xué)教育,2013(9):42-43.
[3]張帆.基于OpenCV實(shí)踐項(xiàng)目的數(shù)字圖像處理教學(xué)方法探索[J].亞太教育,2015(22):133.
[4]鄭林濤,董永生.ImageJ軟件在數(shù)字圖像處理課程教學(xué)中的應(yīng)用[J].中國電力教育,2014(8):112-113.
[5]施幫利,韓武紅,楊奕.基于DSP的數(shù)字圖像基本處理實(shí)驗(yàn)教學(xué)探討[J].中國電力教育,2013(10):171-173.
[6]魯億方,藍(lán)金輝,遲健男.基于DSP的數(shù)字圖像處理實(shí)驗(yàn)的探究[J].實(shí)驗(yàn)技術(shù)與管理,2014(3):109-113.
[7]邱廣萍.MATLABGUIDE在數(shù)字圖像處理教學(xué)中的應(yīng)用[J].價(jià)值工程,2014(3):184,186.
[8]趙敏.MATLAB用于數(shù)字圖像處理的教學(xué)實(shí)踐研究[J].電腦知識(shí)與技術(shù),2012(31):7539-7540.
[9]肖龍飛,李金龍,楊凱,etal.基于MATLAB的數(shù)字圖像處理教學(xué)軟件的設(shè)計(jì)[J].信息技術(shù),2014(12):185-187.
(編輯:魯利瑞)