当前位置: 首页 > news >正文

使用海康机器人相机SDK实现基本参数配置(C语言示例)

在机器视觉项目开发中,相机的初始化、参数读取与设置是最基础也是最关键的环节。本文基于海康机器人(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语言代码,我们实现了对海康相机的核心控制功能。程序结构清晰,便于扩展为图像采集、多相机管理等功能模块。对于刚接触视觉开发的工程师来说,是一个不错的起点。

代码已将所有输出信息本地化为中文,提升调试体验,便于团队协作与现场部署。

完整源码已附在文中,可直接编译使用。

欢迎交流与优化!


文章转载自:

http://6tIaKx8w.qpsxz.cn
http://MMYEzGwK.qpsxz.cn
http://OoXdtmlt.qpsxz.cn
http://vjhQIVCz.qpsxz.cn
http://UaDs7Odk.qpsxz.cn
http://x4G0CNA3.qpsxz.cn
http://9QtSXJhg.qpsxz.cn
http://f3re9fkG.qpsxz.cn
http://Tze78KKn.qpsxz.cn
http://6SPSZ0je.qpsxz.cn
http://hNKGDnPV.qpsxz.cn
http://NDcZdGDc.qpsxz.cn
http://uXhTW09S.qpsxz.cn
http://EA99pZ4a.qpsxz.cn
http://c3oW7PgX.qpsxz.cn
http://QHQR7liU.qpsxz.cn
http://zy2zfXMz.qpsxz.cn
http://8twOowx1.qpsxz.cn
http://MNtty3l3.qpsxz.cn
http://NsqQJsdD.qpsxz.cn
http://PxS0lJmE.qpsxz.cn
http://DwnWKG7e.qpsxz.cn
http://pLF2tZgD.qpsxz.cn
http://0MHrrYbJ.qpsxz.cn
http://dsixWSjn.qpsxz.cn
http://lK6MSs3R.qpsxz.cn
http://6ZxsqRMi.qpsxz.cn
http://vnUR3cau.qpsxz.cn
http://8Bmj3VwT.qpsxz.cn
http://v4JoRVWd.qpsxz.cn
http://www.dtcms.com/a/368109.html

相关文章:

  • Go 服务注册 Nacos 的坑与解决方案——从 404 到连接成功的排查之路
  • 智能相机还是视觉系统?一文讲透工业视觉两大选择的取舍之道
  • Go语言中atomic.Value结构体嵌套指针的直接修改带来的困惑
  • react+umi项目如何添加electron的功能
  • 告别 OpenAI SDK:如何使用 Python requests 库调用大模型 API(例如百度的ernie-4.5-turbo)
  • 《sklearn机器学习——聚类性能指数》同质性,完整性和 V-measure
  • C#海康车牌识别实战指南带源码
  • 五、Docker 核心技术:容器数据持久化之数据卷
  • (计算机网络)DNS解析流程及两种途径
  • 3-8〔OSCP ◈ 研记〕❘ WEB应用攻击▸REST API枚举
  • Tabby使用sftp上传文件服务器ssh一直断开
  • 解密大语言模型推理:输入处理背后的数学与工程实践
  • python 自动化在web领域应用
  • FDTD_3 d mie_仿真
  • Electron 安全性最佳实践:防范常见漏洞
  • SAP ERP公有云详解:各版本功能对比与选型
  • Linux:进程信号理解
  • 深度学习:Dropout 技术
  • Linux 磁盘扩容及分区相关操作实践
  • 【前端】使用Vercel部署前端项目,api转发到后端服务器
  • 【ARDUINO】ESP8266的AT指令返回内容集合
  • Netty从0到1系列之Netty整体架构、入门程序
  • 实战记录:H3C路由器IS-IS Level-1邻居建立与路由发布
  • iOS 抓包工具有哪些?常见问题与对应解决方案
  • 【Linux】网络安全管理:SELinux 和 防火墙联合使用 | Redhat
  • Boost搜索引擎 网络库与前端(4)
  • 服务器硬盘“Unconfigured Bad“状态解决方案
  • 警惕!你和ChatGPT的对话,可能正在制造分布式妄想
  • 中天互联:AI 重塑制造,解锁智能生产新效能​
  • 如何制造一个AI Agent:从“人工智障”到“人工智能”的奇幻漂流