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

发布于:2025-09-06 ⋅ 阅读:(17) ⋅ 点赞:(0)

在机器视觉项目开发中,相机的初始化、参数读取与设置是最基础也是最关键的环节。本文基于海康机器人(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); // 将整数转换为 bool
        nRet = 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.cpp
	g++ -g -o SetParam SetParam.cpp -I../../../../../include -Wl,-rpath=$(MVCAM_COMMON_RUNENV)/64 -L$(MVCAM_COMMON_RUNENV)/64 -lMvCameraControl
	

clean:
	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语言代码,我们实现了对海康相机的核心控制功能。程序结构清晰,便于扩展为图像采集、多相机管理等功能模块。对于刚接触视觉开发的工程师来说,是一个不错的起点。

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

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

欢迎交流与优化!


网站公告

今日签到

点亮在社区的每一天
去签到