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。
相機控制函式庫中的 Error Handling#
const char * Sgc_getErrorDescription(
int result);
API 的大多數函式皆會傳回一個 int 結果代碼。如果函式呼叫成功執行,則傳回值將會是 SGC_OK 或是針對某些函式傳回大於或等於零的值。在多數情況下,負值代表發生錯誤狀況。Error Codes 定義於標頭檔 siso_genicam_error.h中,該檔案會自動包含在檔案 siso_genicam.h.
函數 Sgc_getErrorDescription() 可用於取得特定結果代碼的字串表示形式。
本說明文件其餘部分的程式碼範例將不包含 error handling,因為這取決於應用程式的特定需求。不過,在可行範圍內,仍會檢查傳回代碼以確保函式成功執行。
相機控制函式庫初始化#
int Sgc_initBoard(
Fg_Struct * fg,
unsigned int flags,
SgcBoardHandle ** board);
void Sgc_freeBoard(
SgcBoardHandle * board);
若要開始使用 siso_genicam 函式庫,必須先如 畫面擷取卡庫 fglib5。接下來,應用程式所使用的每個畫面擷取卡都應呼叫 Sgc_initBoard() 函數。參數 flags 保留供未來擴充使用,應用程式應一律傳入 0。若初始化成功,應將主機板代辦事項(board handle)儲存至傳入參數 board.
的變數中。如果應用程式已完成使用 siso_genicam 庫,則應透過呼叫 Sgc_freeBoard() 來釋放所有成功取得的主機板代辦事項(board handle)。
以下範例顯示如何取得主機板代辦事項(board 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的主機板代辦事項(board handle)、在參數中指定要執行探索之實體連接埠的位元遮罩(bit mask) portMask 以及在參數中等待至少探索到一部相機的毫秒時間 timeout。參數 speed 在大多數情況下應為 LINK_SPEED_NONE 。它可選擇性地用於提供探索提示,指出預期在哪個連線速度下探索到相機。
在使用單一程序執行一個或多個畫面擷取卡的應用程式中,連接埠遮罩應一律為 0xf。透過這種方式,將會掃描畫面擷取卡的所有連接埠以尋找相機。如果應用程式針對畫面擷取卡使用多個程序,請閱讀章節 支援來自多個處理程序的相機搜尋.
探索相機後,會根據所使用的 Applet 與相機預設設定來協商最終的連線設定。了解此程序的限制有助於理解向應用程式呈現已探索相機時的狀態。探索演算法不會使用相機所提供的 GenICam XML。相反地,預設相機設定決定了探索程序可供該相機使用的最大連線速度與最大連線數。對某些相機而言,預設設定並非相機可使用的最高連線速度或最大連線數!另一方面,Applet 版面配置決定了 Applet 探索程序可使用的最大相機數量,以及每部相機的最大連線數。探索演算法會試圖將一方面找到的相機與另一方面 Applet 的版面配置進行最佳匹配。請參閱 Applet 文件與相機文件,以尋找最符合您打算使用的相機設置與功能的 Applet。
(亦請參閱章節 Understanding Image Data Flow 以了解說明 Applet 版面配置的圖表。對於連接至畫面擷取卡的每個相機,Applet 需要對應的相機運算子。相機運算子的數量是每個 Applet 的固定屬性。您可能也想複習部分 The Frame Grabber Library fglib5 之章節 Frame Grabber Initialization 結尾處的註解,以了解如何為連接至畫面擷取卡的相機選擇 Applet。)
如果對 Sgc_scanPorts() 傳回 SGC_OK的呼叫,則表示在指定時間內至少找到一部相機,且 Applet 與相機可以成功匹配。如果傳回值為 ERR_SGC_TOPOLOGY_MISMATCH,則表示至少找到一部相機,但 Applet 與相機無法匹配,雖然與相機的通訊仍然可行,但無法將影像資料從相機正確傳輸至 Applet。
成功呼叫 Sgc_scanPorts()取得 bytearray,可以呼叫 Sgc_getCameraCount() 後,即可呼叫以要求所找到的相機數量,並使用其中一個 Sgc_getCameraByIndex() 或 Sgc_getCamera() 來取得相機控制代碼。這兩個函式運作方式相似,且都需要三個參數。第一個參數是應看作的板卡控制代碼。對於 Sgc_getCameraByIndex()而言,第二個參數透過 0 到 Sgc_getCameraCount() 所回報的相機數量減 1 之間的數字來識別相機。因此,該函式可用於方便地迭代所有已發現的相機,但發現相機的順序以及因此產生的索引可能會在兩次呼叫 Sgc_scanPorts()。對於 Sgc_getCamera()之間改變;第二個參數則透過相機連接的實體連接埠來識別相機。實體連接埠從 0 開始編號,最高可達所使用擷取卡的實體連接埠總數減 1。如果始終使用相同的實體纜線佈局,則可使用此函式來避免 Sgc_getCameraByIndex()中所述的不確定性。第三個參數是指向用來儲存相機控制代碼之變數的指標。
以下範例顯示如何搜尋相機最長 10 秒鐘,然後取得對應的相機控制代碼:
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 以啟動裝置發現程序。在回呼處理常式中,應用程式可以在發現新相機時,例如啟動獨立的擷取執行緒。
或者,應用程式可以重複呼叫 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.
處理相機 features#
發現相機後,應用程式即可開始使用相機功能。這些功能(即相機參數與指令)定義在 XML 文件中,相機可透過標準化功能介面提供此文件供下載,或透過相機製造商的其他方式提供(例如,某些相機製造商可能會提供可下載 XML 文件的網站)。XML 文件的結構是在 GenICam 標準中定義。若要深入了解 GenICam,請造訪歐洲機器視覺協會 (European Machine Vision Association) 的 GenICam 網站。若要深入了解相機所提供的功能,請參閱相機文件。
GenICam 標準還定義了透過 GenApi 控制相機功能的方法。使用 GenICam 參考實作一章將討論如何將 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().
取得與設定相機 features#
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 以及在參數中的功能名稱 feature中。函數 Sgc_isCommandDone() 可用於檢查命令是否已執行完畢。它在參數中預期相機代碼 camera在參數中預期功能名稱 feature 以及指向型別變數的指標 unsigned int 中的參數來重新啟動尋找 value如果命令已執行完畢,變數中將會儲存值 1;如果命令仍在執行中,則會儲存值 0。
這些函式 Sgc_startAcquisition() 進行明確的生命週期管理即呼叫 Sgc_stopAcquisition() 是標準功能的捷徑 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 | 以零結字串表示的相機 XML 資料(additionalValue:緩衝區大小) | char * |
| CAM_PROP_VENDOR_NAME | 以零結字串表示的相機製造商名稱(additionalValue:緩衝區大小) | char * |
| CAM_PROP_MODEL_NAME | 以零結字串表示的相機型號名稱(additionalValue:緩衝區大小) | char * |
| CAM_PROP_FAMILY_NAME | 以零結字串表示的相機系列名稱(additionalValue:緩衝區大小) | char * |
| CAM_PROP_VERSION | 相機版本,以零結尾的字串形式(additionalValue:緩衝區大小) | char * |
| CAM_PROP_FIRMWARE_VERSION | 相機韌體版本,以零結尾的字串形式(additionalValue:緩衝區大小) | char * |
| CAM_PROP_MANUFACTURER_INFO | 相機製造商資訊,以零結尾的字串形式(additionalValue:緩衝區大小) | char * |
| CAM_PROP_SERIAL_NUMBER | 相機序號,以零結尾的字串形式(additionalValue:緩衝區大小) | char * |
| CAM_PROP_USER_ID | 相機 User ID,以零結尾的字串形式(additionalValue:緩衝區大小) | char * |
上述清單並不完整,僅包含對應用程式有用的資訊Property。有關該 API 的更多使用案例,請參閱 Framegrabber API 參考手冊。
若某個 Property 使用了參數 additionalValue 作為連線索引(link index),若在呼叫中將 nullptr 傳遞給 additionalValue ,則預設連線索引為 0。連線索引 0 為相機的主連線(master link)。
應使用下列值來請求對應型別的值:
| Property 型別 | C/C++ 型別 |
|---|---|
| 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;
}
若要請求型別為 SGC_PROPERTY_TYPE_STRING的 Property,需要對 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;
}
}
當應用程式使用會變更透過以下內容取得之資訊的相機功能時 Sgc_getCameraPropertyWithType(),例如透過設定使用者 ID 字串或更新相機韌體版本,應呼叫函數 Sgc_updateCameraInfos() 以要求更新 Framegrabber API 中的資料。
了解影像資料流程#
為了理解影像資料如何從相機透過擷取卡中的 applet 傳輸到應用程式記憶體中,我們先來看一個簡單的設定,其中兩部相機以直覺的方式連接到 applet 中的對應相機運算子:

