張玉萍,鄒 澎
(鄭州大學(xué)信息工程學(xué)院,河南 鄭州 450001)
責(zé)任編輯:任健男
隨著信息技術(shù)的飛速發(fā)展,視頻采集系統(tǒng)廣泛應(yīng)用于數(shù)碼攝像、安防監(jiān)控、機(jī)器人視覺等眾多領(lǐng)域。Linux操作系統(tǒng)以其免費(fèi)、開源等諸多優(yōu)勢(shì),成為嵌入式設(shè)備開發(fā)的研究熱點(diǎn),同時(shí)Qt/Embedded是Trolltech開發(fā)商發(fā)布的嵌入式版本GUI開發(fā)工具,主要運(yùn)行在Linux系統(tǒng)上,它包含完整的C++圖形界面開發(fā)工具包,并具有整套供應(yīng)用程序開發(fā)的標(biāo)準(zhǔn)API函數(shù),以其開源性、跨平臺(tái)性、界面藝術(shù)美觀性,適合高端應(yīng)用性等特點(diǎn),在嵌入式設(shè)備中得到廣泛的應(yīng)用。因此采用基于Qt/Embedded視頻采集方案,性價(jià)比更高。
嵌入式設(shè)備視頻采集GUI設(shè)計(jì)的過程中,以往多采用QTimer定時(shí)器類實(shí)現(xiàn)圖像的連續(xù)性。該方案中時(shí)間的設(shè)定依賴于嵌入式平臺(tái)和攝像頭的類型,需要多次測(cè)試,過程較為繁瑣。本文調(diào)用V4L2提供的API接口函數(shù)以及在設(shè)計(jì)相同的Qt/Embedded圖像用戶界面基礎(chǔ)上,分別使用QThread類和QPainter類庫(kù)兩種方案,實(shí)現(xiàn)把USB攝像頭采集的圖像實(shí)時(shí)的顯示在GUI界面上。
V4L2是Linux系統(tǒng)中關(guān)于視頻設(shè)備的內(nèi)核驅(qū)動(dòng),它為視頻設(shè)備的應(yīng)用程序提供一系列接口函數(shù)[1-2]。本文Linux系統(tǒng)內(nèi)核版本為2.6.29在內(nèi)核定制過程中,已經(jīng)加入了對(duì)V4L2模塊及USB攝像頭的支持,兩種方案中圖像的采集程序均調(diào)用V4L2模塊提供的主要編程接口函數(shù)獲取USB攝像頭中圖像數(shù)據(jù),V4L2下視頻編程的流程如圖1所示。
圖1 視頻編程流程圖
下面對(duì)流程中用到的V4L2主要的API函數(shù)作簡(jiǎn)要分析,并給出具體的參數(shù)設(shè)置。
1)打開設(shè)備操作
在Linux操作系統(tǒng)中任何設(shè)備都看作文件,對(duì)設(shè)備的操作就轉(zhuǎn)換成對(duì)設(shè)備文件的操作。打開視頻設(shè)備,調(diào)用函數(shù) fd=open("/dev/video0",O_RDWR,0),其中/dev/video0就是USB攝像頭對(duì)應(yīng)的設(shè)備文件,O_RDWR表明本文采用阻塞模式打開攝像頭設(shè)備。
2)視頻采集前初始化的設(shè)置
首先使用ioctl(fd,VIDIOC_QUERYCAP,&cap)獲取有關(guān)攝像頭的基本信息,查看是否支持視頻輸入或者音頻輸入輸出等。其次,在支持視頻輸入的基礎(chǔ)上,通過調(diào)用ioctl(fd,VIDIOC_S_FMT,&format)函數(shù)對(duì)當(dāng)前驅(qū)動(dòng)視頻捕獲格式進(jìn)行設(shè)置。具體如下:
在上述步驟的基礎(chǔ)上,需要對(duì)V4L2中關(guān)鍵結(jié)構(gòu)體v4l2_requestbuffers和v4l2_buffer進(jìn)行設(shè)置,分別通過調(diào)用VIDIOC_REQBUFS及VIDIOC_QUERYBUF指令獲取緩存,實(shí)現(xiàn)內(nèi)存映射。關(guān)鍵設(shè)置如下:
3)圖像采集與處理
內(nèi)核采集到圖像的數(shù)據(jù)通過內(nèi)存映射的方式,使得在用戶空間內(nèi)可以對(duì)圖像數(shù)據(jù)進(jìn)行各種處理操作。關(guān)鍵設(shè)置如下:
4)結(jié)束視頻采集
調(diào)用 ioctl(fd,VIDIOC_STREAMOFF,&format)函數(shù)停止視頻采集,之后取消內(nèi)存映射,釋放內(nèi)核中申請(qǐng)的緩存,分別通過函數(shù) munmap(buffers[i].start,buffers[i].length)和free(buffers)實(shí)現(xiàn),最后關(guān)閉視頻設(shè)備。
該方案提出的基礎(chǔ)是已經(jīng)編寫好獨(dú)立的視頻采集處理程序,為將其運(yùn)行結(jié)果在后續(xù)開發(fā)的Qt/Emedded界面上,使用QT中的QThread線程庫(kù),可以實(shí)現(xiàn)非GUI和GUI程序的通信,使得非GUI到GUI的移植過程較為簡(jiǎn)單,以下將闡述其過程。
1)非GUI到GUI程序移植
通過調(diào)用V4L2中API接口和Linux系統(tǒng)函數(shù)編寫視頻采集程序,由于采用非QT類庫(kù),視頻顯示的實(shí)現(xiàn)是直接對(duì)framebuffer進(jìn)行一些列的操作。關(guān)鍵代碼如下:
首先打開 framebuffer,查看其參數(shù)設(shè)置,其次,將framebuffer的內(nèi)存地址映射到內(nèi)存空間,最后通過調(diào)用fb_pixel函數(shù)將緩存中的每一個(gè)像素繪制好framebuffer上。在此過程中需要考慮framebuffer支持圖像格式和深度,本文使用USB攝像頭采集圖片格式是MJPEG格式,framebuffer最高支持16位深度圖像,因此需要將圖片解壓并將解壓后RGB24格式轉(zhuǎn)換成RGB565格式,才能在framebuffer上清晰的顯示。
2)QThread類框體設(shè)計(jì)
在Qt/Embedded程序中,繼承QThread類的同時(shí)繼承QFrame類,類名為screen,該類具有線程和QFrame類窗體部件的雙重特性,線程中run函數(shù)是上一章節(jié)中的代碼,代碼中需要注意圖像顯示大小和screen窗體大小保持一致的同時(shí),需要設(shè)置screen的寬度和高度必須是16的整數(shù)倍,這樣可以保證圖像正常顯示,當(dāng)主窗口界面按下play按鈕時(shí)表明調(diào)用該線程時(shí),開始執(zhí)行run函數(shù),點(diǎn)擊close按鈕表明結(jié)束該線程,并關(guān)閉界面。
3)QThread類庫(kù)的編譯配置
在QT程序編譯配置線程庫(kù)libqte-mt.so.3.1.0。本文使用的QT的版本為qtopia-2.2.0-FriendlyARM,此版本相對(duì)較低不支持線程庫(kù),在編譯時(shí)會(huì)出現(xiàn)錯(cuò)誤提示cannot find-lqt-mt,此時(shí)需要在配置編譯環(huán)境的參數(shù)中添加-thread,具體配置如下:
1)方案描述
由QWidget類繼承的 screen,并重新構(gòu) paintEvent(QPaintEvent*event)函數(shù)。同時(shí),使用QPushButton類創(chuàng)建play和close兩個(gè)按鈕,通過Qt的信號(hào)與槽機(jī)制,與screen窗體通信分別用于視頻顯示的開啟和關(guān)閉。在圖像實(shí)時(shí)顯示的過程中,該方案沒有采用以往的QTimer類實(shí)現(xiàn),而采用while循環(huán),既保證了圖像采集的連續(xù)性,又使得程序簡(jiǎn)化。每處理一幀圖像就會(huì)調(diào)用screen窗體部件的paintEvent函數(shù)[3-5],重新顯示 screen中的圖像,達(dá)到實(shí)時(shí)顯示的效果。
2)關(guān)鍵偽代碼解析
while中每當(dāng)調(diào)用repaint(FALSE)進(jìn)行更新時(shí),程序會(huì)自動(dòng)調(diào)用paintEvent函數(shù)。經(jīng)調(diào)試表明如果使用update(),顯示效果會(huì)出現(xiàn)閃爍。使用repaint(FALSE)時(shí)自動(dòng)保存screen窗體上一次的圖像信息,能很好地解決閃爍的問題。本系統(tǒng)申請(qǐng)兩幀圖像的緩沖區(qū),每次顯示一幀圖像之后要初始化全局變量ptcur值為0,這可避免采集幀的混亂,導(dǎo)致圖像不正常顯示。
由上文可知圖像是以MJPEG格式存放在緩存中,所以V4L2視頻處理中,先計(jì)算經(jīng)攝像頭采集的每一幀圖像大小,在然后保存到同一個(gè)文件infd中,不同幀保存的內(nèi)容不同,當(dāng)while循環(huán)中調(diào)用paintEvent(QPaintEvent*)函數(shù)顯示不同幀的圖像。代碼如下:
這里直接調(diào)用pix.load(QString&filename)實(shí)現(xiàn),沒有使用QImage類來(lái)繪圖的原因在于以MJPEG格式采集的圖像需要先解壓縮成RGB888,然后使用QImage類創(chuàng)建圖像空間,最后使用drawImage(QPoint&,QImage&)繪圖,步驟較為繁瑣。而QPainter類支持壓縮格式圖像文件的繪制,使得繪圖過程較為簡(jiǎn)單快捷。
不同平臺(tái)Qt/Embedded編譯環(huán)境配置的不同,但大體都需要以下4個(gè)步驟:
1)安裝交叉編譯工具。需要ARM9的Linux編譯器去編譯工程并產(chǎn)生ARM9處理器的目標(biāo)代碼;
2)交叉編譯Qt/Embedded庫(kù)。要使Qt/Embedded程序能在嵌入式系統(tǒng)中運(yùn)行,則應(yīng)將其用到的函數(shù)庫(kù)進(jìn)行交叉編譯;
3)交叉編譯Qt/Embedded程序。將交叉編譯后的可執(zhí)行文件放入嵌入式文件系統(tǒng)中;
4)發(fā)布Qt/Embedded應(yīng)用到指定開發(fā)板。
FriendlyARM開發(fā)板將前3個(gè)步驟編寫到build腳本中,只需要運(yùn)行build腳本便可將Qt程序生成ARM版本的可執(zhí)行文件[6-7]。上述兩種方案的發(fā)布流程相同,本文以第二種方案為例講述將視頻采集GUI發(fā)布到嵌入式FriendlyARM開發(fā)板上的簡(jiǎn)單流程。
為了發(fā)布到QPE(Qt PDA應(yīng)用環(huán)境的簡(jiǎn)稱),需要準(zhǔn)備兩個(gè)文件,其一是ARM版本視頻采集GUI的可執(zhí)行文件videocapture和啟動(dòng)器文件videocapture.desktop,啟動(dòng)器需要開發(fā)板支持的圖像格式的圖標(biāo),本文采用png格式的video.png圖片,代碼如下:
使用串口分別將可執(zhí)行文件videocapture和啟動(dòng)器文件videocapture.desktop下載到開發(fā)板opt/Qtopia/bin/和opt/Qtopia/Applications/目錄下,同時(shí)需要把video.png下載到/opt/Qtopia/pics目錄。其程序中所需的二進(jìn)制庫(kù)文件在運(yùn)行build腳本時(shí)已將所需的ARM版本的庫(kù)文件拷貝到開發(fā)板中,使用chmod+x videocature命令后重啟開發(fā)板,點(diǎn)擊video圖標(biāo),便可看到視頻采集的圖像。視頻采集GUI發(fā)布到嵌入式設(shè)備上,如圖2所示。
圖2 嵌入式設(shè)備上的視頻采集GUI
對(duì)比以上兩種方案,當(dāng)QT4.0以上版本支持線程庫(kù)情況下,方案一更為簡(jiǎn)單,反之當(dāng)QT版本較低時(shí)編譯線程庫(kù)配置的過程較為繁瑣,方案二更具優(yōu)勢(shì)。實(shí)驗(yàn)結(jié)果表明,與以往視頻采集顯示方案相比,以上兩種方案不僅保證了圖像的連續(xù)性,而且避免了顯示過程中的復(fù)雜性。兩種方案簡(jiǎn)便可行,適用于手持式或便攜移動(dòng)式圖像處理設(shè)備,以及安防監(jiān)控、交通路口抓拍等應(yīng)用。
[1]SCHIMEK M H.Video for Linux two API specification revision 0.24[EB/OL].[2012-04-20].http://v4l2spec.bytesex.org/v4l2spec/v4l2.pdf.
[2]陳亮.基于Video4Linux2的圖像采集程序設(shè)計(jì)[J].微計(jì)算機(jī)信息,2009,25(3):65-67.
[4]BLANCHETTE G,SUMMERFIELD M.C++GUI Qt3 編程[M].齊亮,譯.北京:北京航空航天大學(xué)出版社,2006.
[5]倪繼利.Qt及Linux操作系統(tǒng)窗口設(shè)計(jì)[M].北京:電子工業(yè)出版社,2006.
[6]王黎明,陳雙橋,閆曉玲,等.ARM9嵌入式系統(tǒng)開發(fā)與實(shí)踐[M].北京:北京航空航天大學(xué)出版社,2008.
[7]任善全,呂強(qiáng),錢培德,等.一個(gè)基Qt/Embedded的嵌入式Linux應(yīng)用程序的實(shí)現(xiàn)[J].計(jì)算機(jī)應(yīng)用與軟件,2006,23(2):105-107.
[8]梅寬勤.基于Qt/Embedded的圖像用戶界面移植[D].上海:復(fù)旦大學(xué),2007.