siso_genicam#
若要使用此程式庫,應將標頭檔 siso_genicam.h 新增至原始程式碼中。
#include <siso_genicam.h>
此外, siso_genicam.lib 應新增至您的 Microsoft Visual Studio 專案中,或者 libsiso_genicam.so 至您的 Linux 專案。如果您使用 CMake,則套件名稱為 SisoGenicam,且程式庫會儲存在變數中 ${SisoGenicam_LIBRARIES}。請參閱 先決條件 以了解有關專案以及如何使用 CMake 的更多詳細資訊。
本函式庫總是與影格擷取卡函式庫 fglib5 搭配使用,關於如何將 fglib5 函式庫新增至您的專案中的詳細資訊,請參閱The Frame Grabber Library fglib5。
Camera Control Library 中的錯誤處理#
const char * Sgc_getErrorDescription(
int result);
API 的大多數函式都會傳回一個 int result code。如果函式呼叫順利執行,傳回值將會是 SGC_OK 或對於某些函式而言,為大於或等於零的值。負值在大多數情況下表示發生錯誤狀況。Error Codes 定義於標頭檔中 siso_genicam_error.h,其會自動包含在檔案中 siso_genicam.h.
函式 Sgc_getErrorDescription() 可用於取得特定結果代碼的字串表示形式。
本文件其餘部分的程式碼範例將不包含錯誤處理,因為這是針對應用程式需求而定的。不過,在可行範圍內,仍會檢查傳回碼以確保函式成功執行。
Camera Control Library 初始化#
int Sgc_initBoard(
Fg_Struct * fg,
unsigned int flags,
SgcBoardHandle ** board);
void Sgc_freeBoard(
SgcBoardHandle * board);
若要開始使用 siso_genicam 函式庫,必須先如 The Frame Grabber Library fglib5中所述將影格擷取卡初始化。接下來,該函式 Sgc_initBoard() 應針對應用程式所使用的每個擷取卡進行呼叫。參數 flags 保留供未來擴充之用,應用程式應一律傳遞 0。如果初始化成功,則主機板代代碼 (board handle) 會儲存在傳遞至參數中的變數 board.
如果應用程式已完成使用 siso_genicam 程式庫,則應透過呼叫 Sgc_freeBoard() 來釋放所有成功取得的板卡代碼(Handle)。
以下範例顯示如何取得主機板代碼以開始使用此程式庫:
SgcBoardHandle * board = nullptr;
int result = Sgc_initBoard(fg, 0, &board);
if (result != SGC_OK) {
// handle error ...
}
// use board, start discovery ...
Sgc_freeBoard(board);
相機尋找#
int Sgc_scanPorts(
SgcBoardHandle * board,
unsigned int portMask,
int timeout,
int speed);
int Sgc_getCameraCount(
SgcBoardHandle * board);
int Sgc_getCameraByIndex(
SgcBoardHandle * board,
unsigned int index,
SgcCameraHandle ** camera);
int Sgc_getCamera(
SgcBoardHandle * board,
unsigned int port,
SgcCameraHandle ** camera);
資訊
在 Framegrabber API 的 5.9 版本中,函式 Sgc_scanPorts() 以及該函式的傳回值 Sgc_getCameraCount() 的行為均已變更。
在應用程式可以使用相機之前,必須先探索相機。探索程序會掃描擷取卡的實體連接埠以尋找連接。當在多個連接埠上偵測到連接時,下一步是找出連接了多少相機,以及每部相機正在使用多少實體連接。實體連接及其屬性(例如所使用的傳輸速度)稱為鏈結 (link)。相機支援一或多個鏈結組態。例如,CoaXPress 相機可能支援各種鏈結組態。例如,具有四個實體連接埠的相機可能支援使用 CoaXPress 2.0 鏈結速度子集的的一、二或四個鏈結組態:3.125、5、6.25、10 和 12.5 Gbit/s。因此此相機將總共支援 15 種不同的鏈結組態。
若要啟動相機偵測程序,函式 Sgc_scanPorts() 應予以呼叫。此函式預期來自先前呼叫的主機板代碼 Sgc_initBoard() 中的參數 board(一個指定應執行偵測之實體連接埠的位元遮罩)位於參數中 portMask 以及在參數中等待至少探索到一部相機的時間(以毫秒為單位) timeout來同步等待來自一組事件來源的事件。參數 speed 應該是 LINK_SPEED_NONE 多數情況下皆可適用。它可用於選擇性地為偵測程序提供提示,指示預期偵測到的相機連結速度。
在為一個或多個擷取卡使用單一處理程序的應用程式中,連接埠遮罩(port mask)應該始終為 0xf。透過這種方式,將會掃描影格擷取卡的所有連接埠以尋找相機。如果應用程式針對某個影格擷取卡使用多個行程,請閱讀章節 支援從多個行程進行相機探索.
偵測到相機後,最終的連結設定會根據所使用的 applet 與相機預設設定進行協商。了解此過程的限制有助於理解所偵測相機呈現在應用程式中的狀態。偵測演算法不會使用相機提供的 GenICam XML。相反地,預設相機設定會決定偵測程序可為相機使用的最大連結速度與連結數量。對於某些相機而言,預設設定並非相機可使用的最高連結速度或最大連結數量!另一方面,applet 佈局則決定了 applet 偵測程序可使用的最大相機數量,以及每台相機可使用的最大連結數量。偵測演算法會試圖在找到的相機與 applet 佈局之間達到最佳匹配。請參閱 applet 說明文件與相機說明文件,以找到最符合您打算使用的相機設定與功能的 applet。
(另請參閱Understanding Image Data Flow章節中的圖表,該圖表說明了 Applet 的配置。對於連接到影格擷取卡的每個相機,Applet 都需要一個對應的相機運算子。相機運算子的數量是每個 Applet 的固定 Property。您可能還想檢閱The Frame Grabber Library fglib5部分之Frame Grabber Initialization章節末尾的註解,以了解如何為連接到影格擷取卡的相機選擇 Applet。)
若呼叫 Sgc_scanPorts() 會在查詢模擬結果中未定義區域的資料時傳回 SGC_OK,則表示在指定的時間內至少找到了一台相機,並且該小程式與相機已成功配對。如果傳回值為 ERR_SGC_TOPOLOGY_MISMATCH,則表示至少找到了一台相機,但 applet 與相機無法匹配;儘管與相機的通訊仍然可行,但影像資料無法正確從相機傳輸至 applet。
在成功呼叫 Sgc_scanPorts()取得 bytearray, Sgc_getCameraCount() 可被呼叫以請求所找到的相機數量,並使用 Sgc_getCameraByIndex() 或 Sgc_getCamera() 以取得相機代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代代介面取得相機代碼。這兩個函式運作方式類似,且都需要三個參數。第一個參數是板卡代碼。對於 Sgc_getCameraByIndex(),第二個參數透過 0 到由 Sgc_getCameraCount() 減一。因此,該函式可用於方便地迭代所有被探索到的相機,但探索相機的順序以及因此的索引可能會在對以下內容進行兩次呼叫之間發生變化 Sgc_scanPorts()對於 Sgc_getCamera()回報的相機數量之間的數字來識別相機;,第二個參數透過相機所連接的實體連接埠來識別相機。實體連接埠從 0 開始編號,直到所使用的擷取卡實體連接埠總數減一為止。如果總是使用相同的實體佈線,則可以使用此函數來避免針對 Sgc_getCameraByIndex()。第三個參數是指向變數的指標,用於儲存相機代碼。
提到的不明確情況。
const unsigned int portMask = 0xf;
const int timeoutInMs = 10000;
int result = Sgc_scanPorts(board, portMask, timeoutInMs, LINK_SPEED_NONE);
if (result != SGC_OK) {
// handle error ...
}
SgcCameraHandle * camera = nullptr;
result = Sgc_getCameraByIndex(board, index, &camera);
if (result == SGC_OK) {
// use camera ...
}
上述範例中概述的簡單方法僅適用於單相機設定。
對於處理一台以上相機的應用程式,建議的探索處理方式是註冊回呼函式(如章節所述) 為尋找事件註冊回呼函式,然後呼叫 Sgc_scanPorts() 並將逾時設為 0 以啟動探索程序。從回呼處理常式 (callback handler) 內部,應用程式可以在探索到新相機時,例如啟動獨立的擷取執行緒。
對於處理多台相機的應用程式,建議的處理偵測方式是註冊回呼函數(如「為偵測事件註冊回呼函數」一章中所討論的),然後呼叫 Sgc_scanPorts() 重複進行,直到找到所有預期的相機為止。以下範例在繼續處理之前,會等待發現四台相機:
const unsigned int portMask = 0xf;
const int timeoutInSeconds = 10;
const int numberOfCamerasExpected = 4;
int result = SGC_OK;
int numberOfCamerasFound = 0;
auto start = std::chrono::steady_clock::now();
do {
result = Sgc_scanPorts(board, portMask, 1000, LINK_SPEED_NONE);
if (result == SGC_OK) {
numberOfCamerasFound = Sgc_getCameraCount(board);
}
} while ((numberOfCamerasFound < numberOfCamerasExpected) && (std::chrono::steady_clock::now() - start < std::chrono::seconds(timeoutInSeconds)));
if (numberOfCamerasFound < numberOfCamerasExpected) {
// handle error ...
}
// use cameras ...
重新啟動相機探索#
int Sgc_scanPortsEx(
SgcBoardHandle * board,
unsigned int portMask,
int timeout,
int speed,
unsigned int flags);
資訊
該函式的預設行為 Sgc_scanPortsEx() 已在 Framegrabber API 5.9 版本中變更。
函式 Sgc_scanPorts() 和 Sgc_scanPortsEx() 或者,應用程式可以呼叫 flags 當呼叫時在參數中傳遞 0,兩者皆會啟動一個背景執行緒來執行偵測程序,然後與該執行緒進行同步,以檢查在呼叫中指定的時間內是否找到了任何相機。隨後對該函數的任何呼叫都只會執行同步以檢查相機。若要完全重新啟動相機偵測程序, Sgc_scanPortsEx() 可以透過以下方式呼叫: SGC_SP_FLAG_RESET_DISCOVERY_INFOS 中的參數 flags.
使用相機 Property#
發現相機後,應用程式即可開始使用相機 Property。這些 Property(相機參數與命令)是在 XML 文件中定義的,相機可以透過標準化的 Property 介面提供此文件以供下載,或者由相機製造商透過其他方式提供(例如,某些相機製造商可能會提供一個網站來下載 XML 文件)。XML 文件的結構是在 GenICam 標準中定義的。若要深入了解 GenICam,請造訪歐洲機器視覺協會 (European Machine Vision Association) 的 GenICam 網站。若要深入了解相機提供的 Property,請參閱相機說明文件。
GenICam 標準還定義了一種透過 GenApi 控制相機 Property 的方法。Using the GenICam Reference Implementation章節將討論如何將 siso_genicam 函式庫與 GenApi 連接。
在本章中,記錄了一組函式,允許直接從 Framegrabber API 使用相機功能,並包裝 GenApi 以便於使用。雖然所描述的 API 可在已知這些功能時用於取得和設定相機參數以及執行命令,但不支援 XML 的進階功能,這需要應用程式使用 GenApi。
相機連接#
int Sgc_connectCamera(
SgcCameraHandle * camera);
int Sgc_connectCameraWithExternalXml(
SgcCameraHandle * cameraHandle,
const char * file);
int Sgc_disconnectCamera(
SgcCameraHandle * camera);
在偵測程序中,已建立與所偵測相機的實體連接。若要使用相機功能,則必須建立邏輯連接。此邏輯連接將透過讀取 GenICam XML 並準備由 Framegrabber SDK 內部使用的 GenApi 環境來建立。若要使用相機提供的 XML 建立邏輯連接,函數 Sgc_connectCamera() 應該被呼叫。如果應使用從製造商網站下載或透過其他方式取得的 XML 檔案,則該函式 Sgc_connectCameraWithExternalXml() 可供使用。這兩個函數也都期望在參數中帶入相機代號 camera。此函數 Sgc_connectCameraWithExternalXml() 預期在參數中傳入 XML 檔案的路徑 file 。
當應用程式完成相機功能的使用後,可以透過呼叫來關閉邏輯連接 Sgc_disconnectCamera().
取得與設定相機 Property#
int Sgc_getIntegerValue(
SgcCameraHandle * camera,
const char * feature,
int64_t * value);
int Sgc_getBooleanValue(
SgcCameraHandle * camera,
const char * feature,
unsigned int * value);
int Sgc_getFloatValue(
SgcCameraHandle * camera,
const char * feature,
double * value);
int Sgc_getStringValue(
SgcCameraHandle * camera,
const char * feature,
const char ** value);
int Sgc_getEnumerationValue(
SgcCameraHandle * camera,
const char * feature,
int64_t * value);
int Sgc_getEnumerationValueAsString(
SgcCameraHandle * camera,
const char * feature,
const char ** value);
int Sgc_clearStringCache(
SgcCameraHandle * camera);
int Sgc_setIntegerValue(
SgcCameraHandle * camera,
const char * feature,
int64_t value);
int Sgc_setBooleanValue(
SgcCameraHandle * camera,
const char * feature,
unsigned int value);
int Sgc_setFloatValue(
SgcCameraHandle * camera,
const char * feature,
double value);
int Sgc_setStringValue(
SgcCameraHandle * camera,
const char * feature,
const char * value);
int Sgc_setEnumerationValue(
SgcCameraHandle * camera,
const char * feature,
const char * value);
若要請求具有數字表示法的相機參數值,函數 Sgc_getIntegerValue(), Sgc_getBooleanValue(), Sgc_getFloatValue() 和 Sgc_getEnumerationValue() 可以使用。這些函式預期在參數中傳入相機代碼 camera,特徵名稱在參數中 feature 以及指向對應類型變數的指標,值將被儲存在該參數中 value.
請求具有字串表示法的相機參數值的函數 Sgc_getStringValue() 和 Sgc_getEnumerationValueAsString(),預期指向某個類型的變數指標 char * 中的參數 value。在此變數中,將會儲存指向字串值的指標。
字串值將被配置並儲存在內部快取中。每當應用程式請求字串值時,快取就會增長,並且沒有直接的方法可以從快取中釋放單一字串值。不過,可以透過呼叫來清除快取 Sgc_clearStringCache()。這將會釋放並使所有先前配置的字串值失效。
若要設定值,可使用函式 Sgc_setIntegerValue(), Sgc_setBooleanValue(), Sgc_setFloatValue(), Sgc_setStringValue() 和 Sgc_setEnumerationValue() 可被呼叫。這些函數期望在參數中帶入相機代號 camera,特徵名稱在參數中 feature 以及參數中的值 value.
以下範例顯示如何使用相機 XML 連接相機,並設定要傳輸影像的寬度與高度:
int result = Sgc_connectCamera(camera);
if (result == SGC_OK) {
result = Sgc_setIntegerValue(camera, "Width", 1920);
}
if (result == SGC_OK) {
result = Sgc_setIntegerValue(camera, "Height", 1080);
}
執行相機命令#
int Sgc_executeCommand(
SgcCameraHandle * camera,
const char* feature);
int Sgc_isCommandDone(
SgcCameraHandle * camera,
const char* feature,
unsigned int * value);
int Sgc_startAcquisition(
SgcCameraHandle * camera,
unsigned int start);
int Sgc_stopAcquisition(
SgcCameraHandle * camera,
unsigned int stop);
若要執行命令,可使用函式 Sgc_executeCommand() 可被呼叫。該函數期望在參數中帶入相機代號 camera 以及參數中的 Property 名稱 feature。此函數 Sgc_isCommandDone() 可用於檢查命令是否已執行完成。它期望在參數中帶入相機代號 camera,特徵名稱在參數中 feature 以及指向某種類型變量的指標 unsigned int 中的參數 value.如果命令已執行完畢,變數中將儲存值 1;如果命令仍在執行中,則將儲存值 0。
函式 Sgc_startAcquisition() 和 Sgc_stopAcquisition() 是標準 Property 的捷徑 AcquisitionStart 和 AcquisitionStop.只有在參數 start 或 stop 評估結果為 true:
int Sgc_startAcquisition(SgcCameraHandle * camera, unsigned int start)
{
int result = SGC_OK;
if (start) {
result = Sgc_executeCommand(camera, "AcquisitionStart");
}
return result;
}
相機資訊#
int Sgc_getCameraPropertyWithType(
SgcCameraHandle * camera,
const char * property,
void * value,
unsigned int * type,
void * additionalValue);
int Sgc_updateCameraInfos(
SgcCameraHandle * camera);
資訊
在 Framegrabber API 的 5.9 版本中,透過函數 Sgc_getCameraPropertyWithType() 已擴充,且該函數 Sgc_updateCameraInfos() 可用資訊已新增。
在發現程序中建立與相機的實體連接後,即可要求取得關於相機和連接的各種資訊。
函式 Sgc_getCameraPropertyWithType() 可以被呼叫以請求關於相機連線的資訊。該函數期望在參數中傳入相機代號 camera,並在參數中傳入連線 Property property、一個用於儲存數值的變量指標、一個指向某種類型變量的指標 unsigned int ,其必須進行初始化以反映 Property 的類型。參數 additionalValue 某些 Property 需要如下文所述:
| Property | 描述 | Type |
|---|---|---|
| CAM_PROP_MASTERID | 相機的主 IDa | uint32_t |
| CAM_PROP_NROFLINKS | 用於影像傳輸的實體鏈路數量 | uint32_t |
| CAM_PROP_LINKSPEED | 當前鏈路速度(以 Mbit/s 為單位) | uint32_t |
| CAM_PROP_DISCOVERYSPEED | 發現相機時的鏈路速度(以 Mbit/s 為單位) | uint32_t |
| CAM_PROP_FGPORT | 鏈路連接到的實體連接埠(additionalValue: 鏈路索引) | uint32_t |
| CAM_PROP_MASTERPORT | 主鏈路連接到的實體連接埠(與鏈路 0 的 FGPORT 相同) | uint32_t |
| CAM_PROP_APPLETMASTERID | Applet 相機連接埠的主 IDa | uint32_t |
| CAM_PROP_APPLETOPERATORINDEX | Applet 相機運算子的索引 | uint32_t |
| CAM_PROP_APPLETOPERATORSIZE | Applet 相機運算子的鏈路數量 | uint32_t |
| CAM_PROP_APPLETPORT | 鏈路連接到的邏輯連接埠(additionalValue: 鏈路索引) | uint32_t |
| CAM_PROP_CONTROLPACKETSIZE | 控制封包的最大大小 | uint32_t |
| CAM_PROP_STREAMPACKETSIZE | 串流封包的最大大小 | uint32_t |
| CAM_PROP_ISCONNECTED | 0:無實體連接 1:已建立實體連接 | uint32_t |
| CAM_PROP_ISGENICAMCONNECTED | 0:無邏輯連接 1:已建立邏輯連接 | uint32_t |
| CAM_PROP_ISTRANSCEIVERLOCKED | 0:傳輸錯誤過多 1:傳輸穩定 | uint32_t |
| CAM_PROP_XML_DATA | 以字串終止空字元結尾的 Camera XML 資料(additionalValue:buffer 大小) | char * |
| CAM_PROP_VENDOR_NAME | 以字串終止空字元結尾的相機製造商名稱(additionalValue:buffer 大小) | char * |
| CAM_PROP_MODEL_NAME | 以字串終止空字元結尾的相機型號名稱(additionalValue:buffer 大小) | char * |
| CAM_PROP_FAMILY_NAME | 以字串終止空字元結尾的相機系列名稱(additionalValue:buffer 大小) | char * |
| CAM_PROP_VERSION | 以字串終止空字元結尾的相機版本(additionalValue:buffer 大小) | char * |
| CAM_PROP_FIRMWARE_VERSION | 以字串終止空字元結尾的相機韌體版本(additionalValue:buffer 大小) | char * |
| CAM_PROP_MANUFACTURER_INFO | 以字串終止空字元結尾的相機製造商資訊(additionalValue:buffer 大小) | char * |
| CAM_PROP_SERIAL_NUMBER | 以字串終止空字元結尾的相機序號(additionalValue:buffer 大小) | char * |
| CAM_PROP_USER_ID | 以字串終止空字元結尾的相機 User ID(additionalValue:buffer 大小) | char * |
上面的清單並不完整,僅包含對應用程式有用的資訊的 property。有關 API 的更多使用案例,請參閱 Framegrabber API 參考手冊。
如果某個 Property 使用了參數 additionalValue 用於 link index,如果 nullptr 傳遞給 additionalValue 在呼叫中。鏈結索引 0 是相機的主鏈結。
要求取得對應類型的數值時應使用下列數值:
| Property 類型 | C/C++ Type |
|---|---|
| SGC_PROPERTY_TYPE_UINT | uint32_t |
| SGC_PROPERTY_TYPE_DOUBLE | double |
| SGC_PROPERTY_TYPE_STRING | char * |
以下範例顯示如何取得相機連接的速率以及鏈結數量:
unsigned int numberOfLinks = 0;
unsigned int linkSpeed = 0;
int type = SGC_PROPERTY_TYPE_UINT;
int result =
Sgc_getCameraPropertyWithType(camera, CAM_PROP_NROFLINKS,
&linkSpeed, &type, nullptr);
if (result == SGC_OK) {
result =
Sgc_getCameraPropertyWithType(camera, CAM_PROP_LINKSPEED,
&numberOfLinks, &type, nullptr);
}
if (result == SGC_OK) {
std::cout << "Link configuration: " << numberOfLinks
<< " x " << (1e-3 * linkSpeed)
<< " Gbit/s" << std::endl;
}
若要要求取得某種類型的 Property SGC_PROPERTY_TYPE_STRING,對 Sgc_getCameraPropertyWithType() 進行兩次呼叫是必要的。將 nullptr 傳遞給參數 value 以及指向某種類型變量的指標 unsigned int 給參數 additionalValue,字串所需的緩衝區大小(包含結束符號) \0 字元可以被請求並將儲存於變數中。在第二次呼叫中,指向已分配緩衝區的指標將透過參數傳遞 value 連同參數中用於大小的變量指標 additionalValue.如果分配的緩衝區空間大於實際需要,則在返回時,表示緩衝區大小的變數將包含資料的長度,其中包含結尾的 \0 字元。
以下範例顯示如何使用以下內容請求設備型號名稱 Sgc_getCameraPropertyWithType():(此範例需要 C++ 標頭檔 memory 針對 std::unique_ptr 類型。)
// get size of model name
unsigned int size = 0;
unsigned int propertyType = SGC_PROPERTY_TYPE_STRING;
result =
Sgc_getCameraPropertyWithType(camera, CAM_PROP_MODEL_NAME,
nullptr, &propertyType, &size);
if (result == SGC_OK && size > 0) {
// create buffer and request camera model name
std::unique_ptr<char[]> modelName(new char[size]);
result =
Sgc_getCameraPropertyWithType(camera, CAM_PROP_MODEL_NAME,
modelName.get(), &propertyType, &size);
if (result == SGC_OK) {
std::cout << "Camera model name: " << modelName.get() << std::endl;
}
}
當應用程式使用會變更透過下列項目取得之資訊的相機 Property 時 Sgc_getCameraPropertyWithType(), 例如透過設定使用者 ID 字串或更新相機韌體版本,應呼叫函數 Sgc_updateCameraInfos() 以請求更新 Framegrabber API 中的資料。
了解影像資料流#
為了瞭解影像資料如何從相機透過擷取卡中的 applet 流向應用程式 Memory,我們先來看一個簡單的設定,其中兩台相機以直接的方式連接到 applet 中的對應相機運算子:

