从零打造 C# 工业视觉检测系统(四):海康威视 MVS SDK 入门与相机枚举实战

从零打造 C# 工业视觉检测系统(四):海康威视 MVS SDK 入门与相机枚举实战

系列标签C# 海康威视 MVS SDK 工业相机 机器视觉

本文目标:掌握工业相机选型要点,学会使用海康 MVS SDK 枚举和发现设备


一、前言

工业相机是视觉检测系统的"眼睛"。与手机摄像头不同,工业相机需要:

  • 高稳定性:7x24 小时连续工作
  • 低延迟:从触发到出图 < 100ms
  • 可编程控制:曝光、增益、白平衡等参数由软件控制
  • 标准接口:GigE(千兆网)、USB3.0、CameraLink

本文将带你从相机选型开始,一直到用 C# 代码枚举出局域网中的所有相机。


二、工业相机选型指南

2.1 关键参数解读

参数 说明 选型建议
分辨率 像素数量,如 1920x1200 根据检测精度要求计算:精度 = 视野 / 分辨率
帧率 (FPS) 每秒采集帧数 产线速度越快,帧率要求越高
传感器类型 CCD / CMOS CMOS 已成为主流,性价比高
接口类型 GigE / USB3.0 / CamLink GigE 传输距离远(100m),USB3.0 即插即用
触发模式 软触发 / 硬触发 产线联动通常使用硬触发(外接传感器)

2.2 海康威视 MVS 生态

