VS(C#)调用海康工业相机SDK采集图像及基本功能设定

时间:2024-10-05 12:15:36

VS(C#)调用海康工业相机SDK采集图像及基本功能设定

简介
由于工作关系,本人最近使用到了海康的网口及USB3.0接口的工业相机。现将相关内容进行整理记录。
开发环境
64位VS2013 +C#
Halcon12
海康MVS3.0.0

引用海康相机动态库()
在VS项目文件中添加添加引用,如下图
在这里插入图片描述
引用MVS安装目录下MVS\Development\DotNet\这个文件。
创建相机类
鼠标右键单击工程项目–添加–类,选择“类”,输入类的名称,例如Hikvision,点击右下角的“添加”。
在项目中使用海康相机时,为便于程序编写,可引入如下的命名空间:
using ;
创建需要用到的全局变量

public MyCamera myCamera;//相机对象
private MyCamera.MV_CC_DEVICE_INFO_LIST deviceList;//设备列表
private MyCamera.MV_CC_DEVICE_INFO deviceInfo;//设备对象
private string seriesStr;//接收相机序列号
private MyCamera.MVCC_INTVALUE stParam;//用于接收特定的参数
//为读取、保存图像创建的数组
UInt32 m_nBufSizeForDriver = 4096 * 3000;
byte[] m_pBufForDriver = new byte[4096 * 3000];
UInt32 m_nBufSizeForSaveImage = 4096 * 3000 * 3 + 3000;
byte[] m_pBufForSaveImage = new byte[4096 * 3000 * 3 + 3000];
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

创建相关函数
1.创建构造函数

//在构造函数中实例化设备列表对象
public Hikvision()
 {
     deviceList = new MyCamera.MV_CC_DEVICE_INFO_LIST();
 }
  • 1
  • 2
  • 3
  • 4
  • 5

2.创建改变相机IP的函数

//成功返回0失败返回-1
//调用函数时可以传入需要改变的目标IP,如过没有传入则将相机IP设置为其所连接的网卡地址+1或-1
public int changeIP(string IP = "")
{
   try
   {
         //获取相机相关信息,例如相机所连接网卡的网址
          IntPtr buffer = (, 0);
          MyCamera.MV_GIGE_DEVICE_INFO gigeInfo = (MyCamera.MV_GIGE_DEVICE_INFO)(buffer, typeof(MyCamera.MV_GIGE_DEVICE_INFO));
          IPAddress cameraIPAddress;
          string tempStr = "";
          if (().Equals("") || !((IP, out cameraIPAddress)))
          {
               //当前网卡的IP地址
               UInt32 nNetIp1 = ( & 0xFF000000) >> 24;
               UInt32 nNetIp2 = ( & 0x00FF0000) >> 16;
               UInt32 nNetIp3 = ( & 0x0000FF00) >> 8;
               UInt32 nNetIp4 = ( & 0x000000FF);
               //根据网卡IP设定相机IP,如果网卡ip第四位小于252,则相机ip第四位+1,否则相机IP第四位-1
              UInt32 cameraIp1 = nNetIp1;
              UInt32 cameraIp2 = nNetIp2;
              UInt32 cameraIp3 = nNetIp3;
              UInt32 cameraIp4 = nNetIp4;
              if (nNetIp4 < 252)
              {
                    cameraIp4++;
              }
              else
              {
                     cameraIp4--;
              }
              tempStr = cameraIp1 + "." + cameraIp2 + "." + cameraIp3 + "." + cameraIp4;
          }
          else
          {
                tempStr = IP;
          }
          (tempStr, out cameraIPAddress);
          long cameraIP = ();
          //设置相机掩码
          uint maskIp1 = ( & 0xFF000000) >> 24;
          uint maskIp2 = ( & 0x00FF0000) >> 16;
          uint maskIp3 = ( & 0x0000FF00) >> 8;
          uint maskIp4 = ( & 0x000000FF);
          IPAddress subMaskAddress;
          tempStr = maskIp1 + "." + maskIp2 + "." + maskIp3 + "." + maskIp4;
          (tempStr, out subMaskAddress);
          long maskIP = ();
          //设置网关
          uint gateIp1 = ( & 0xFF000000) >> 24;
          uint gateIp2 = ( & 0x00FF0000) >> 16;
          uint gateIp3 = ( & 0x0000FF00) >> 8;
          uint gateIp4 = ( & 0x000000FF);
          IPAddress gateAddress;
          tempStr = gateIp1 + "." + gateIp2 + "." + gateIp3 + "." + gateIp4;
          (tempStr, out gateAddress);
          long gateIP = ();

          int temp = myCamera.MV_GIGE_ForceIpEx_NET((UInt32)(cameraIP >> 32), (UInt32)(maskIP >> 32), (UInt32)(gateIP >> 32));//执行更改相机IP的命令
          if (temp == 0)
                //强制IP成功
                return 0;
          //强制IP失败
          return -1;
     }
     catch
     {
          return -1;
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70

3.创建相机连接函数

public int connectCamera(string id)//连接相机,返回-1为失败,0为成功
{
     = id;
    string m_SerialNumber = "";//接收设备返回的序列号
    int temp;//接收命令执行结果
    myCamera = new MyCamera();
    try
    {
        temp = MyCamera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE | MyCamera.MV_USB_DEVICE, ref deviceList);//更新设备列表
        if (temp != 0)
        {
            //设备更新成功接收命令的返回值为0,返回值不为0则为异常
            return -1;
        }

        //强制相机IP
        for (int i = 0; i < ; i++)
        {
        
        /*******该部分用于获取相机名称、序列号等,从而对指定的相机进行IP更改******/
           //更改IP的函数中也有该部分,重叠部分程序可进行相应的简化,本文暂不做处理
        
            deviceInfo = (MyCamera.MV_CC_DEVICE_INFO)([i], typeof(MyCamera.MV_CC_DEVICE_INFO));//获取设备信息
            IntPtr buffer = (, 0);
            MyCamera.MV_GIGE_DEVICE_INFO gigeInfo = (MyCamera.MV_GIGE_DEVICE_INFO)(buffer, typeof(MyCamera.MV_GIGE_DEVICE_INFO));
            
        /*****************************************************************/
        
             m_SerialNumber = ;
             if( == MyCamera.MV_GIGE_DEVICE)
             {
               //判断是否为网口相机
                if ((m_SerialNumber))
                {
                   //如果相机用户名正确则修改IP
                   temp = myCamera.MV_CC_CreateDevice_NET(ref deviceInfo);//更改IP前需要创建设备对象
                   forceIP();
                }
             }
         }
       //更改IP后需要重新刷新设备列表,否则打开相机时会报错
       temp = MyCamera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE | MyCamera.MV_USB_DEVICE, ref deviceList);//更新设备列表
       for (int i = 0; i < ; i++)
       {
            deviceInfo = (MyCamera.MV_CC_DEVICE_INFO)([i], typeof(MyCamera.MV_CC_DEVICE_INFO));//获取设备
            if ( == MyCamera.MV_GIGE_DEVICE)
            {
                 IntPtr buffer = (, 0);
                  MyCamera.MV_GIGE_DEVICE_INFO gigeInfo = (MyCamera.MV_GIGE_DEVICE_INFO)(buffer, typeof(MyCamera.MV_GIGE_DEVICE_INFO));
                  //m_SerialNumber = ;//获取序列号
                  m_SerialNumber = ;//获取用户名
           }
           else if ( == MyCamera.MV_USB_DEVICE)
           {
                  IntPtr buffer = (.stUsb3VInfo, 0);
                  MyCamera.MV_USB3_DEVICE_INFO usbInfo = (MyCamera.MV_USB3_DEVICE_INFO)(buffer, typeof(MyCamera.MV_USB3_DEVICE_INFO));
                  m_SerialNumber = ;
          }
          if ((m_SerialNumber))
          {
               temp = myCamera.MV_CC_CreateDevice_NET(ref deviceInfo);
               if (MyCamera.MV_OK != temp)
               {
                    //创建相机失败
                    return -1;
               }
               temp = myCamera.MV_CC_OpenDevice_NET();//
               if (MyCamera.MV_OK != temp)
               {
                    //打开相机失败
                    return -1;
                }
                return 0;
         }
         continue;
       }
   }
   catch
   {
        return -1;
   }
   return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83

4.创建开始采集、停止采集、关闭相机函数

 public int startCamera()//相机开始采集,返回0为成功,-1为失败
 {
     int temp = myCamera.MV_CC_StartGrabbing_NET();
     if (MyCamera.MV_OK != temp)
          return -1;
     return 0;
}

public int stopCamera()//停止相机采集,返回0为成功,-1为失败
{
     int temp = myCamera.MV_CC_StopGrabbing_NET();
     if (MyCamera.MV_OK != temp )
           return -1;
     return 0;
}

 public int closeCamera()//关闭相机,返回0为成功,-1为失败
 {
      int temp = stopCamera();//停止相机采集
       if (MyCamera.MV_OK != temp )
           return -1;
      temp = myCamera.MV_CC_CloseDevice_NET();
       if (MyCamera.MV_OK != temp )
           return -1;
      temp = myCamera.MV_CC_DestroyDevice_NET();
       if (MyCamera.MV_OK != temp )
           return -1;
       return 0;
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

5.创建发送软触发函数

//发送成功返回0,失败返回-1
public int softTrigger()
{
     int temp = myCamera.MV_CC_SetCommandValue_NET("TriggerSoftware");
     if (MyCamera.MV_OK != temp )
           return -1;
      return 0;
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

6.创建读取图像函数
函数返回Halcon图像库可以处理的Himage格式。
如何添加halcon图像库请自行百度,网上教程非常多。

//读取成功返回Himage图像,失败返回NULL
public HImage readImage()
{
    UInt32 nPayloadSize = 0;
    int temp = myCamera.MV_CC_GetIntValue_NET("PayloadSize", ref stParam);
    if (MyCamera.MV_OK != temp)
    {
        return null;
    }
    nPayloadSize = ;
    if (nPayloadSize > m_nBufSizeForDriver)
    {
        m_nBufSizeForDriver = nPayloadSize;
        m_pBufForDriver = new byte[m_nBufSizeForDriver];
        m_nBufSizeForSaveImage = m_nBufSizeForDriver * 3 + 2048;
        m_pBufForSaveImage = new byte[m_nBufSizeForSaveImage];
     }
     IntPtr pData = (m_pBufForDriver, 0);
     MyCamera.MV_FRAME_OUT_INFO_EX stFrameInfo = new MyCamera.MV_FRAME_OUT_INFO_EX();
     temp = myCamera.MV_CC_GetOneFrameTimeout_NET(pData, m_nBufSizeForDriver, ref stFrameInfo, 1000);//获取一帧图像,超时时间设置为1000
     if (MyCamera.MV_OK != temp)
     {
         return null;
     }
     HImage image = new HImage();
     if (IsMonoData())//判断是否为黑白图像
     {
          //如果是黑白图像,则利用Halcon图像库中的GenImage1算子来构建图像
          image .GenImage1("byte", (int), (int), pData);
     }
     else
     {
          if ( == .PixelType_Gvsp_RGB8_Packed)
          {
              //如果彩色图像是RGB8格式,则可以直接利用GenImageInterleaved算子来构建图像
              image .GenImageInterleaved(pData, "rgb", (int), (int), 0, "byte", (int), (int), 0, 0, -1, 0);
          }
          else
          {
               //如果彩色图像不是RGB8格式,则需要将图像格式转换为RGB8。
               IntPtr pBufForSaveImage = ;
               if (pBufForSaveImage == )
               {
                   pBufForSaveImage = ((int)( *  * 3 + 2048));
               }
               MyCamera.MV_PIXEL_CONVERT_PARAM stConverPixelParam = new MyCamera.MV_PIXEL_CONVERT_PARAM();
                = ;
                = ;
                = pData;
                = ;
                = ;
                = .PixelType_Gvsp_RGB8_Packed;//在此处选择需要转换的目标类型
                = pBufForSaveImage;
                = (uint)( *  * 3 + 2048);
               myCamera.MV_CC_ConvertPixelType_NET(ref stConverPixelParam);
               image .GenImageInterleaved(pBufForSaveImage, "rgb", (int), (int), 0, "byte", (int), (int), 0, 0, -1, 0);
               //释放指针
               (pBufForSaveImage);
             }
        }
        return image ;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62

7.其他功能设置

//1.设置Int型参数
public int setWidth(uint width)//设置图像宽度,成功返回0失败返回-1
{
    int temp= myCamera.MV_CC_SetIntValue_NET("Width", width);
    if (MyCamera.MV_OK != temp)
        return 0;
    return -1;
}
//2.设置枚举型参数
public int setTriggerMode(uint TriggerMode)//设置触发事件,成功返回0失败返回-1
{
    //1:On 触发模式
    //0:Off 非触发模式
    int returnValue = myCamera.MV_CC_SetEnumValue_NET("TriggerMode", TriggerMode);
    if (MyCamera.MV_OK != temp)
        return 0;
    return -1;
}
//3.设置浮点型型参数
public int setExposureTime(uint ExposureTime)//设置曝光时间(us),成功返回0失败返回-1
{
    int returnValue = myCamera.MV_CC_SetFloatValue_NET("ExposureTime", ExposureTimeNum);
    if (MyCamera.MV_OK != temp)
        return 0;
    return -1;
}
//4.判断是否为黑白图像
private Boolean IsMonoData( enGvspPixelType)
{
    switch (enGvspPixelType)
    {
        case .PixelType_Gvsp_Mono8:
        case .PixelType_Gvsp_Mono10:
        case .PixelType_Gvsp_Mono10_Packed:
        case .PixelType_Gvsp_Mono12:
        case .PixelType_Gvsp_Mono12_Packed:
            return true;
        default:
            return false;
    }
}
//5.设置心跳时间,成功返回0失败返回-1
public int setHeartBeatTime(uint heartBeatTime)
{
   //心跳时间最小为500
    uint tempTime = heartBeatTime > 500 ? heartBeatTime : 500;
    int temp = m_pCSI.MV_CC_SetIntValue_NET("GevHeartbeatTimeout", tempTime);
    if (MyCamera.MV_OK != temp)
       return 0;
    return -1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

在海康MVS安装目录下MVS\Development\Documentations\是一个关于参数设置的文档,可以参考MVS并结合该文档进行相应参数的设置,非常方便。
8.实例化相机对象,并通过软触发采集图像

 Hikvision camera = new Hikvision();//创建相机对象并实例化
 ("123456");//连接相机,传入相机序列号123456
 ();//开启相机采集
 (10000);//设置曝光时间为10ms
 ();//发送软触发采集图像
 Himage image=();//获取采集到且转换后的图像
 ();//停止相机采集
 ();//关闭相机
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

注意:软触发采集图像需要将相机设置为触发模式,并设置触发源为soft。
9.补充
相机在使用、调试过程中,当与相机成功连接后,如果在程序异常退出前相机没有进行相应关闭操作,则可能会导致短时间内相机无法连接,利用MVS进行连接时会出现下面如下提示:
在这里插入图片描述
这是由于心跳时间导致,海康相机默认的心跳时间为60s(Basler相机好像是5分钟),所以在异常退出后的60s内无法再次重新连接,在MVS中,可以找到心跳时间的相关设置,如下图,但是在设置成功后,依旧出现了程序异常退出相机短时间内连接不上的情况。向海康技术咨询了一下,答复是利用SDK连接相机后,默认为调试模式, 此时心跳时间恢复默认值。因此,建议在调试过程中,利用前文给出的函数将心跳时间设置为500ms,这是海康相机可以设置的最小心跳时间。
在这里插入图片描述
水平有限,难免有错误和不足之处,恳请批评指正。