在機器視覺項目開發中,相機的初始化、參數讀取與設置是最基礎也是最關鍵的環節。本文基于海康機器人(Hikrobot)提供的MVS SDK,使用C語言實現了一個簡潔的控制程序,完成設備枚舉、連接以及常用參數的獲取與設置。
📌 功能概述
該程序主要實現了以下功能:
初始化SDK環境
自動枚舉當前連接的所有相機設備(支持GigE、USB、CameraLink、CXP等類型)
打印每臺設備的基本信息,如型號、IP地址、用戶自定義名稱等
用戶可選擇指定設備進行操作
連接設備后,對常見類型的參數進行讀寫操作:整型參數:如圖像高度(Height)浮點型參數:如曝光時間(ExposureTime)枚舉型參數:如觸發模式(TriggerMode)布爾型參數:如圖像翻轉(ReverseX)字符串型參數:如設備用戶ID(DeviceUserID)
最后關閉設備并釋放資源
#include <stdio.h> // 標準輸入輸出庫,用于 printf, scanf 等
#include <string.h> // 字符串操作庫,用于 memset 等
#include "MvCameraControl.h" // 海康機器人(Hikrobot)相機 SDK 頭文件,包含所有相機控制函數和結構體定義// =================================================================================================
// 函數:PressEnterToExit
// 用途:等待用戶按回車鍵以退出程序(本程序中未實際調用,但可作為調試輔助)
// 說明:該函數用于阻塞程序,等待用戶輸入回車,常用于防止控制臺程序閃退
// =================================================================================================
void PressEnterToExit(void)
{int c;// 清空輸入緩沖區中的殘留字符(如之前 scanf 留下的換行符)while ( (c = getchar()) != '\n' && c != EOF );// 提示用戶按回車退出fprintf( stderr, "\n請按回車鍵退出。\n");// 再次等待用戶按回車while( getchar() != '\n');
}// =================================================================================================
// 函數:PrintDeviceInfo
// 用途:根據設備類型打印相機的詳細信息(型號、IP、用戶自定義名稱等)
// 參數:pstMVDevInfo - 指向設備信息結構體的指針
// 返回值:成功返回 true,失敗返回 false
// 說明:根據設備的傳輸層類型(GigE、USB、CameraLink 等)使用不同的結構體成員打印信息
// =================================================================================================
bool PrintDeviceInfo(MV_CC_DEVICE_INFO* pstMVDevInfo)
{// 檢查指針是否為空,防止空指針訪問if (NULL == pstMVDevInfo){printf("設備信息指針為空!\n");return false;}// 根據設備的傳輸層類型進行分支處理if (pstMVDevInfo->nTLayerType == MV_GIGE_DEVICE){// GigE 網口相機:解析當前IP地址(32位整數轉為點分十進制)int nIp1 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24);int nIp2 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16);int nIp3 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8);int nIp4 = (pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff);// 打印 GigE 相機信息printf("設備型號名稱: %s\n", pstMVDevInfo->SpecialInfo.stGigEInfo.chModelName);printf("當前IP地址: %d.%d.%d.%d\n" , nIp1, nIp2, nIp3, nIp4);printf("用戶自定義名稱: %s\n\n" , pstMVDevInfo->SpecialInfo.stGigEInfo.chUserDefinedName);}else if (pstMVDevInfo->nTLayerType == MV_USB_DEVICE){// USB3.0 相機:打印型號和用戶自定義名稱printf("設備型號名稱: %s\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chModelName);printf("用戶自定義名稱: %s\n\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chUserDefinedName);}else if (pstMVDevInfo->nTLayerType == MV_GENTL_GIGE_DEVICE){// GenTL 協議下的 GigE 相機:打印用戶自定義名、序列號、型號printf("用戶自定義名稱: %s\n", pstMVDevInfo->SpecialInfo.stGigEInfo.chUserDefinedName);printf("序列號: %s\n", pstMVDevInfo->SpecialInfo.stGigEInfo.chSerialNumber);printf("型號名稱: %s\n\n", pstMVDevInfo->SpecialInfo.stGigEInfo.chModelName);}else if (pstMVDevInfo->nTLayerType == MV_GENTL_CAMERALINK_DEVICE){// CameraLink 相機:打印用戶自定義名、序列號、型號printf("用戶自定義名稱: %s\n", pstMVDevInfo->SpecialInfo.stCMLInfo.chUserDefinedName);printf("序列號: %s\n", pstMVDevInfo->SpecialInfo.stCMLInfo.chSerialNumber);printf("型號名稱: %s\n\n", pstMVDevInfo->SpecialInfo.stCMLInfo.chModelName);}else if (pstMVDevInfo->nTLayerType == MV_GENTL_CXP_DEVICE){// CoaXPress (CXP) 相機:打印用戶自定義名、序列號、型號printf("用戶自定義名稱: %s\n", pstMVDevInfo->SpecialInfo.stCXPInfo.chUserDefinedName);printf("序列號: %s\n", pstMVDevInfo->SpecialInfo.stCXPInfo.chSerialNumber);printf("型號名稱: %s\n\n", pstMVDevInfo->SpecialInfo.stCXPInfo.chModelName);}else if (pstMVDevInfo->nTLayerType == MV_GENTL_XOF_DEVICE){// XoF (如光纖) 相機:打印用戶自定義名、序列號、型號printf("用戶自定義名稱: %s\n", pstMVDevInfo->SpecialInfo.stXoFInfo.chUserDefinedName);printf("序列號: %s\n", pstMVDevInfo->SpecialInfo.stXoFInfo.chSerialNumber);printf("型號名稱: %s\n\n", pstMVDevInfo->SpecialInfo.stXoFInfo.chModelName);}else{// 不支持的設備類型printf("設備類型不支持。\n");}return true;
}// =================================================================================================
// 主函數:main
// 用途:演示如何使用海康相機 SDK 進行設備枚舉、參數讀寫等基本操作
// 流程:
// 1. 初始化 SDK
// 2. 枚舉所有連接的相機設備
// 3. 打印設備信息
// 4. 用戶選擇一個設備
// 5. 創建句柄并打開設備
// 6. 讀取并設置各種類型的相機參數(int, float, enum, bool, string)
// 7. 關閉設備并銷毀句柄
// 8. 反初始化 SDK
// =================================================================================================
int main()
{int nRet = MV_OK; // 用于存儲 SDK 函數調用的返回值,MV_OK 表示成功void* handle = NULL; // 相機設備的句柄(類似于文件描述符),用于后續所有操作// 使用 do-while(0) 結構實現“偽 goto”,便于在任意步驟出錯時跳出并統一清理資源do {// ================== 步驟 1:初始化 SDK ==================nRet = MV_CC_Initialize();if (MV_OK != nRet){printf("初始化SDK失敗!錯誤碼 [0x%x]\n", nRet);break; // 初始化失敗,跳出循環}printf("SDK初始化成功。\n");// 定義設備列表結構體,用于存儲枚舉到的設備信息MV_CC_DEVICE_INFO_LIST stDeviceList;memset(&stDeviceList, 0, sizeof(MV_CC_DEVICE_INFO_LIST)); // 結構體清零,防止野值// ================== 步驟 2:枚舉設備 ==================// 枚舉所有支持的設備類型(GigE, USB, CameraLink, CXP, XoF)nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE | MV_GENTL_CAMERALINK_DEVICE | MV_GENTL_CXP_DEVICE | MV_GENTL_XOF_DEVICE, &stDeviceList);if (MV_OK != nRet){printf("枚舉設備失敗!錯誤碼 [%x]\n", nRet);break;}// 檢查是否找到設備if (stDeviceList.nDeviceNum > 0){printf("共發現 %d 臺設備:\n", stDeviceList.nDeviceNum);for (int i = 0; i < stDeviceList.nDeviceNum; i++){printf("[設備 %d]:\n", i);MV_CC_DEVICE_INFO* pDeviceInfo = stDeviceList.pDeviceInfo[i]; // 獲取第 i 個設備的信息指針if (NULL == pDeviceInfo){break;} PrintDeviceInfo(pDeviceInfo); // 調用函數打印設備信息 } } else{printf("未發現任何設備!\n");break; // 無設備,跳出}// ================== 步驟 3:用戶選擇設備 ==================printf("請輸入要操作的相機序號: ");unsigned int nIndex = 0;if(0 == scanf("%d", &nIndex)) // 檢查輸入是否為有效整數{printf("輸入格式錯誤!\n");break;}// 檢查用戶輸入的索引是否有效if (nIndex >= stDeviceList.nDeviceNum){printf("輸入錯誤!序號超出范圍。\n");break;}// ================== 步驟 4:創建設備句柄 ==================// 根據用戶選擇的設備信息創建句柄nRet = MV_CC_CreateHandle(&handle, stDeviceList.pDeviceInfo[nIndex]);if (MV_OK != nRet){printf("創建設備句柄失敗!錯誤碼 [%x]\n", nRet);break;}printf("設備句柄創建成功。\n");// ================== 步驟 5:打開設備 ==================// 打開指定的相機設備,建立通信nRet = MV_CC_OpenDevice(handle);if (MV_OK != nRet){printf("打開設備失敗!錯誤碼 [%x]\n", nRet);break;}printf("設備打開成功。\n");// ================== 步驟 6:獲取并設置各種類型的相機參數 ==================// --- 6.1 獲取 int 型參數:圖像高度 (Height) ---MVCC_INTVALUE stHeight = {0}; // 定義結構體存儲 int 型參數信息nRet = MV_CC_GetIntValue(handle, "Height", &stHeight);if (MV_OK == nRet){printf("圖像高度 - 當前值: %d\n", stHeight.nCurValue);printf("圖像高度 - 最大值: %d\n", stHeight.nMax);printf("圖像高度 - 最小值: %d\n", stHeight.nMin);printf("圖像高度 - 增量: %d\n\n", stHeight.nInc);}else{printf("獲取圖像高度失敗!錯誤碼 [%x]\n\n", nRet);}// --- 6.2 設置 int 型參數:圖像高度 ---unsigned int nHeightValue = 0;printf("請輸入要設置的圖像高度: ");if(0 == scanf("%d", &nHeightValue)){printf("輸入格式錯誤!\n");break;}// 注意:某些相機的寬高設置有步進要求(如16的倍數)nRet = MV_CC_SetIntValueEx(handle, "Height", nHeightValue); if (MV_OK == nRet){printf("設置圖像高度成功!\n\n");}else{printf("設置圖像高度失敗!錯誤碼 [%x]\n\n", nRet);}// --- 6.3 獲取 float 型參數:曝光時間 (ExposureTime) ---MVCC_FLOATVALUE stExposureTime = {0};nRet = MV_CC_GetFloatValue(handle, "ExposureTime", &stExposureTime);if (MV_OK == nRet){printf("曝光時間 - 當前值: %f\n", stExposureTime.fCurValue);printf("曝光時間 - 最大值: %f\n", stExposureTime.fMax);printf("曝光時間 - 最小值: %f\n\n", stExposureTime.fMin);}else{printf("獲取曝光時間失敗!錯誤碼 [%x]\n\n", nRet);}// --- 6.4 設置 float 型參數:曝光時間 ---float fExposureTime = 0.0f;printf("請輸入要設置的曝光時間: ");if(0 == scanf("%f", &fExposureTime)){printf("輸入格式錯誤!\n");break;}nRet = MV_CC_SetFloatValue(handle, "ExposureTime", fExposureTime);if (MV_OK == nRet){printf("設置曝光時間成功!\n\n");}else{printf("設置曝光時間失敗!錯誤碼 [%x]\n\n", nRet);}// --- 6.5 獲取 enum 型參數:觸發模式 (TriggerMode) ---MVCC_ENUMVALUE stTriggerMode = {0};nRet = MV_CC_GetEnumValue(handle, "TriggerMode", &stTriggerMode);if (MV_OK == nRet){printf("觸發模式 - 當前值: %d\n", stTriggerMode.nCurValue);printf("支持的觸發模式數量: %d\n", stTriggerMode.nSupportedNum);for (unsigned int i = 0; i < stTriggerMode.nSupportedNum; ++i){printf("支持的觸發模式 [%d]: %d\n", i, stTriggerMode.nSupportValue[i]);}printf("\n");}else{printf("獲取觸發模式失敗!錯誤碼 [%x]\n\n", nRet);}// --- 6.6 設置 enum 型參數:觸發模式 ---unsigned int nTriggerMode = 0;printf("請輸入要設置的觸發模式: ");if(0 == scanf("%d", &nTriggerMode)){printf("輸入格式錯誤!\n");break;}nRet = MV_CC_SetEnumValue(handle, "TriggerMode", nTriggerMode);if (MV_OK == nRet){printf("設置觸發模式成功!\n\n");}else{printf("設置觸發模式失敗!錯誤碼 [%x]\n\n", nRet);}// --- 6.7 獲取 bool 型參數:圖像X方向翻轉 (ReverseX) ---bool bGetBoolValue = false;nRet = MV_CC_GetBoolValue(handle, "ReverseX", &bGetBoolValue);if (MV_OK == nRet){printf("圖像X方向翻轉 - 當前值: %s\n\n", bGetBoolValue ? "開啟" : "關閉");}else{printf("獲取圖像X方向翻轉狀態失敗!錯誤碼 = [%x]\n\n", nRet);}// --- 6.8 設置 bool 型參數:圖像X方向翻轉 ---int nSetBoolValue;bool bSetBoolValue;printf("請輸入圖像X方向翻轉狀態 (0=關閉, 1=開啟): ");if(0 == scanf("%d", &nSetBoolValue)){printf("輸入格式錯誤!\n");break;}bSetBoolValue = (nSetBoolValue != 0); // 將整數轉換為 boolnRet = MV_CC_SetBoolValue(handle, "ReverseX", bSetBoolValue);if (MV_OK == nRet){printf("設置圖像X方向翻轉成功!\n\n");}else{printf("設置圖像X方向翻轉失敗!錯誤碼 = [%x]\n\n", nRet);}// --- 6.9 獲取 string 型參數:設備用戶ID (DeviceUserID) ---MVCC_STRINGVALUE stStringValue = {0};nRet = MV_CC_GetStringValue(handle, "DeviceUserID", &stStringValue);if (MV_OK == nRet){printf("當前設備用戶ID: [%s]\n\n", stStringValue.chCurValue);}else{printf("獲取設備用戶ID失敗!錯誤碼 = [%x]\n\n", nRet);}// --- 6.10 設置 string 型參數:設備用戶ID ---unsigned char strValue[256]; // 用于存儲用戶輸入的字符串printf("請輸入要設置的設備用戶ID (字符串): ");if(0 == scanf("%s", strValue)) // 注意:此處有緩沖區溢出風險,實際應用中應使用 scanf_s 或 fgets{printf("輸入格式錯誤!\n");break;}nRet = MV_CC_SetStringValue(handle, "DeviceUserID", (char*)strValue);if (MV_OK == nRet){printf("設置設備用戶ID成功!\n\n");}else{printf("設置設備用戶ID失敗!錯誤碼 = [%x]\n\n", nRet);}// ================== 步驟 7:關閉設備 ==================nRet = MV_CC_CloseDevice(handle);if (MV_OK != nRet){printf("關閉設備失敗!錯誤碼 [%x]\n", nRet);break;}printf("設備已關閉。\n");// ================== 步驟 8:銷毀句柄 ==================nRet = MV_CC_DestroyHandle(handle);if (MV_OK != nRet){printf("銷毀設備句柄失敗!錯誤碼 [%x]\n", nRet);break;}handle = NULL; // 避免懸空指針printf("設備句柄已銷毀。\n");} while (0); // do-while(0) 結束,用于錯誤處理跳轉// ================== 步驟 9:異常清理 ==================// 如果循環中出錯導致 handle 不為 NULL,則在此處進行清理if (handle != NULL){MV_CC_DestroyHandle(handle);handle = NULL;}// ================== 步驟 10:反初始化 SDK ==================// 釋放 SDK 占用的全局資源MV_CC_Finalize();printf("SDK反初始化完成。\n");printf("程序退出。\n");return 0; // 程序正常退出
}
makefile為:
Demo: SetParam.cppg++ -g -o SetParam SetParam.cpp -I../../../../../include -Wl,-rpath=$(MVCAM_COMMON_RUNENV)/64 -L$(MVCAM_COMMON_RUNENV)/64 -lMvCameraControlclean:rm SetParam -rf
SDK初始化成功。
共發現 2 臺設備:
[設備 0]:
設備型號名稱: MV-CE120-10GM
當前IP地址: 169.254.183.31
用戶自定義名稱: [設備 1]:
設備型號名稱: MV-CE120-10GM
當前IP地址: 169.254.183.31
用戶自定義名稱: 請輸入要操作的相機序號: 0
設備句柄創建成功。
設備打開成功。
圖像高度 - 當前值: 3036
圖像高度 - 最大值: 3036
圖像高度 - 最小值: 32
圖像高度 - 增量: 2請輸入要設置的圖像高度: 3036
設置圖像高度成功!曝光時間 - 當前值: 5000.000000
曝光時間 - 最大值: 1999733.000000
曝光時間 - 最小值: 34.000000請輸入要設置的曝光時間: 4000
設置曝光時間成功!觸發模式 - 當前值: 0
支持的觸發模式數量: 2
支持的觸發模式 [0]: 0
支持的觸發模式 [1]: 1請輸入要設置的觸發模式: 1
設置觸發模式成功!圖像X方向翻轉 - 當前值: 關閉請輸入圖像X方向翻轉狀態 (0=關閉, 1=開啟): 1
設置圖像X方向翻轉成功!當前設備用戶ID: []請輸入要設置的設備用戶ID (字符串): 111
設置設備用戶ID成功!設備已關閉。
設備句柄已銷毀。
SDK反初始化完成。
程序退出。
? 適用場景
本示例適用于以下場景:
工業相機二次開發入門學習
快速驗證相機通信與參數配置
搭建相機控制模塊的基礎框架
🔧 使用說明
安裝最新版 Hikrobot MVS SDK
將 MvCameraControl.h 和相關庫文件加入工程
編譯并運行程序
根據提示選擇設備并設置參數
📝 結語
通過簡潔明了的C語言代碼,我們實現了對海康相機的核心控制功能。程序結構清晰,便于擴展為圖像采集、多相機管理等功能模塊。對于剛接觸視覺開發的工程師來說,是一個不錯的起點。
代碼已將所有輸出信息本地化為中文,提升調試體驗,便于團隊協作與現場部署。
完整源碼已附在文中,可直接編譯使用。
歡迎交流與優化!