海康机器人(Hikrobot)是国内工业视觉领域的龙头企业,其 MVS(Machine Vision Software) 提供:

  • MVS 客户端(类似相机厂商的"取景器")
  • SDK 开发包(C/C++/C#/Python)
  • 丰富的示例代码和文档

三、MVS SDK 环境配置

3.1 安装步骤

  1. 从海康机器人官网下载 MVS 标准开发包
  2. 安装时勾选"安装驱动"和".NET 开发包"
  3. 安装完成后,在 C:\Program Files (x86)\MVS\Development\DotNet\win64\ 目录下找到 MvCamCtrl.Net.dll

3.2 项目引用

FormUI.csproj 中引用:

xml 复制代码
<Reference Include="MvCamCtrl.Net">
  <HintPath>..\..\..\MVS\Development\DotNet\win64\MvCamCtrl.Net.dll</HintPath>
</Reference>

注意 :路径需根据实际安装位置调整。如果团队开发,建议将 DLL 复制到项目 libs 目录下统一引用。

3.3 命名空间

csharp 复制代码
using MvCamCtrl.NET;
using MvCamCtrl.NET.CameraParams;

四、核心数据结构

4.1 MV_CC_DEVICE_INFO_LIST

设备列表结构体,用于存储枚举到的所有相机:

csharp 复制代码
// SDK 中的定义(简化示意)
public struct MV_CC_DEVICE_INFO_LIST
{
    public uint nDeviceNum;           // 设备数量
    public IntPtr[] pDeviceInfo;      // 设备信息指针数组
}

4.2 MV_CC_DEVICE_INFO

单个设备的详细信息,包含设备型号、序列号、IP 地址等:

csharp 复制代码
public struct MV_CC_DEVICE_INFO
{
    public MV_GIGE_DEVICE_INFO SpecialInfo;  // GigE 设备特有信息
    // ... 其他字段
}

五、相机枚举实战

5.1 P/Invoke 声明

由于 SDK 底层是 C++ 实现,C# 需要通过 DllImport 调用:

csharp 复制代码
public static class DllMethod
{
    private const string CameraDll = @".\Algorithm.dll";

    [DllImport(CameraDll, CallingConvention = CallingConvention.Cdecl)]
    public static extern int EnumCameraDevices(IntPtr p);

    [DllImport(CameraDll, CallingConvention = CallingConvention.Cdecl)]
    public static extern int InitializeCanmera();

    [DllImport(CameraDll, CallingConvention = CallingConvention.Cdecl)]
    public static extern int ConnectCamera(int selectIndex, int selectCameraIndex, 
        ref int CameraId, ref int ImgWidth, ref int ImgHeight);

    [DllImport(CameraDll, CallingConvention = CallingConvention.Cdecl)]
    public static extern int DisconnectCamera(int CameraId);
}

注意Algorithm.dll 是本项目的算法封装 DLL,内部调用了海康 SDK。实际开发中,你也可以直接调用 MvCamCtrl.Net 提供的托管方法。

5.2 枚举设备的核心代码

csharp 复制代码
public static int EnumCamera()
{
    // 分配非托管内存,用于接收设备列表
    IntPtr pt = Marshal.AllocHGlobal(
        Marshal.SizeOf(typeof(MV_CC_DEVICE_INFO_LIST)));
    
    // 调用 SDK 枚举设备
    int ret = EnumCameraDevices(pt);
    if (ret != 0)
    {
        Marshal.FreeHGlobal(pt);
        return ret;  // 返回错误码
    }
    
    // 将非托管内存转换为托管结构体
    CameraData._DeviceList = (MV_CC_DEVICE_INFO_LIST)Marshal.PtrToStructure(
        pt, typeof(MV_CC_DEVICE_INFO_LIST));
    
    // 遍历每个设备,提取详细信息
    for (int i = 0; i < CameraData._DeviceList.nDeviceNum; i++)
    {               
        CameraData._DeviceInfoList[i] = (MV_CC_DEVICE_INFO)Marshal.PtrToStructure(
            CameraData._DeviceList.pDeviceInfo[i], typeof(MV_CC_DEVICE_INFO));
    }
    
    // 释放非托管内存!重要!
    Marshal.FreeHGlobal(pt);
    return ret;
}

关键点

  • Marshal.AllocHGlobal / Marshal.FreeHGlobal 必须成对出现,否则内存泄漏
  • PtrToStructure 将 C++ 结构体指针转换为 C# 结构体
  • 错误码 ret 需要查 SDK 文档,0 通常表示成功

5.3 SelectCamera 弹窗实现

枚举到设备后,通过弹窗让用户选择要连接的相机:

csharp 复制代码
public partial class SelectCamera : Sunny.UI.UIForm
{
    public int selectCameraIndex = -1;

    private void SelectCamera_Load(object sender, EventArgs e)
    {
        selectCameraIndex = -1;
        
        // 枚举设备
        DllMethod.EnumCamera();
        
        for (int i = 0; i < CameraData._DeviceList.nDeviceNum; i++)
        {             
            // 提取型号名称(GB2312 编码)
            string modelTop = Encoding.GetEncoding("GB2312")
                .GetString(CameraData._DeviceInfoList[i].SpecialInfo.stGigEInfo, 52, 20)
                .TrimEnd('\0');
            
            string modelBottom = Encoding.GetEncoding("GB2312")
                .GetString(CameraData._DeviceInfoList[i].SpecialInfo.stGigEInfo, 164, 20)
                .TrimEnd('\0');
            
            string cameraItem = modelTop + "(" + modelBottom + ")";
            this.DeviceListBox.Items.Add(
                string.IsNullOrEmpty(cameraItem) ? "Camera" + i : cameraItem);
        }
        
        // 已连接的相机置灰禁用
        for (int i = 0; i < CameraData.MAX_CAMERA_NUM; i++)
        {
            if (CameraData.CameraIndex[i] != -1)
            {
                AddNonSelectableIndex(CameraData.CameraIndex[i]);
            }
        }
    }
}

细节说明

  • 海康 SDK 返回的字符串是 GB2312 编码 ,必须用 Encoding.GetEncoding("GB2312") 解码,否则中文乱码
  • TrimEnd('\0') 去除 C 风格字符串的结束符
  • 通过 AddNonSelectableIndex 将已连接的相机设为不可选,避免重复连接

5.4 已连接设备禁用的实现

csharp 复制代码
private HashSet<int> _nonSelectableIndices = new HashSet<int>();

private void ListBox1_DrawItem(object sender, DrawItemEventArgs e)
{
    e.DrawBackground();
    if (e.Index < 0) return;

    bool isNonSelectable = _nonSelectableIndices.Contains(e.Index);
    string itemText = DeviceListBox.Items[e.Index].ToString();

    // 已连接的设备显示灰色
    Color textColor = isNonSelectable ? Color.Gray : e.ForeColor;

    using (Brush brush = new SolidBrush(textColor))
    {
        e.Graphics.DrawString(itemText, e.Font, brush, e.Bounds);
    }

    e.DrawFocusRectangle();
}

六、常见问题与排查

Q1:EnumCameraDevices 返回非 0 错误码?

  • 检查 MVS 客户端能否识别相机
  • 检查防火墙是否阻挡了 GigE 发现端口(默认 3956)
  • 确认相机 IP 与电脑在同一网段

Q2:中文相机名称乱码?

必须使用 Encoding.GetEncoding("GB2312"),UTF-8 无法正确解码。

Q3:已断开连接的相机仍显示灰色?

需要在断开连接时调用 RemoveNonSelectableIndex,并刷新 ListBox。


七、总结

本文从工业相机选型开始,讲解了:

  1. 关键参数:分辨率、帧率、接口类型的选型方法
  2. 环境配置:MVS SDK 安装与 DLL 引用
  3. 枚举设备Marshal 非托管内存操作、PtrToStructure 转换
  4. UI 交互:弹窗选择、已连接设备禁用

下篇预告:《从零打造 C# 工业视觉检测系统(五):相机连接、连续取流与双路实时预览》

我们将实现相机的连接/断开、连续取流,以及将 IntPtr 图像数据显示到 PictureBox 中。


欢迎点赞、收藏、关注,你的支持是我持续输出的动力!

相关推荐
m0_749492224 小时前
2026平价运动相机选择指南:科美锐(Komery)PX3与另外两款相机的功能取舍拆解
数码相机
沐梯子4 小时前
AI视频工具大战升级!PixPix首发接入MiniMaxH3大战Seedance
数码相机
c#上位机4 小时前
线扫相机的帧触发
数码相机
深视智能科技6 小时前
PIV高速成像系统如何同步?相机、激光与数据传输配置指南
数码相机
czhc11400756636 小时前
8.4:今日概念与语法总结
c#
大数据张老师6 小时前
Typora 导出 Word 模版操作手册
开发语言·c#·word·typora
我是苏苏7 小时前
C#基础:使用System.Speech.Synthesis离线播放/朗读文字内容
开发语言·c#
程序员-Benothing9 小时前
如何实现高并发系统订单30分钟自动关闭?
开发语言·c#·wpf
海盗123421 小时前
微软技术周报 ——2026-08-03
后端·python·microsoft·c#·.netcore