??? 摘 要: 介紹了QR碼識別的基本原理,并設(shè)計(jì)了一個基于Symbian智能手機(jī)的QR碼識別系統(tǒng)" title="識別系統(tǒng)">識別系統(tǒng),重點(diǎn)說明了系統(tǒng)在Symbian平臺上實(shí)現(xiàn)時,圖像采集、異常處理" title="異常處理">異常處理和代碼移植等方面的問題。測試表明,該系統(tǒng)可以快速、準(zhǔn)確地識別QR碼,并有效地處理圖像傾斜和投影形變等問題。
??? 關(guān)鍵詞: QR碼? 智能手機(jī)? Symbian操作系統(tǒng)? Series 60平臺
?
??? 由于內(nèi)置高分辨率攝像頭手機(jī)的逐漸普及,催生了一種新的二維碼應(yīng)用模式——手機(jī)二維碼。手機(jī)二維碼是指將相關(guān)信息使用二維碼編碼,并以各類業(yè)務(wù)的形式在手機(jī)里存儲、閱讀和傳播[1]。手機(jī)既是二維碼信息的載體,也是二維碼的識讀設(shè)備。目前,手機(jī)二維碼在歐美、日韓等發(fā)達(dá)國家和地區(qū)已有較成熟的市場應(yīng)用。2006年9月,中國移動也正式推出了手機(jī)二維碼業(yè)務(wù),并表示手機(jī)二維碼將會成為移動增值服務(wù)的重要內(nèi)容之一。
??? QR碼(Quick Response Code)是由日本Denso公司于1994年9月研制的一種矩陣式二維碼,它除具有其他二維碼所具有的信息容量大、可靠性高、可表示漢字及圖像有多種文字信息、保密防偽性強(qiáng)等優(yōu)點(diǎn)外,還具有如下主要特點(diǎn):超高速識讀,全方位識讀,能夠有效地表示中國漢字和日本漢字[2]。本文設(shè)計(jì)了一個基于Symbian智能手機(jī)的QR碼識別系統(tǒng),重點(diǎn)介紹了系統(tǒng)在Symbian平臺上實(shí)現(xiàn)時需要注意的關(guān)鍵問題。測試表明,該系統(tǒng)可以快速、準(zhǔn)確地識別QR碼,并能有效地處理圖像傾斜和投影形變等問題。
1 QR碼符號簡介
??? QR碼符號是由正方形模塊構(gòu)成的正方形陣列,它由編碼區(qū)域和功能圖形構(gòu)成。其中,編碼區(qū)域包含格式信息、版本信息、數(shù)據(jù)和糾錯碼字;功能圖形由尋像圖形、分隔符、定位圖形和校正圖形組成。QR碼符號共有40種規(guī)格。版本1的規(guī)格為21×21模塊,每一版本的符號比前一版本每邊增加4個模塊,直到版本40,規(guī)格為177×177模塊。QR碼符號的示例見圖1。
?
?
2 QR碼的識別
??? 這一過程的基本思路是將攝像頭采集到的彩色圖像I(x,y)進(jìn)行灰度化;然后用適當(dāng)?shù)拈撝礣對灰度圖像進(jìn)行二值化處理,從而得到二值圖像B(x,y);接著在二值圖像中掃描位置探測圖形,通過3個位置探測圖形,求出QR碼的4個頂點(diǎn)坐標(biāo)和旋轉(zhuǎn)角度,然后將QR碼旋轉(zhuǎn)至水平位置,并把QR碼從圖像I(x,y)分割出來。
2.1 圖像的二值化
??? 圖像二值化的關(guān)鍵在于閾值的選取。二值化閾值計(jì)算方法主要有直方圖雙峰法、微分直方圖法和最大類間方差法。在基于手機(jī)的QR碼識別系統(tǒng)中,由于人在拍攝過程中會有意識地“瞄準(zhǔn)”QR碼符號,并使其盡量充滿取景器的主要區(qū)域,因此采集到的QR碼圖像一般都比較簡單,淺色的背景與條碼基本模塊構(gòu)成的正方形陣列形成了較大的反差,其直方圖經(jīng)過平滑之后,呈現(xiàn)出明顯的“雙峰”特性。這樣,使用簡單的直方圖雙峰法就可以快速地確定圖像的二值化閾值。
2.2 QR碼的定位
??? QR碼符號的尋像圖形包括3個相同的位置探測圖形,分別位于左上角、右上角和左下角。每個位置探測圖形可以看作是由3個重疊的同心正方形組成,它們分別為7×7個深色模塊、5×5個淺色模塊和3×3個深色模塊。位置探測圖形的模塊寬度比為1:1:3:1:1。符號中其他地方遇到類似圖形的可能性極小,因此可通過識別這三個位置探測圖形來確定視場中符號的位置和方向,從而使迅速識讀QR碼符號成為可能。在圖2中,a、b、c為QR碼符號旋轉(zhuǎn)不同角度時穿過位置探測圖形中心的掃描線??梢钥闯觯D(zhuǎn)的角度不影響掃描線上的模塊寬度之比。實(shí)際中,由于噪聲、投影形變等因素的影響,應(yīng)該允許這個比例有一定的偏差。
?
?
2.3 圖像的旋轉(zhuǎn)
檢測到3個位置探測圖形之后,就可以計(jì)算出QR碼的4個頂點(diǎn)坐標(biāo)和旋轉(zhuǎn)角度。根據(jù)這些參數(shù)即可將QR碼旋轉(zhuǎn)至水平位置并從圖像中分割出來。在對圖像做旋轉(zhuǎn)時,變換之后的坐標(biāo)不一定是整數(shù),因此要對變換之后整數(shù)坐標(biāo)的像素值進(jìn)行估計(jì)。這里采用的是雙線形插值算法。假設(shè)輸出圖像某像素的位置坐標(biāo)通過反向變換得到的浮點(diǎn)坐標(biāo)為(i+u,j+v),其中i,j為非負(fù)整數(shù),u,v為[0,1)區(qū)域的浮點(diǎn)數(shù),則該像素的值f(i+u,j+v)可由原圖像中坐標(biāo)為(i,j)、(i+1,j)、(i,j+1)、(i+1,j+1)的4個像素的值決定,即[3]:
??? f(i+u,j+v)=(1-u)(1-v)f(i,j)+(1-u)vf(i,j+1)+u(1-v)f(i+1,j)+uvf(i+1,j+1)
??? 將QR碼從圖像中分割出來之后,建立采樣網(wǎng)格,對網(wǎng)格的每一交點(diǎn)上的圖像像素取樣,即可得出QR碼符號的位圖矩陣。
3 QR碼的解碼
??? 這一過程將QR碼符號數(shù)據(jù)按照QR碼標(biāo)準(zhǔn)進(jìn)行解碼,從而得到存儲在其中的用戶信息。解碼的流程如下[2]:
??? (1)識讀格式信息,按需要去除掩模" title="掩模">掩模圖形并完成對格式信息模塊的糾錯,識別糾錯等級與掩模圖形參考。
??? (2)識讀版本信息,確定符號的版本。
??? (3)用掩模圖形(掩模圖形參考已從格式信息中得出)對編碼區(qū)域的位圖進(jìn)行異或處理,消除掩模。
??? (4)根據(jù)模塊排列規(guī)則,識讀符號字符,恢復(fù)信息的數(shù)據(jù)與糾錯碼字。
??? (5)用與糾錯級別信息相對應(yīng)的糾錯碼字檢測錯誤,如果發(fā)現(xiàn)錯誤,立即糾錯。
??? (6)根據(jù)模式指示符和字符計(jì)數(shù)指示符將數(shù)據(jù)碼字劃分成多個部分。
??? (7)按照使用的模式譯碼得出數(shù)據(jù)字符并輸出結(jié)果。
4 QR碼識別系統(tǒng)在Symbian平臺上的實(shí)現(xiàn)
4.1 Symbian操作系統(tǒng)
??? 智能手機(jī)是一種擁有開放型操作系統(tǒng)的手機(jī),用戶可以在這個平臺上安裝各種各樣的應(yīng)用程序" title="應(yīng)用程序">應(yīng)用程序,從而使手機(jī)的功能得到無限擴(kuò)充。目前,主流的智能手機(jī)操作系統(tǒng)有三種" title="三種">三種:Symbian、Windows Mobile和Linux。其中Symbian以其平臺的開放性、較低的授權(quán)費(fèi)用、眾多廠商的支持、對硬件要求低、第三方軟件豐富等優(yōu)勢,成為智能手機(jī)市場上應(yīng)用最為廣泛的產(chǎn)品。Symbian由Psion公司的EPOC(Electronic Piece of Cheese)操作系統(tǒng)發(fā)展而來,是一個32位的多任務(wù)操作系統(tǒng),其內(nèi)核由基礎(chǔ)組件(微核、設(shè)備驅(qū)動程序和用戶庫)、中間件(系統(tǒng)服務(wù)、安全和應(yīng)用程序框架)和通信組件(電話、消息和個人區(qū)域網(wǎng)絡(luò))構(gòu)成[4]。由于不同的終端產(chǎn)品在屏幕尺寸、用戶輸入方式等方面的差異,Symbian給出了用戶界面風(fēng)格的三種參考設(shè)計(jì):Pearl、Crystal和Quartz,最終演變?yōu)镾ymbian上的三種主要平臺:Series 60、Series 80和UIQ。Series 60針對屏幕分辨率為176×208像素、單手操作的智能手機(jī);Series 80針對屏幕分辨率為640×200像素、采用標(biāo)準(zhǔn)鍵盤輸入的高端智能手機(jī);UIQ針對采用筆式輸入(觸摸屏)的智能手機(jī)。其中Series 60是應(yīng)用最為廣泛的平臺。本系統(tǒng)就是在基于Symbian Series 60平臺的手機(jī)上實(shí)現(xiàn)的。
4.2 圖像采集
??? 系統(tǒng)在手機(jī)上實(shí)現(xiàn)時, 待識別圖像的采集是一個比較關(guān)鍵的問題。在Series 60平臺上,CCamera類包裝了攝像頭相關(guān)的API。為了使用這些API,應(yīng)用程序必須實(shí)現(xiàn)一個MCameraObserver(或MCameraObserver2)的派生類。MCameraObserver類與CCamera類之間的關(guān)系是觀測者設(shè)計(jì)模式(Observer Design Pattern)在Symbian系統(tǒng)中的具體體現(xiàn)。圖像采集可通過以下三種方式實(shí)現(xiàn):
??? (1)用CCamera∷CaptureImage()啟動靜態(tài)圖像的捕獲。當(dāng)其調(diào)用完成之后,MCameraObserver∷ImageReady()會被異步調(diào)用。用戶可在該函數(shù)中訪問剛剛捕獲的圖像。此方式一般用來實(shí)現(xiàn)手機(jī)的照相功能。
??? (2)用CCamera∷StartVideoCapture()啟動視頻捕獲。當(dāng)視頻緩沖區(qū)被預(yù)置數(shù)目的視頻幀填充之后,MCameraObserver∷FrameBufferReady()會被異步調(diào)用。用戶可在該函數(shù)中訪問視頻緩沖區(qū)。此方式一般用來實(shí)現(xiàn)手機(jī)的攝像功能。
??? (3)用CCamera∷StartViewFinderBitmapsL()啟動取景器(View Finder)數(shù)據(jù)的傳輸。當(dāng)其調(diào)用完成之后,MCameraObserver∷ViewFinderFrameReady()會被周期性地調(diào)用。用戶可在該函數(shù)中訪問剛剛獲取的視景幀(View Finder Frame)。此方式一般用來實(shí)現(xiàn)手機(jī)照相或攝像過程中的取景器功能。
??? 第一種方式采用非連續(xù)模式采集圖像,效率較低且不利于人在識別過程中的主動參與。第二種方式雖是連續(xù)模式,但在視頻采集過程中,攝像頭的閃光燈會一直亮著,不符合低功耗原則。第三種方式采集圖像的分辨率高,有利于識別精度的提高,但會增加處理時間。最終采用第三種方式并折中處理,選擇400×300的分辨率。
??? ViewFinderFrameReady()函數(shù)的處理流程如圖3所示。視景幀是一個CFbsBitmap類型的位圖對象。可以通過CFbsBitmap::DataAddress()函數(shù)獲得位圖中第一個像素(位于位圖的左上角)的地址,從而實(shí)現(xiàn)對位圖數(shù)據(jù)的直接訪問。視景幀根據(jù)手機(jī)類型的不同,具有不同的顏色格式。所以需要首先通過CFbsBitmap∷DisplayMode()函數(shù)獲得圖像的顏色格式,然后采用相應(yīng)的方式獲取各像素的R、G、B分量,以便將彩色圖像轉(zhuǎn)換為灰度圖像。
?
4.3 異常處理
??? 對手機(jī)而言,內(nèi)存泄漏是十分嚴(yán)重的問題。因?yàn)槭謾C(jī)的內(nèi)存資源非常有限,而它又通常會連續(xù)運(yùn)行很長時間不重啟,這樣,異常處理就顯得尤為重要。Symbian系統(tǒng)采用了一套不同于標(biāo)準(zhǔn)C++的異常處理機(jī)制。
??? Symbian對異常處理的基本支持包括:(1)TRAP和TRAPD宏,用作捕獲異常,類似于標(biāo)準(zhǔn)C++中的try和catch。(2)異常退出(Leave)機(jī)制,其作用類似于標(biāo)準(zhǔn)C++中的throw。
??? 清理?xiàng)#–leanup Stack)是Symbian避免內(nèi)存泄漏的主要手段之一。請看如下示例代碼:
void DoExampleL(){
CSomeObject*myObject=new(ELeave) CSomeObject;
CallLeavingMethodL();
delete myObject;}
??? 代碼使用重載的操作符new(ELeave)為CSomeObject類的新實(shí)例分配動態(tài)內(nèi)存。在Symbian中,為簡單對象在堆內(nèi)存上分配空間基本都采用這種方式。ELeave參數(shù)表明內(nèi)存分配失敗時會發(fā)生異常退出。傳統(tǒng)的new操作符無法利用異常退出機(jī)制,只是在極少數(shù)情況下才被使用。CallLeavingMethodL()是一個調(diào)用時可能會發(fā)生異常退出的函數(shù)。當(dāng)CallLeavingMethodL()發(fā)生異常退出時,DoExampleL()的函數(shù)棧會被釋放。這就意味著,局部指針變量myObject會被銷毀,但它指向的堆內(nèi)存卻沒有被釋放,從而發(fā)生了內(nèi)存泄漏。Symbian使用清理?xiàng)?CleanupStack類在e32base.h中定義)來解決這個問題?;居梅ㄊ牵涸谡{(diào)用可能會發(fā)生異常退出的代碼之前,使用PushL()方法將任何指向堆內(nèi)存的局部指針壓入清理?xiàng)?nèi)。若發(fā)生異常退出,清理?xiàng)4_保所有相關(guān)的資源都被釋放。如果沒有發(fā)生異常,則使用Pop()方法將那些指針彈出。這樣,DoExampleL()函數(shù)可以修改為:
void DoExampleL(){
CSomeObject*myObject=new(ELeave) CSomeObject;
CleanupStack∷PushL(myObject);
CallLeavingMethodL();
CleanupStack∷Pop(myObject);
delete myObject;}
??? 可以使用“CleanupStack∷PopAndDestroy(myObject);”代替上述代碼的最后兩句。有三種情況可能會使代碼發(fā)生異常退出:
??? (1)使用了退出函數(shù):User∷Leave(),User∷LeaveIfError(),User∷LeaveNoMemory(),或User∷LeaveIfNull()。
??? (2)使用了重載的new(ELeave)操作符。
??? (3)調(diào)用了一個可能會異常退出的函數(shù)。
??? 構(gòu)造過程中需要分配資源的對象被稱為復(fù)雜對象,其所屬類通常為CBase類的派生類。在堆內(nèi)存上構(gòu)造復(fù)雜對象時,若其構(gòu)造函數(shù)發(fā)生異常退出,則會發(fā)生內(nèi)存泄漏。所以復(fù)雜對象采用兩階段構(gòu)造過程,這是Symbian避免內(nèi)存泄漏的另一主要手段。例如,使用CText類表征解碼之后的文本,它的一個私有成員變量textBuf8為指向HBuf8類描述符(Symbian主要使用描述符來處理字符串)的指針。下面為兩階段構(gòu)造過程的示例代碼:
//第一階段構(gòu)造
CText∷CText(){}
//第二階段構(gòu)造
void CText∷ConstructL(TUint aMaxTextLength)
{ textBuf8=HBufC8∷NewL(aMaxTextLength);}
??? 這樣,每次構(gòu)造復(fù)雜對象都需要兩行代碼。為了避免這個麻煩,通常會提供兩個靜態(tài)成員函數(shù):
//不將指向函數(shù)返回對象的指針留在清理?xiàng)?nèi)
CText*CText∷NewL(TUint aMaxTextLength){?
CText*self=CText∷NewLC(aMaxTextLength);
CleanupStack∷Pop(self);
return self;}
//將指向函數(shù)返回對象的指針留在清理?xiàng)?nèi)
CText*CText∷NewLC(TUint aMaxTextLength){
CText*self=new(ELeave) CText;
CleanupStack∷PushL(self);
self->ConstructL(aMaxTextLength);
return self;}
4.4 代碼移植
??? 系統(tǒng)開發(fā)并不需要從零開始編寫所有程序,有很多地方(例如直方圖雙峰法、雙線性插值和RS碼糾錯算法等)可將現(xiàn)成的Windows平臺的代碼移植到Symbian平臺上來。在移植過程中,除了異常處理方式需要改變之外,還需要注意以下幾點(diǎn):
??? (1)將標(biāo)準(zhǔn)C++的內(nèi)建數(shù)據(jù)類型替換為對應(yīng)的或者合適的Symbian C++的基本數(shù)據(jù)類型,以保持平臺的獨(dú)立性。例如,用TInt類型替換int類型。
??? (2)在Symbian系統(tǒng)中,由于GUI應(yīng)用程序(后綴為.app的程序)的棧的默認(rèn)尺寸只有8KB,所以不要在這類程序中使用尺寸較大的局部變量。遇有需要的情況(例如大數(shù)組),將對象分配在堆內(nèi)存上。
??? (3)在Symbian 8.1a及以前版本的操作系統(tǒng)中,DLL(Dynamic Link Library)程序不能使用可寫的靜態(tài)數(shù)據(jù)(例如全局變量);在Symbian 8.1b及以后版本的操作系統(tǒng)中,盡管DLL程序支持可寫的靜態(tài)數(shù)據(jù),但不推薦使用。Symbian的GUI應(yīng)用程序?qū)嶋H上是apprun.exe程序啟動的DLL程序,所以在這類程序中不可以使用全局變量。代碼移植時,應(yīng)將這些變量封裝到類中。另一種解決方案是將原代碼移植為Symbian服務(wù)器程序(后綴為.exe的程序,支持可寫的靜態(tài)數(shù)據(jù)),并向客戶程序提供API接口。
??? (4)Symbian不支持標(biāo)準(zhǔn)模板庫(STL),但提供了一些集合類來支持?jǐn)?shù)組、鏈表等數(shù)據(jù)結(jié)構(gòu)。
??? 系統(tǒng)基于S60 2nd Edition SDK(FP3)開發(fā),采用的開發(fā)環(huán)境為Metrowerks公司的CodeWarrior。系統(tǒng)在Nokia N70上做了性能測試,可以達(dá)到平均約0.6s的識別速度。在沒有微距模式支持的情況下,可以識別的QR碼符號的最高版本為10。測試還表明,系統(tǒng)可以有效地處理QR碼圖像傾斜和投影失真等問題。系統(tǒng)在Nokia 3230和Nokia 6680上做了兼容性測試,也取得了比較好的效果。
參考文獻(xiàn)
[1] 梁鵬.手機(jī)二維碼業(yè)務(wù)研究[J].電信科學(xué),2006;(12):36-39.
[2] 張成海,郭衛(wèi)華,羅秋科.QR Code二維碼——一種新型的矩陣符號[M].北京:中國標(biāo)準(zhǔn)出版社,2000.
[3] 劉宏偉,嚴(yán)妍.快速響應(yīng)碼的識別和解碼[J].計(jì)算機(jī)工程與設(shè)計(jì),2005;26(6):1560-1562.
[4] Digia Inc.Programming for the series 60 platform and?symbian OS[M].Chichester:John Wiley & Sons Ltd,2003.