1.工業相機編程模型和(hé)流程
不同的工業相機提供不同的編程接口(SDK),盡管不同接口不同相機間(jiān)編程接口各不相同,他們實際的API結構和(hé)編程模型很(hěn)相似,了解了這些(xiē)再對工業相機編程就很(hěn)簡單了。
DMA技(jì)術(shù)
DMA是一種高(gāo)速的數(shù)據傳輸操作(zuò),允許在外部設備和(hé)存儲器(qì)之間(jiān)直接讀寫數(shù)據,既不通(tōng)過CPU,也不需要CPU幹預。整個(gè)數(shù)據傳輸操作(zuò)在一個(gè)稱為(wèi)"DMA控制(zhì)器(qì)"的控制(zhì)下進行(xíng)的。CPU除了在數(shù)據傳輸開(kāi)始和(hé)結束時(shí)做(zuò)一點處理(lǐ)外,在傳輸過程中CPU可(kě)以進行(xíng)其他的工作(zuò)。這樣,在大(dà)部分時(shí)間(jiān)裏,CPU和(hé)輸入輸出都處于并行(xíng)操作(zuò)。因此,使整個(gè)計(jì)算(suàn)機系統的效率大(dà)大(dà)提高(gāo)。
對于工業相機來(lái)說,當CMOS或CCD芯片曝光然後将數(shù)據轉到相機緩存後,這時(shí)候DMA會(huì)負責将緩存中數(shù)據保存到硬盤上(shàng)指定位置,正好滿足相機高(gāo)速大(dà)數(shù)據的傳輸。一般都會(huì)使用DMA來(lái)完成實時(shí)的數(shù)據采集和(hé)保存。
多(duō)數(shù)時(shí)候,DMA控制(zhì)器(qì)存在各種接口的圖像采集卡中,包括1394/GigE/USB/Camera Link等,這些(xiē)采集卡有(yǒu)自己的時(shí)間(jiān)控制(zhì)單元完成和(hé)相機曝光的同步,并控制(zhì)DMA的存取行(xíng)為(wèi)。
工作(zuò)流程
當相機工作(zuò)時(shí),就是連續的采集-處理(lǐ)-采集-處理(lǐ)...的過程,但(dàn)是這就存在一個(gè)問題,如果采集的速度比處理(lǐ)速度快,處理(lǐ)不過來(lái),怎麽辦?在實際中,我們使用隊列來(lái)解決這個(gè)問題,當前幀沒有(yǒu)處理(lǐ)完,下一幀到來(lái)時(shí)直接放入隊列等待當前處理(lǐ)完成後再處理(lǐ)它。
如下圖
這裏使用三個(gè)隊列完成采集和(hé)處理(lǐ)同步。
DMA隊列:當CMOS或CCD芯片曝光然後将數(shù)據轉到相機緩存後,這時(shí)候DMA會(huì)負責将緩存中數(shù)據寫入到“DMA隊列”頭Buffer中。
準備隊列:一旦“DMA隊列”頭Buffer被填充完成,會(huì)被加到“準備隊列”尾後,這時(shí)候會(huì)發送中斷通(tōng)知用戶程序:當前又有(yǒu)一幀數(shù)據采集完成,您看着處理(lǐ)吧(ba)。
處理(lǐ)隊列:當用戶接收到中斷會(huì)自動跳(tiào)轉到中斷函數(shù)中,使用GetFrame拿(ná)取“準備隊列”頭Buffer,然後加到當前用戶程序“處理(lǐ)隊列”尾,用戶程序從“處理(lǐ)隊列”頭拿(ná)取Buffer處理(lǐ)完成後使用PutFrame将Buffer再添加到原始的“DMA隊列”尾。
需要說明(míng)如下幾點:
1.這裏的初始隊列為(wèi)1-10,都是初始分配為(wèi)DMA隊列的,這個(gè)內(nèi)存分配和(hé)釋放過程有(yǒu)的SDK是自己負責的,有(yǒu)的則需要用戶自己分配和(hé)釋放,SDK隻負責托管使用。
2.一般最開(kāi)始注冊一個(gè)中斷處理(lǐ)函數(shù),當“準備隊列”填充完成會(huì)自動跳(tiào)轉到中斷函數(shù)中,借此完成同步操作(zuò)。也可(kě)以是用戶自己維護同步結構體(tǐ),使用查詢和(hé)等待的方式判斷“準備隊列”頭是否填充完成,是否該用戶程序獲取數(shù)據和(hé)處理(lǐ)了。
3.如果用戶處理(lǐ)任務非常簡單,可(kě)以去掉“處理(lǐ)隊列”,每次直接GetFrame->處理(lǐ)->PutFrame。如果用戶處理(lǐ)任務比較複雜而不希望出現丢幀的現象,則需要用戶使用“處理(lǐ)隊列”來(lái)保存所有(yǒu)可(kě)用的Buffer。
4.這裏隊列也隻是能夠解決處理(lǐ)速度比采集速度慢少(shǎo)許的情況,主要是對不同處理(lǐ)速度做(zuò)平均來(lái)保證采集和(hé)處理(lǐ)同步。如果每一幀的處理(lǐ)時(shí)間(jiān)太長,這時(shí)候“DMA隊列” Buffer全部轉移到“處理(lǐ)隊列” Buffer,就會(huì)出現異常情況,這時(shí)不同的相機會(huì)有(yǒu)不同的處理(lǐ)方法。
數(shù)據傳輸和(hé)顯示流程
如圖,每個(gè)相機可(kě)能有(yǒu)不同的流采集器(qì)(Grab Streamer)或同一接口上(shàng)安裝了多(duō)個(gè)相機(也對應多(duō)個(gè)流采集器(qì)),對應多(duō)個(gè)通(tōng)道(dào)(Channel)。對每個(gè)通(tōng)道(dào)來(lái)說,在實際采集時(shí)數(shù)據傳輸實際上(shàng)是拆分成如圖的數(shù)據包(Packet) RawData形式傳遞的,內(nèi)存中存儲形式為(wèi)一維數(shù)組,在每一幀圖像的起始存在不同的标識表明(míng)一幀的開(kāi)始和(hé)結束,每一個(gè)Packet都有(yǒu)标識表明(míng)當前所屬的通(tōng)道(dào)。為(wèi)了顯示圖像,用戶程序需要重新将一維數(shù)組數(shù)據拼裝成圖像形式,這一過程由用戶完成,通(tōng)常可(kě)借助OpenCV或MIL等圖像處理(lǐ)包完成該操作(zuò)。
編程模型和(hé)流程
對于相機來(lái)說,常見編程時(shí)我們關注三個(gè)對象——相機對象、采集對象、參數(shù)對象。
相機對象(Camera Object):負責相機的連接、斷開(kāi)等工作(zuò)。
采集對象(Grab Streamer):負責相機的采集隊列分配、相機單幀、連續采集。
參數(shù)對象(Parameter Object):負責相機參數(shù)的設置。
不同的SDK可(kě)能安排不一樣,一般來(lái)說要不是三種對象的功能合并到“相機對象”中,要不是分為(wèi)三種對象,其實采集對象和(hé)參數(shù)對象都是在“相機對象”上(shàng)封裝而來(lái)。
通(tōng)用編程流程如下圖:
可(kě)以看到相機編程需要做(zuò)三方面工作(zuò):
1.初始化操作(zuò)
首先初始化相機驅動Com環境,然後遍曆得(de)到當前的相機列表,根據相機ID或List 編号選擇對應相機。
之後連接指定相機,首先設置本次采集的相機參數(shù)(幀速、圖像大(dà)小(xiǎo)、縮放比等),然後是分配和(hé)注冊當前DMA隊列,這裏有(yǒu)的是用戶完成,有(yǒu)的是SDK完成。
之後先開(kāi)啓DMA邏輯等待相機采圖,然後使相機開(kāi)始工作(zuò)采圖,整個(gè)系統就按照之前工作(zuò)流程運作(zuò)起來(lái)了,許多(duō)SDK将“開(kāi)啓DMA”和(hé)“相機開(kāi)始工作(zuò)”合并為(wèi)“開(kāi)始采集”。
2.結束操作(zuò)
先停止相機工作(zuò)再關閉DMA邏輯,許多(duō)SDK将“開(kāi)啓DMA”和(hé)“相機開(kāi)始工作(zuò)”合并為(wèi)“結束采集”。
然後清理(lǐ)DMA隊列,和(hé)分配時(shí)對應,這裏有(yǒu)的是用戶完成,有(yǒu)的是SDK完成。
最後斷開(kāi)相機并清理(lǐ)工作(zuò)環境。
3.中斷響應操作(zuò)
當相機一幀采集完成後,自動跳(tiào)轉進入中斷回調函數(shù),這裏分了兩種中斷回調函數(shù)。
第一種為(wèi)簡單的取Buffer->處理(lǐ)->放回。
第二種結合Windows的消息隊列,在此處再給一個(gè)“處理(lǐ)隊列”,給處理(lǐ)一個(gè)緩沖時(shí)間(jiān)。
這裏的處理(lǐ)包括常見的圖像處理(lǐ)、計(jì)算(suàn)和(hé)顯示及RawData拼裝為(wèi)圖像等用到Buffer的地方。
前面也說過,常用的是中斷響應處理(lǐ),除此之外,自己去查詢Buffer填充狀态并作(zuò)相關同步操作(zuò)在某些(xiē)場(chǎng)合也會(huì)用到,這個(gè)請(qǐng)查詢不同相機SDK給出的同步方案。
差不多(duō)所有(yǒu)的工業相機SDK都是這樣的編程模型和(hé)流程,AVT 1394相機和(hé)Basler Camera Link相機和(hé)AVT GigE相機相關代碼在筆者網站(zhàn)可(kě)下載,還(hái)有(yǒu)之前講的Basler Pylon SDK相機編程,他們基本流程都是一樣,恕不詳述!
2. 工業相機SDK接口使用總結
相機調用
我們利用相機采集圖像,首先要對相機進行(xíng)相關參數(shù)設置及控制(zhì),這需要對相機的SDK包比較了解,一般相機廠家(jiā)都會(huì)提供相機SDK,其中包含用戶手冊和(hé)調用Demo,這些(xiē)都大(dà)大(dà)降低(dī)了調用門(mén)檻,提高(gāo)了二次開(kāi)發用戶的效率。目前用過Balser、海康、大(dà)華等相機,其實都是一個(gè)套路,都是按照下面幾個(gè)步驟進行(xíng)的。
1)枚舉設備
2)創建句柄
3)打開(kāi)設備
4)開(kāi)始抓圖
5)獲取一幀并保存圖像
6)停止抓圖
7)關閉設備
8)銷毀句柄
相機同步
若是開(kāi)發過程中用到雙目或者多(duō)目的話(huà),則需要外接同步觸發器(qì)或者外部觸發信号,通(tōng)過相機同步觸發線來(lái)實現同步問題。以實際應用過的Basler acA1300-200uc為(wèi)例,其相機同步觸發線具體(tǐ)類型如下:
1 -—— +12 VDC 紅
2 —— I/O Input 1 黃
3 —— VCC(加電(diàn)阻) 藍(lán)
4 —— I/O Out 1 綠
6 —— DCcam Power GND 黑(hēi)
0000—— I/O GND 白
3. Basler Pylon工業相機SDK的使用
Pylon庫有(yǒu)C++ .Net等各種封裝版本,一般用C++版本,功能全面效率高(gāo),但(dàn)對于不同接口(GigE USB3.0 CameraLink)的相機必須對應使用不同的類,之間(jiān)不能通(tōng)用。
基于GenAPI通(tōng)用相機抽象接口使用的是Node結構,以字符串形式訪問相機參數(shù),可(kě)以統一管理(lǐ)不同接口類型的相機。但(dàn)效率低(dī),使用不方便。
Pylon高(gāo)層用C++封裝,形成本地相機對象
如何管理(lǐ)多(duō)個(gè)相機,最靠譜的方法是按相機ID标定順序,需要讀一個(gè)配置文件,比如XML或JSON,然而一開(kāi)始不知道(dào)ID,需要先列舉出來(lái)。
4.Pylon 以實時(shí)圖像采集講解PylonC SDK使用流程
一般的對于提供硬件編程來(lái)說,硬件生(shēng)産廠家(jiā)都會(huì)提供好SDK使用的手冊和(hé)實例。手冊中一般包括安裝和(hé)配置流程,一些(xiē)基本概念的介紹,SDK每個(gè)函數(shù)使用,SDK使用流程和(hé)實例(有(yǒu)些(xiē)硬件實例直接寫在手冊中,有(yǒu)些(xiē)會(huì)以單獨文件存在,還(hái)有(yǒu)的兩者皆有(yǒu))。對于上(shàng)位機軟件開(kāi)發人(rén)員來(lái)說拿(ná)到一個(gè)硬件上(shàng)位機編程任務。
首先應該閱讀了解其SDK概念,再按照其介紹的SDK開(kāi)發流程閱讀其提供的實例,修改相應的實例為(wèi)自己所用,有(yǒu)不懂的函數(shù)查詢一下其用法即可(kě)。有(yǒu)些(xiē)開(kāi)發人(rén)員習慣性的去記其API,這是費時(shí)費力的做(zuò)法,并不推薦。下面主要以實時(shí)圖像采集講解Basler相機的PylonC SDK的使用流程。
PylonC SDK的使用的總體(tǐ)流程圖如下:
下面是其中對于不同的工作(zuò)要求,加載相機對象和(hé)卸載相機對象是通(tōng)用的。而要使用其他模塊,如事件對象時(shí),相應的改為(wèi)加載事件對象和(hé)卸載事件對象,以及使用事件對象完成相關任務即可(kě)。編程時(shí)一定要對整個(gè)流程做(zuò)好規劃,特别是硬件編程時(shí)一定留意內(nèi)存洩露,前面分配的資源一定要在後面釋放。
下面是五個(gè)大(dà)流程的詳細解析,需要的地方已經加以說明(míng),并注解了需要用到的函數(shù)
加載相機對象
卸載相機對象
加載數(shù)據流抓取對象
卸載數(shù)據流抓取對象
單幀或連續抓圖過程
按照以上(shàng)介紹的流程即可(kě)實現實時(shí)圖像采集
在工業控制(zhì)當中,用到basler工業相機sdk編程,主要是使用c或者c++,當項目龐大(dà)時(shí),又需要良好的用戶界面,用C++是不錯的選擇。
以實例和(hé)看過的一些(xiē)參照講講PylonCppSDK使用流程。
從中我們知道(dào),總的開(kāi)發流程圖如下:
那(nà)麽,用C++開(kāi)發也大(dà)抵如此。
這裏我們看一個(gè)basler的cpp sample:
把這個(gè)和(hé)上(shàng)面的流程圖對比理(lǐ)解,再看看文檔和(hé)sdk的結構,理(lǐ)解起來(lái)就容易多(duō)了。
5.工業相機SDK之opencv二次開(kāi)發
做(zuò)視(shì)覺的第一步是選好相機鏡頭等硬件設備,接下來(lái)就是将自己開(kāi)發的算(suàn)法在硬件上(shàng)實現。我最近做(zuò)一個(gè)項目,實現了一下Opencv在相機SDK上(shàng)的運用,下面小(xiǎo)結一下具體(tǐ)實現步驟.
1. 安裝相機自帶的驅動和(hé)SDK開(kāi)發包;
2. 用VS2010新建一個(gè)工程,配置好SDK的動态鏈接庫(或者靜态),具體(tǐ)動态鏈接庫的使用可(kě)參見孫鑫的那(nà)本書(shū),這裏不多(duō)說;
3. 條用SDK開(kāi)發包中的函數(shù)建立相機和(hé)PC機件的鏈接;
4. 建立視(shì)頻流數(shù)據,設立一個(gè)回調函數(shù)(具體(tǐ)參見各SDK),并将數(shù)據拷貝到Mat中的data中;
5. 有(yǒu)了opencv中的Mat數(shù)據結構,接下來(lái)就可(kě)以實現我們的各種算(suàn)法了。