範例中的小應用程式可以是 Acq_DualCXP12Area,或類似的小程式。來自相機索引為 0 且主識別碼為 1 的相機的影像資料,會透過影像擷取卡的物理埠 0 和 1,傳送至操作員索引為 0 且主識別碼為 1 的相機操作員處;隨後,該資料會在該小程式專屬的影像處理管線中進行處理,並透過索引為 0 的 DMA 操作員傳送至應用程式記憶體。 (由於主機 ID 是根據攝影機或操作器所連接的埠來決定,因此第二台攝影機和操作器的主機 ID 為 3,而非 2。其索引為 1。)
從應用程式的角度來看,重要的資訊在於應在哪個 DMA 通道上預期相機的影像資料。對於範例中的小應用程式配置,僅需要相機的一個 Property, CAM_PROP_APPLETOPERATORINDEX,是瞭解正確 DMA 通道所需的條件。Framegrabber SDK 安裝中包含的所有 applet 都是根據此原則設計的。對於使用 VisualApplets 設計的 applet,強烈建議採用類似的方法並將配置記錄下來。
讓我們來看一個更複雜的範例,其中相機透過交叉電纜連接:

為了讓影像傳輸正常運作,發現程序必須按照上圖所示的方式,將擷取卡的實體連接埠連接到相機運算子上的邏輯連接埠。(查看圖表,還有第二種可能性,即主 ID 為 2 的相機連接到主 ID 為 0 的相機運算子。如果在首次執行發現程序時僅連接了一台相機,而第二台相機是在稍後才加入的,則可能會是這種情況。)
不過,相同的相機 Property CAM_PROP_APPLETOPERATORINDEX, 足以了解正確的 DMA 通道。
為尋找事件註冊回呼函式#
struct SgcEventInfo {
uint16_t eventID;
union SgcEventData data;
}
typedef int (* Sgc_BoardEventCallbackFunc_t)(
SgcBoardHandle * board,
const struct SgcEventInfo * info,
void * data);
int Sgc_registerBoardEventCallback(
SgcBoardHandle * board,
Sgc_BoardEventCallbackFunc_t func,
void * data);
int Sgc_scanPortsEx(
SgcBoardHandle * board,
unsigned int portMask,
int timeout,
int speed,
unsigned int flags);
資訊
函式 Sgc_registerBoardEventCallback() 已在 Framegrabber API 5.9 版本中新增。
使用 Sgc_registerBoardEventCallback(),類型為 SgcEventCallback_t 當庫產生事件時,可以註冊回呼函數。該函數將針對指定的 board handle 進行註冊,並在被呼叫時傳入三個參數。回呼函數的第一個參數是 board handle。第二個參數是指向 struct SgcEventInfo 用於儲存關於事件的資訊。最後一個參數是隨呼叫一起提供的指標 Sgc_registerBoardEventCallback() 並且可用作指向內容結構或類別的指標,例如 this 實作影像處理的類別實例的指標。
每個 board handle 只能註冊一個回呼函數。
關於相機的發現資訊僅會在下列函數執行時更新 Sgc_scanPorts() 或 Sgc_scanPortsEx() 被呼叫。若只要更新資訊, Sgc_scanPortsEx() 可從 callback 函式中呼叫,使用 SGC_SP_FLAG_UPDATE_DISCOVERY_INFOS_ONLY 中的參數 flags.
不再需要回呼函數後,可以透過呼叫來取消註冊 Sgc_registerBoardEventCallback(),並傳遞 nullptr 至參數 func 和 data.
影像 struct SgcEventInfo instance 包含成員中的事件識別碼 eventID 以及聯集成員中的額外資料 data。庫產生的事件會使用以下事件識別碼:
| Event | 描述 |
|---|---|
| SGC_EVENT_DISCOVERY_STATE_CAMERA_ADDED | 已發現新相機 |
| SGC_EVENT_DISCOVERY_STATE_CAMERA_LOST | 與相機的連接已中斷 |
| SGC_EVENT_DISCOVERY_STATE_CAMERA_PROPERTY_CHANGE | 相機連線的 Property 已變更 |
以下範例顯示如何使用可保留對應用程式有用資訊的簡單結構來註冊 callback 函式:
struct DiscoveryUserCallbackData
{
// ...
};
int DiscoveryUserCallback(SgcBoardHandle * board,
const struct SgcEventInfo * info, void * data)
{
auto context = reinterpret_cast<DiscoveryUserCallbackData *>(data);
// update discovery infos
Sgc_scanPortsEx(board, 0xf, 0, LINK_SPEED_NONE,
SGC_SP_FLAG_UPDATE_DISCOVERY_INFOS_ONLY);
// process event ...
return 0;
}
void SetupDiscoveryUserCallback(SgcBoardHandle * board,
DiscoveryUserCallbackData * context)
{
// register callback function
int result =
Sgc_registerBoardEventCallback(board, &DiscoveryUserCallback, context);
if (result != SGC_OK) {
throw std::runtime_error("Failed to register callback function");
}
}
範例中未顯示內容結構的分配與管理。當回呼函數保持註冊狀態時,該指標必須有效。一種解決方案是將所有內容保留在 C++ 類別中。若要在 C++ 類別內容中使用回呼函數,可以使用靜態函數來註冊回呼處理常式,並且 this 指標應作為內容資料指標使用,該指標可以轉換回類別指標並相應地使用。
探索狀態變更資訊#
struct SgcEventData_DiscoveryStateChanged {
uint32_t id;
uint32_t properties_int_count;
char ** properties_int_key;
uint32_t * properties_int_value;
uint32_t properties_string_count;
char ** properties_string_key;
char ** properties_string_value;
};
資訊
discovery state changed 事件是在 Framegrabber API 5.9 版中新增的。
對於 board 事件, struct SgcEventData_DiscoveryStateChanged 用於提供受事件影響的相機連線相關資訊。此結構包含成員中的相機 master id id 以及兩個鍵值對應表(一個用於整數值,另一個用於字串值)。這些鍵與透過以下方式可用的 Property 相同: Sgc_getCameraPropertyWithType(),但根據事件和相機介面技術,並非所有 Property 都會存在於事件資訊中。應用程式可以預期映射中會包含與觸發該事件的變更相關的 Property。除此之外,應用程式不應假設映射中存在特定的 Property 或其順序。
結構中的所有資料僅在 event callback 函式中有效。若需保留資訊,必須複製相關部分。
以下範例顯示如何在 SGC_EVENT_DISCOVERY_STATE_CAMERA_PROPERTY_CHANGE event:
int DiscoveryUserCallback(SgcBoardHandle * board,
const struct SgcEventInfo * info, void * data)
{
auto context = reinterpret_cast<DiscoveryUserCallbackData *>(data);
// update discovery infos
Sgc_scanPortsEx(board, 0xf, 0, LINK_SPEED_NONE,
SGC_SP_FLAG_UPDATE_DISCOVERY_INFOS_ONLY);
// process event ...
if (info->eventID == SGC_EVENT_DISCOVERY_STATE_CAMERA_PROPERTY_CHANGE) {
int newNumOfLinks = 0;
int newLinkSpeed = LINK_SPEED_NONE;
for (int i = 0; i < info->data.discovery_state.properties_int_count; ++i) {
if (strcmp(info->data.discovery_state.properties_int_keys[i],
CAM_PROP_NROFLINKS) == 0) {
newNumOfLinks = info->data.discovery_state.properties_int_values[i];
}
if (strcmp(info->data.discovery_state.properties_int_keys[i],
CAM_PROP_LINKSPEED) == 0) {
newLinkSpeed = info->data.discovery_state.properties_int_values[i];
}
}
// ...
}
return 0;
}
使用 GenICam 參考實作#
使用 GenICam 參考實作是使用 Framegrabber API 所提供的 GenApi 包裝函式的另一種選擇,如第 使用相機 Property章節所述。如果應用程式使用 GenICam 參考實作,則 Sgc_connectCamera() 或 Sgc_connectCameraWithExternalXml() 不得呼叫。相反地,應用程式應包含 GenApi 標頭檔 GenICam.h,連結至 GenICam 庫 GCBase 和 GenApi 並初始化對應的 GenApi 內容。
#include <GenICam.h>
若要使用隨 Framegrabber SDK 安裝提供的 GenICam 參考實作,應執行以下步驟:
- 如果應用程式在 Windows 上使用 64-bit Framegrabber SDK:
- 將
%BASLER_FG_SDK_DIR%\bin至系統環境變數PATH - 將
%BASLER_FG_SDK_DIR%\include新增至專案包含目錄 - 將
%BASLER_FG_SDK_DIR%\library\visualc至專案庫目錄 - 新增程式庫
GCBase_MD_VC141_v3_1_Basler_pylon_v3.lib和GenApi_MD_VC141_v3_1_Basler_pylon_v3.lib至您的專案連結庫 - 如果應用程式在 Linux 上使用 64 位元 Framegrabber SDK:
- 將
$BASLER_FG_SDK_DIR\lib64至系統環境變數LD_LIBRARY_PATH以及專案庫目錄 - 將
$BASLER_FG_SDK_DIR\include新增至專案包含目錄 - 新增程式庫
libGCBase_gcc_v3_1_Basler_pylon_v3.so和libGenApi_gcc_v3_1_Basler_pylon_v3.so至您的專案連結庫 - 將
#define GENICAM_NO_AUTO_IMPLIB在#include <GenICam.h>
如果您使用 CMake 來產生專案檔案,SisoGenicam 套件也會尋找隨 Framegrabber SDK 安裝附帶的 GenICam 庫,並將其包含在變數中 ${SisoGenicam_LIBRARIES}之前。GenICam 包含路徑儲存在變數中 ${GENICAM_INCLUDE_DIR} 其應新增至 INCLUDE_DIRECTORIES.
建立 IPort 包裝函式#
int Sgc_memoryReadFromCamera(
SgcCameraHandle * camera,
void * buffer,
uint64_t address,
size_t length);
int Sgc_memoryWriteToCamera(
SgcCameraHandle * camera,
const void * buffer,
uint64_t address,
size_t length);
若要使用 GenICam 參考實作, GENAPI_NAMESPACE::IPort 需要一個 wrapper 來轉譯 Framegrabber API 與 GenApi 之間的相機暫存器存取。函式 Sgc_memoryReadFromCamera() 和 Sgc_memoryWriteToCamera() 可用於建立簡單直接的 wrapper 類別:
class DevicePort: virtual public GENAPI_NAMESPACE::IPort
{
SgcCameraHandle * camera;
public:
DevicePort(SgcCameraHandle * camera)
: camera(camera)
{}
GENAPI_NAMESPACE::EAccessMode GetAccessMode() const override
{
return GENAPI_NAMESPACE::RW;
}
void Read(void * buffer, int64_t address, int64_t length) override
{
int result = Sgc_memoryReadFromCamera(camera, buffer, address, length);
if (result != SGC_OK) {
// handle error ...
}
}
void Write(const void * buffer, int64_t address, int64_t length) override
{
int result = Sgc_memoryWriteToCamera(camera, buffer, address, length);
if (result != SGC_OK) {
// handle error ...
}
}
};
初始化並連接節點對應 (Node Map)#
int Sgc_loadCameraXml(
SgcCameraHandle * camera);
將 GenICam 參考實作連接至 Framegrabber API 的最後步驟為:取得相機的 GenICam XML 文件、建立 node map 並將其連接至 XML。
若要從相機下載並解壓縮 XML 文件,請使用函式 Sgc_loadCameraXml() 和 Sgc_getCameraPropertyWithType() 可以使用。首先,函數 Sgc_loadCameraXml() 應被呼叫以從相機下載 XML 文件。然後函數 Sgc_getCameraPropertyWithType() 可以透過傳遞 CAM_PROP_XML_DATA 給參數 property 和 nullptr 給參數 value 以請求解壓縮 XML 文件所需的緩衝區大小。配置所需大小的緩衝區後, Sgc_getCameraPropertyWithType() 可以再次呼叫,並在參數中傳遞指向緩衝區的指標 value 以解壓縮 XML 文件。
以下範例顯示如何從相機下載並擷取 XML 文件、初始化並連接 node map,以及設定要傳輸的影像寬度和高度:(此範例需要 C++ 標頭檔) memory 針對 std::unique_ptr 型別與 stdexcept 針對 std::runtime_error 和 std::exception types.)
try {
// download camera XML
int result = Sgc_loadCameraXml(camera);
if (result != SGC_OK)
throw std::runtime_error("Failed to download camera XML");
// get size of XML
unsigned int size = 0;
unsigned int propertyType = SGC_PROPERTY_TYPE_STRING;
result =
Sgc_getCameraPropertyWithType(camera, CAM_PROP_XML_DATA,
nullptr, &propertyType, &size);
if (result != SGC_OK || size == 0)
throw std::runtime_error("Failed to determine size of camera XML");
// create buffer and extract camera XML
std::unique_ptr<char[]> xml(new char[size]);
result =
Sgc_getCameraPropertyWithType(camera, CAM_PROP_XML_DATA,
xml.get(), &propertyType, &size);
if (result != SGC_OK)
throw std::runtime_error("Failed to extract camera XML");
// create device port and node map
DevicePort port(camera);
GENAPI_NAMESPACE::CNodeMapRef nodeMap;
// initialize and connect node map
nodeMap._LoadXMLFromString(xml.get());
if (!nodeMap._Connect(&port, "Device"))
throw std::runtime_error("Failed to connect node map to device port");
// use node map to access camera features ...
// set width
GENAPI_NAMESPACE::CIntegerPtr width = nodeMap._GetNode("Width");
if (width != nullptr) {
width->SetValue(1920);
}
// set height
GENAPI_NAMESPACE::CIntegerPtr height = nodeMap._GetNode("Height");
if (height != nullptr) {
height->SetValue(1080);
}
} catch (GENICAM_NAMESPACE::GenericException & x) {
// handle GenICam exceptions ...
} catch (std::exception & x) {
// handle C++ standard exceptions ...
}
變更相機連接#
int Sgc_setCameraPropertyWithType(
SgcCameraHandle * camera,
const char * property,
const void * value,
unsigned int type,
void * additionalValue);
若要變更相機的連線速度或使用的連線數量,請使用函式 Sgc_setCameraPropertyWithType() can be called. It works in a similar way as the function Sgc_getCameraPropertyWithType() 章節中所述的函式 相機資訊.
有兩個 Property 可以變更:
| Property | 描述 | Type |
|---|---|---|
| CAM_PROP_LINKSPEED | 當前鏈路速度(以 Mbit/s 為單位) | uint32_t |
| CAM_PROP_NROFLINKS | 用於影像傳輸的實體鏈路數量 | uint32_t |
支援從多個行程進行相機探索#
int Sgc_initBoardEx(
Fg_Struct * fg,
unsigned int flags,
SgcBoardHandle ** board,
unsigned int portMask,
unsigned int mode);
int Sgc_scanPortsEx(
SgcBoardHandle * board,
unsigned int portMask,
int timeout,
int speed,
unsigned int flags);
資訊
Framegrabber API 的 5.9 版本新增了對來自多個行程的相機探索功能。
如果應用程式使用多個行程來存取單一擷取卡上的相機,Framegrabber API 僅支援每個擷取卡實體連接埠一個行程。雖然單一行程可以存取多個實體連接埠,但絕對不能透過 Framegrabber API 從多個行程存取任何實體連接埠。
在多行程應用程式中,可以透過取代對下列項目的呼叫來限制對實體連接埠的存取: Sgc_initBoard() 和 Sgc_scanPorts() 並使用 Sgc_initBoardEx() 和 Sgc_scanPortsEx() 並使用連接埠遮罩。此外, SGC_SP_FLAG_SKIP_AUTO_PORTADJUSTMENT should be used in the call to Sgc_scanPortsEx() 中的參數 flags 以抑止重新對應實體連接埠。
連接埠遮罩(port mask)每個實體連接埠使用一個位元,當位元為 1 時啟用對該連接埠的存取,當位元為 0 時停用存取。位元 0 對應到實體連接埠 0,依此類推。在預設的連接埠遮罩中 0xf 所有四個連接埠的位元皆為 1,因此已啟用對所有四個連接埠的存取。
最容易理解的場景是具有一個擷取卡和四台相機的設定,每台相機連接到單一實體連接埠。第一個行程可以使用連接埠遮罩 0x1, the second 0x2,第三個 0x4 and the fourth 0x8。每個行程將負責在一個實體連接埠上進行初始化與探索。
當我們考慮連接了多個連接線(link)的相機時,情況會變得稍微複雜一些,因為相機必須始終連接到正確的實體連接埠。例如,如果第一個行程使用連接埠遮罩 0x3 而第二個使用連接埠遮罩 0xc, 第一台相機的連接線在任何情況下都必須連接到連接埠 0 和 1,而第二台相機則必須連接到連接埠 2 和 3。如果在任何時間點以不同方式連接相機,探索程序將會失敗。