範例中的 applet 可以是 Acq_DualCXP12Area或類似的 applet。來自相機索引為 0 且主識別碼 (master id) 為 1 的相機的影像資料,會透過擷取卡的實體連接埠 0 和 1 流向相機運算子(運算子索引為 0 且主識別碼為 1),然後在該 applet 專屬的影像管線中進行處理,並透過索引為 0 的 DMA 運算子傳送至應用程式記憶體。(由於主識別碼是根據相機或運算子所連接的連接埠而定,因此第二部相機和運算子的主識別碼為 3,而不是 2。其索引為 1。)
從應用程式的角度來看,最重要的資訊是預期在哪個 DMA 通道上接收相機的影像資料。對於範例中的 applet 配置,只需要相機的一個屬性 CAM_PROP_APPLETOPERATORINDEX,即可得知正確的 DMA 通道。所有包含在 Framegrabber SDK 安裝中的 applet 都是根據此原則設計的。對於使用 VisualApplets 設計的 applet,強烈建議採用類似的方法並將配置記錄下來。
讓我們來看一個更複雜的範例,其中相機是以交叉纜線連接:

為了讓影像傳輸正常運作,偵測程序必須以如上圖所示的方式,將擷取卡的實體連接埠連接到相機運算子上的邏輯連接埠。(從圖中可以看出,還有第二種可能性,即主識別碼為 2 的相機連接到主識別碼為 0 的相機運算子。當首次執行偵測程序時僅連接了一部相機,而後續才新增第二部相機時,可能就會是這種情況。)
儘管如此,相同的相機屬性 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 的函數可以進行註冊,以便在程式庫產生事件時進行回呼。該函數將針對指定的板卡代代柄進行註冊,並在呼叫時傳入三個參數。回呼函數的第一個參數是板卡控制代碼。第二個參數是指向 struct SgcEventInfo 用於儲存有關事件的資訊。最後一個引數是一個指標,隨呼叫一起提供 Sgc_registerBoardEventCallback() 並且可以用作指向上下文結構或類別的指標,例如 this 實作影像處理的類別執行個體的指標。
每個板卡代碼(board handle)只能註冊一個回呼函式。
關於相機的探索資訊僅在以下函式 Sgc_scanPorts() 或 Sgc_scanPortsEx() 被呼叫時才會更新。若只想更新資訊, Sgc_scanPortsEx() 可以從回呼函式中呼叫,使用 SGC_SP_FLAG_UPDATE_DISCOVERY_INFOS_ONLY 中的參數來重新啟動尋找 flags.
當不再需要回呼函式時,可以透過呼叫取消註冊 Sgc_registerBoardEventCallback(),並將 nullptr 傳遞給參數 func 進行明確的生命週期管理即呼叫 data.
當 struct SgcEventInfo 執行個體在其成員中包含事件的識別碼 eventID 以及聯集成員中的附加資料 data。library 所產生的事件會使用以下事件識別碼:
| 事件 | 描述 |
|---|---|
| SGC_EVENT_DISCOVERY_STATE_CAMERA_ADDED | 已發現新相機 |
| SGC_EVENT_DISCOVERY_STATE_CAMERA_LOST | 與相機的連線已中斷 |
| SGC_EVENT_DISCOVERY_STATE_CAMERA_PROPERTY_CHANGE | 相機連線的 Property 已變更 |
以下範例展示如何使用簡單的結構來註冊回呼函式,該結構可以保留對應用程式有用的資訊:
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;
};
資訊
探索狀態變更事件是在 Framegrabber API 的 5.9 版本中新增的。
對於板卡事件, struct SgcEventData_DiscoveryStateChanged 用於提供有關事件中受影響的相機連線的資訊。該結構在成員中包含相機 master id id 以及兩個鍵值對應表(Key-Value Map),一個用於整數值,另一個用於字串值。這些鍵與透過以下方式提供的 Property 相同: Sgc_getCameraPropertyWithType(),但根據事件與相機介面技術,並非所有 Property 都會存在於 Event Info 中。應用程式可以預期,與觸發事件之變更相關的 Property 會存在於對應表中。除此之外,應用程式不應假設 Property 的存在性或對應表中 Property 的順序。
結構中的所有資料僅在 Event 回呼函式中有效。若需保留資訊,必須複製相關部分。
以下範例顯示如何在 SGC_EVENT_DISCOVERY_STATE_CAMERA_PROPERTY_CHANGE 事件中擷取連線速度與連線數量:
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 包裝函式(如章節所述)的另一種選擇 處理相機 features。如果應用程式使用 GenICam 參考實作,則函式 Sgc_connectCamera() 或 Sgc_connectCameraWithExternalXml() 不得被呼叫。相反地,應用程式應包含 GenApi 標頭檔 GenICam.h、連結至 GenICam 程式庫 GCBase 進行明確的生命週期管理即呼叫 GenApi 並初始化對應的 GenApi Context。
#include <GenICam.h>
若要使用隨 Framegrabber SDK 安裝隨附的 GenICam 參考實作,應採取以下步驟:
- 如果應用程式在 Windows 上使用 64 位元 Framegrabber SDK:
- 新增
%BASLER_FG_SDK_DIR%\bin至系統環境變數PATH - 新增
%BASLER_FG_SDK_DIR%\include至專案 Include 目錄 - 新增
%BASLER_FG_SDK_DIR%\library\visualc至專案 Library 目錄 - 新增程式庫
GCBase_MD_VC141_v3_1_Basler_pylon_v3.lib進行明確的生命週期管理即呼叫GenApi_MD_VC141_v3_1_Basler_pylon_v3.lib至您的專案 Link 程式庫 - 如果應用程式在 Linux 上使用 64 位元 Framegrabber SDK:
- 新增
$BASLER_FG_SDK_DIR\lib64至系統環境變數LD_LIBRARY_PATH以及專案 Library 目錄 - 新增
$BASLER_FG_SDK_DIR\include至專案 Include 目錄 - 新增程式庫
libGCBase_gcc_v3_1_Basler_pylon_v3.so進行明確的生命週期管理即呼叫libGenApi_gcc_v3_1_Basler_pylon_v3.so至您的專案 Link 程式庫 - 新增
#define GENICAM_NO_AUTO_IMPLIB之前#include <GenICam.h>
如果您使用 CMake 來產生專案檔案,套件 SisoGenicam 也會尋找隨 Framegrabber SDK 安裝隨附的 GenICam 程式庫,並將其包含在變數中 ${SisoGenicam_LIBRARIES}。GenICam Include 路徑儲存在變數 ${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 包裝函式,用於在 Framegrabber API 與 GenApi 之間轉換對相機暫存器的存取。這些函式 Sgc_memoryReadFromCamera() 進行明確的生命週期管理即呼叫 Sgc_memoryWriteToCamera() 可用於建立簡單直接的包裝函式類別:
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 文件、初始化並連接節點對應表,以及設定要傳輸的影像寬度和高度:(此範例需要 C++ 標頭檔 memory 適用於 std::unique_ptr 型別與 stdexcept 適用於 std::runtime_error 進行明確的生命週期管理即呼叫 std::exception 型別。)
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() 。它的運作方式與第 Sgc_getCameraPropertyWithType() 章中所述的函式 相機資訊.
類似。
| 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() 的呼叫並使用連接埠遮罩(port mask)來限制對實體連接埠的存取。此外,在呼叫 SGC_SP_FLAG_SKIP_AUTO_PORTADJUSTMENT 時應使用 Sgc_scanPortsEx() 中的參數來重新啟動尋找 flags 以抑制實體連接埠重新對應。
連接埠遮罩每個實體連接埠使用一個位元,當位元為 1 時啟用對連接埠的存取,為 0 時停用存取。位元 0 對應至實體連接埠 0,依此類推。在預設連接埠遮罩 0xf 中,所有四個連接埠的位元均為 1,因此已啟用對所有四個連接埠的存取。
最容易理解的情境是配備一張擷取卡和四台相機的設定,每台相機連接至單一實體連接埠。第一個處理程序可以使用連接埠遮罩 0x1,第二個 0x2,第三個 0x4 以及第四個 0x8。每個進程將負責單個實體連接埠上的初始化與探索。
當考慮連接多個連結的相機時,情況會變得更複雜,因為相機必須始終連接到正確的實體連接埠。例如,如果第一個進程使用連接埠遮罩 0x3 而第二個進程使用連接埠遮罩 0xc,在任何情況下,第一台相機的纜線必須連接到連接埠 0 和 1,而第二台相機的纜線必須連接到連接埠 2 和 3。如果在任何時間點以不同方式連接相機,探索程序將會失敗。