李宇 譚洪舟
在Windows下開(kāi)發(fā)視頻采集系統(tǒng)時(shí),通常有3種視頻采集的方法。分別為基于VFW(Video for Windows)、基于DirectX的DirectShow部件和基于視頻采集設(shè)備提供的SDK(Software Development Kit,軟件開(kāi)發(fā)包)。
VFW 是微軟公司于 1992年推出的專(zhuān)門(mén)針對(duì)Windows平臺(tái)上視頻處理的軟件包,它不依賴(lài)于專(zhuān)用的硬件設(shè)備,提供了通用的數(shù)字視頻開(kāi)發(fā)方案。使用VFW的優(yōu)點(diǎn)是它隨從Windows操作系統(tǒng)一起安裝,可執(zhí)行文件不需要附帶額外的庫(kù)文件就可以運(yùn)行。文獻(xiàn)1用VFW實(shí)現(xiàn)了視頻圖像疊加與播放。目前新的采集設(shè)備通常使用WDM(Windows Driver Model)驅(qū)動(dòng)模型,而VFW無(wú)法支持這種驅(qū)動(dòng)模型,因而無(wú)法驅(qū)動(dòng)相應(yīng)的采集設(shè)備。這大大限制了VFW在視頻多媒體采集中的應(yīng)用。此外,VFW的工作效率不高,這對(duì)于采集視頻質(zhì)量日漸提高、數(shù)據(jù)量突飛增長(zhǎng)的新設(shè)備來(lái)說(shuō)明顯不吻合。
SDK是采集卡廠(chǎng)家提供的開(kāi)發(fā)視頻監(jiān)控系統(tǒng)的一組庫(kù)函數(shù),使用SDK庫(kù)函數(shù),用戶(hù)可以在不了解視頻壓縮、回放、網(wǎng)絡(luò)與存盤(pán)操作等技術(shù)的前提下,進(jìn)行視頻程序開(kāi)發(fā)(SDK中通常包含了這些技術(shù)的實(shí)現(xiàn))。但是不同廠(chǎng)商提供的采集卡SDK通常無(wú)法兼容,因此編寫(xiě)的程序無(wú)法移植到新的環(huán)境中。而且對(duì)于常見(jiàn)的攝像頭,則不一定會(huì)有提供相應(yīng)的SDK。
DirectShow是基于Windows平臺(tái)的流媒體處理開(kāi)發(fā)包,它與DirectX一起發(fā)布。DirectShow對(duì)流媒體的捕捉、回放提供了強(qiáng)大的支持,使用它還可以在基于WDM驅(qū)動(dòng)的采集卡上進(jìn)行數(shù)據(jù)捕捉。使用DirectShow能夠簡(jiǎn)單、高效地對(duì)流媒體進(jìn)行處理,降低處理的復(fù)雜性。不過(guò),運(yùn)行基于DirectShow開(kāi)發(fā)出來(lái)的應(yīng)用程序要求PC機(jī)系統(tǒng)中安裝有DirectX模塊。一般情況下Windows操作系統(tǒng)中都捆綁了對(duì)應(yīng)版本的DirectX,使得用戶(hù)使用起來(lái)非常方便。相對(duì)前兩種方法,DirectShow簡(jiǎn)單易用,比較適合于Windows環(huán)境下的開(kāi)發(fā)圖像采集系統(tǒng)。
DirectShow是一套完全基于組件對(duì)象模型(Component Object Model,COM)的應(yīng)用系統(tǒng)。圖1是 DirectShow的系統(tǒng)圖[2]。圖中央最大的一塊即為DirectShow系統(tǒng)。虛線(xiàn)以下是Ring 0特權(quán)級(jí)別的硬件設(shè)備,虛線(xiàn)以上是Ring 3特權(quán)級(jí)別的應(yīng)用層。DirectShow系統(tǒng)位于應(yīng)用層中。它使用一種叫做Filter Graph的模型來(lái)管理整個(gè)數(shù)據(jù)流的處理過(guò)程;參與數(shù)據(jù)處理的各個(gè)功能模塊叫做Filter;各個(gè)Filter在Filter Graph中按一定的順序連接成一條“流水線(xiàn)”協(xié)同工作[3]。
圖1 DirectShow系統(tǒng)圖
DirectShow通過(guò)Filter與各式各樣的設(shè)備,包括本地文件系統(tǒng)、TV調(diào)諧器、視頻采集卡、編解碼器、顯示器、聲卡等進(jìn)行通信。因此DirectShow將應(yīng)用程序與設(shè)備之間的多樣性和復(fù)雜性隔離開(kāi)[4]。
按照功能來(lái)分,F(xiàn)ilter大致分為3類(lèi):Source Filter,Transform Filters和Rendering Filters。Source Filters主要負(fù)責(zé)獲取數(shù)據(jù),數(shù)據(jù)源可以是文件、Internet計(jì)算機(jī)里的采集卡(WDM驅(qū)動(dòng)的或VFW 驅(qū)動(dòng)的)、數(shù)字?jǐn)z像機(jī)等,然后將數(shù)據(jù)往下傳輸;Transform Filters主要負(fù)責(zé)數(shù)據(jù)的格式轉(zhuǎn)換分離/合成,解碼/編碼等,然后將數(shù)據(jù)繼續(xù)往下傳輸;Rendering Filters主要負(fù)責(zé)數(shù)據(jù)的最終去向——將數(shù)據(jù)送給顯卡、聲卡進(jìn)行多媒體的演示,或者輸出到文件進(jìn)行存儲(chǔ)。每一個(gè)DirectShow的Filter至少有一個(gè)連接點(diǎn),也稱(chēng)為引腳(Pin)。Filter之間的連接和媒體數(shù)據(jù)的傳送正是通過(guò)Pin的連接得以實(shí)現(xiàn)的。
Filter是DirectShow應(yīng)用程序數(shù)據(jù)處理的基本單元,各個(gè) Filter在 Filter Graph中按一定的順序連接成一條“流水線(xiàn)”協(xié)同工作。DirectShow使用一種叫做 Filter Graph的模型來(lái)管理整個(gè)數(shù)據(jù)流的處理過(guò)程?;诿嫦?qū)ο蟪绦蛟O(shè)計(jì)的思想,我們的圖像采集模塊中設(shè)計(jì)了下面三個(gè)類(lèi)對(duì)數(shù)據(jù)和操作進(jìn)行封裝:CVGraph類(lèi),CVSampleGrabberCB類(lèi)及CVCaptureGraph類(lèi)。整個(gè)捕捉模塊的UML類(lèi)框圖如圖2所示。
圖2 圖像采集模塊類(lèi)框圖
CVGraph類(lèi)主要是實(shí)現(xiàn)一些對(duì)所有與 Filter Graph相關(guān)的應(yīng)用中所必需的操作的封裝,通常作為其他針對(duì)特定領(lǐng)域應(yīng)用的Filter Graph類(lèi)的父類(lèi)。如與采集應(yīng)用相關(guān)的CVCaptureGraph即是繼承于該類(lèi)。
這個(gè)類(lèi)主要記錄一些維護(hù)與 Filter Graph相關(guān)的一些接口的指針,如圖2中所示的:m_pGraph、m_pBuild、m_pControl和m_pEvent;還有視頻預(yù)覽顯示窗口句柄及事件通告窗口句柄,如 m_hVidWin (視頻窗口句柄,可以為NULL,表示不顯示)和m_hWnd(事件窗口句柄,通常不為NULL)。
該類(lèi)相關(guān)的成員函數(shù)都是與設(shè)置視頻顯示窗口,事件通告窗口,啟動(dòng)/停止Filter Graph相關(guān)的操作。值得注意的是該類(lèi)的事件處理機(jī)制。從圖2可知CVGraph依賴(lài)于類(lèi)CVGraphEventHandle,在CVGraph::HandleEvent中調(diào)用了后者的成員函數(shù)。
CVGraphEventHandle是一個(gè)定義為應(yīng)用程序響應(yīng)DirectShow的Filter Graph事件的回調(diào)的類(lèi)。它的作用為:
(1)、 在應(yīng)用程序窗口類(lèi)中繼承該類(lèi);
(2)、調(diào)用CVGraph::SetEventWindow以設(shè)置事件響應(yīng)窗口;
(3)、當(dāng)應(yīng)用程序從消息泵中得到CVGraph::WM_GRAPH_MESSAGE消息的時(shí)候, 以所實(shí)現(xiàn)的窗口類(lèi)作為參數(shù)(根據(jù)C++類(lèi)繼承機(jī)制,這是合法的[5])調(diào)用 CVGraph::HandleEvent,其內(nèi)部調(diào)用了CVGraphEventHandler::OnGraphEvent函數(shù),根據(jù)多態(tài)性,這時(shí)即將調(diào)用在窗口類(lèi)中定義的 OnGraphEvent函數(shù)。
在本模塊中,幀數(shù)據(jù)的獲取采用的是DirectShow自身提供的 SampleGrabber Filter(對(duì)應(yīng)的類(lèi) ID為CLSID_SampleGrabber)。使用這個(gè)Filter時(shí)需要對(duì)其回調(diào)機(jī)制進(jìn)行設(shè)置,其中設(shè)置的回調(diào)參數(shù)中就有具有ISampleGrabber接口的類(lèi)。我們?cè)O(shè)計(jì)的CVSampleGrabberCB類(lèi)即為一例。應(yīng)用程序通過(guò)SetCallback(pSampleGrabberCB,1)設(shè)置回調(diào)函數(shù),其中參數(shù)1表示使用BufferCB這個(gè)方法進(jìn)行回調(diào)。
該類(lèi)還用一個(gè)枚舉的類(lèi)型 FUNCTIONARITY表示該SampbleGrabber Filter具有的功能:
enum FUNCTIONARITY
{ NON_FUN = NO_FUNCTION,
SNAP_ONLY = SG_SNAP,
ALIGN_ONLY = SG_ALIGN,
SNAP_ALIGN = SG_SNAP | SG_ALIGN
};
由此可見(jiàn),一個(gè)SampleGrabber Filter具有SNAP(即單幀拍攝)或(和)ALIGN(對(duì)準(zhǔn),主要用于下一章中廣角鏡頭畸變建模)功能。
回調(diào)的過(guò)程的流程圖如圖 3所示(即BufferCB接口函數(shù)的實(shí)現(xiàn))。
上述過(guò)程通告給應(yīng)用程序的自定義消息為:WM_CAPTURE_BITM AP_FOR_PROCESSING 3.3 CVCaptureGraph類(lèi)
該類(lèi)繼承于CVGraph類(lèi),利用DirectShow中的ICaptureBuilder2接口提供的智能連接功能RenderStream進(jìn)行Filter間互連。智能連接意即客戶(hù)只需要根據(jù)不同的應(yīng)用場(chǎng)景,添加所需要的 Source Filter,Transform Filter和 Rendering Filter,系統(tǒng)便會(huì)自動(dòng)實(shí)現(xiàn)連接。
在采集圖像過(guò)程中,應(yīng)用程序可能提供不同的參數(shù)決定最終的工作模式,因此程序中定義了一個(gè)新的類(lèi)型:
typedef unsigned long WORK_MODE;
并且使用宏定義語(yǔ)句定義了一些工作模式,不同模式對(duì)應(yīng)的Filter Graph是不同的。如果該捕捉類(lèi)以后需要進(jìn)行擴(kuò)展,僅需要使用類(lèi)似的方法添加宏定義即可。下面列出其中的幾個(gè)宏定義語(yǔ)句:
#define NULL_MODE (EMPTY_MODE) //空模式
圖3 BufferCB回調(diào)流程圖
#define PREV_WIN (PREVIEW |RENDER_WINDOW) //用戶(hù)指定窗口預(yù)覽模式
#define PREV_WIN_SNAP (PREVIEW |RENDER_WINDOW | SNAP) // 使用用戶(hù)指定的窗口進(jìn)行預(yù)覽,且提供單幀捕捉功能
#define PREV_WIN_SNAP_ALIGN(PREVIEW|RENDER_WINDOW|SNAP| ALIGN) // 使用用戶(hù)指定的窗口進(jìn)行預(yù)覽,且提供單幀捕捉、對(duì)準(zhǔn)功能
#define PREV_WIN_SNAP_STILL (PREVIEW |RENDER_WINDOW | SNAP | STILL_PIN) // 使用用戶(hù)指定的窗口進(jìn)行預(yù)覽,且利用靜態(tài)引腳捕捉幀數(shù)據(jù)
#define PREV_NULL_RENDER_SNAP_STILL(PREVIEW|SNAP | STILL_PIN) // 不進(jìn)行預(yù)覽顯示且利用靜態(tài)引腳捕捉幀數(shù)據(jù)
RecommendedWorkMode( )根據(jù)用戶(hù)所喜好的配置與及采集設(shè)備本身的硬件工作能力(如是否具有靜態(tài)引腳)返回一種系統(tǒng)推薦的工作模式;
RenderPreview( )函數(shù)完成只有預(yù)覽功能的 Filter Graph的建立;
RenderAviCapture( )函數(shù)完成將視頻流采集到 AVI文件的Filter Graph的搭建,在本系統(tǒng)中并未使用;
RenderStillPin( )完成使用靜態(tài)引腳實(shí)現(xiàn)單幀數(shù)據(jù)采集的Filter Graph中與靜態(tài)引腳相關(guān)的子Filter Graph的搭建;
RenderWholeGraph( )根據(jù)用戶(hù)設(shè)置的工作模式搭建整個(gè)Filter Graph。
從攝像頭中獲取幀數(shù)據(jù)最常見(jiàn)的辦法是從預(yù)覽的視頻流中插入一個(gè)SampleGrabber Filter,這樣由于視頻流中的每一幀數(shù)據(jù)都會(huì)經(jīng)過(guò)該Filter,只要讓該Filter通過(guò)回調(diào)機(jī)制通告上層應(yīng)用程序進(jìn)行對(duì)當(dāng)前幀進(jìn)行處理便可實(shí)現(xiàn)圖像采集。此外,現(xiàn)在的 USB攝像頭都是基于WDM,并且有一些還提供了靜態(tài)引腳捕獲(Still Pin Capture)這種類(lèi)似于相機(jī)快門(mén)的拍照接口(通常這種接口拍攝到的圖片會(huì)比視頻流中取出一幀的圖片的質(zhì)量要好)。不管是視頻流中進(jìn)行幀數(shù)據(jù)捕獲,還是從靜態(tài)引腳進(jìn)行捕獲,均采用回調(diào)函數(shù)的形式將幀數(shù)據(jù)的傳遞給應(yīng)用程序,這兩種情況均是通過(guò)在 Filter Graph中插入SampleGrabber Filter來(lái)實(shí)現(xiàn)的[6]。上層應(yīng)用程序只需要按圖4所示的流程進(jìn)行調(diào)用即可實(shí)現(xiàn)所需的功能。
由此,我國(guó)當(dāng)下通過(guò)“一帶一路”倡議推行國(guó)際經(jīng)貿(mào)合作,需要轉(zhuǎn)變理念和方式,重視法律合作,適時(shí)跟上世界發(fā)展趨勢(shì),借著法律自發(fā)趨同的世界法律合作潮流開(kāi)展國(guó)際經(jīng)貿(mào)活動(dòng),實(shí)現(xiàn)“一帶一路”所涉國(guó)家長(zhǎng)久的互利共贏。該理念和方式的轉(zhuǎn)變也是我國(guó)的必然選擇。
圖4 圖像捕獲模塊調(diào)用流程
由于DirectShow的視頻采集與上層應(yīng)用程序的工作線(xiàn)程邏輯上是獨(dú)立的兩個(gè)線(xiàn)程,它們按照設(shè)定的工作模式進(jìn)行工作。雖然兩種幀數(shù)據(jù)的獲取均是通過(guò)插入Sample Grabber Filter并回調(diào)應(yīng)用程序來(lái)實(shí)現(xiàn),但從技術(shù)細(xì)節(jié)上看還是存在不同之處:
(1)、對(duì)于從預(yù)覽視頻流中獲取幀數(shù)據(jù)的方式來(lái)說(shuō),攝像頭硬件設(shè)備每產(chǎn)生一幀視頻并且通告操作系統(tǒng)后,操作系統(tǒng)根據(jù)負(fù)載的情況,盡可能通過(guò)驅(qū)動(dòng)程序獲取該幀數(shù)據(jù)并通過(guò)設(shè)定的預(yù)覽 Filter路徑進(jìn)行處理。但是允許在負(fù)載較重的情況下丟棄部分預(yù)覽視頻幀。這樣,由于預(yù)覽視頻流源源不斷地從攝像頭設(shè)備處產(chǎn)生,按前述的回調(diào)方式,DirectShow采集線(xiàn)程會(huì)不斷地發(fā)送消息給應(yīng)用程序窗口。因而上層應(yīng)用程序必須進(jìn)行相應(yīng)的過(guò)濾操作。
(2)、在使用靜態(tài)引腳捕獲幀數(shù)據(jù)時(shí),只有用戶(hù)發(fā)送了捕獲命令后,才能夠觸發(fā)攝像頭進(jìn)行拍攝,在拍攝完成之后才發(fā)送消息通告應(yīng)用程序窗口。因而這種情況下不存在DirectShow捕獲線(xiàn)程頻繁發(fā)送通告消息。從邏輯上講,只有用戶(hù)啟動(dòng)捕捉命令,DirectShow在收集完數(shù)據(jù)后才發(fā)送消息,這類(lèi)似于照像機(jī)中的快門(mén)。使用靜態(tài)引腳捕獲幀數(shù)據(jù)非常節(jié)省系統(tǒng)資源,適合當(dāng)系統(tǒng)負(fù)載較重的時(shí)候使用。
圖5與圖6分別描述了圖形用戶(hù)界面下采集模塊在通過(guò)預(yù)覽視頻流獲取幀數(shù)據(jù)和靜態(tài)引腳獲取幀數(shù)據(jù)的UML時(shí)序圖,其中采集命令的發(fā)送都是由用戶(hù)指定。
圖5 預(yù)覽視頻流獲取幀數(shù)據(jù)的UML時(shí)序圖
圖6 靜態(tài)引腳獲取幀數(shù)據(jù)的UML時(shí)序圖
本圖像采集模塊用于我們開(kāi)發(fā)的證件信息識(shí)別系統(tǒng)中實(shí)現(xiàn)證件的圖像輸入。實(shí)驗(yàn)采用了Windows XP操作系統(tǒng)和Visual C++ 6.0作為開(kāi)發(fā)平臺(tái),硬件為普通市面USB攝像頭和Lenovo 奔騰雙核CPU的啟天M6900 PC機(jī)器。該識(shí)別系統(tǒng)具有鏡頭的畸變補(bǔ)償功能。圖7是用本圖像采集模塊得到的身份證原始圖像。由于采集到的圖像會(huì)發(fā)生桶形失真,直接對(duì)采集到的證件圖像進(jìn)行OCR會(huì)影響識(shí)別效果,系統(tǒng)要先對(duì)采集到的圖像進(jìn)行樣條函數(shù)畸變補(bǔ)償校正[8],處理后的身份證圖像為圖8所示。最后對(duì)身份證圖像進(jìn)行識(shí)別采集到證件的信息內(nèi)容(圖 9)。從整個(gè)采集識(shí)別情況來(lái)看,本圖像采集模塊能有效地實(shí)現(xiàn)圖像的輸入功能,滿(mǎn)足證件信息識(shí)別的圖像要求。
圖7 桶形失真原始圖像
圖8 使用雙線(xiàn)性插值法的畸變補(bǔ)償效果
圖9 證件采集識(shí)別效果
本文設(shè)計(jì)了用于圖像采集的 CVGraph類(lèi),CVSampleGrabberCB類(lèi)與CVCaptureGraph類(lèi),并基于這些類(lèi)開(kāi)發(fā)了使用USB攝像頭的圖像采集模塊。通過(guò)自行開(kāi)發(fā)的證件信息采集系統(tǒng)測(cè)試了該圖像采集模塊輸入功能。采集到的圖像達(dá)到了實(shí)際圖像應(yīng)用系統(tǒng)的要求。
[1] 徐從東,羅家融,王樹(shù)坤.基于VFW 的視頻圖像疊加與播放方法[J].計(jì)算機(jī)工程與設(shè)計(jì),2007,28(1):100-102
[2] DirectX. Documentation for C++ [EB/OL]. Microsoft Corporation,2005
[3] 陸其明.DirectShow開(kāi)發(fā)指南[M]. 北京:清華大學(xué)出版社. 2003
[4] Mark D. Pesce. Programming Microsoft DirectShow for Digital Video and TV [M]. Washington: Microsoft Press. 2003.04
[5] David J.Kruglinski, Scot Wingo, George Shepherd著, 希望圖書(shū)創(chuàng)作室譯. Visual C++ 6.0技術(shù)內(nèi)幕(第五版)[M] . 北京:希望電子出版社. 1999.05
[6] Eric Rudolph. How To Get Data from a Microsoft DirectShow Filter Graph [EB/OL]. http://msd n.microsoft.com/zh-cn/library/ms867162(en-us).aspx
[7] 孫鑫, 余安萍. VC++深入詳解[M]. 北京:電子工業(yè)出版社.2006.06
[8] 王占斌, 趙輝, 陶衛(wèi), 唐燕. 廣角鏡頭桶形畸變的樣條函數(shù)修正方法[J]. 光電工程. 2008.35(4). 140-144