海康威视MVS客户端及虚拟相机c++开发案例

1、基本介绍

1.1 海康威视MVS客户端

机器视觉工业相机客户端MVS是为支持海康机器视觉相机产品而开发的软件应用程序,适用于所有海康机器视觉面阵以及线阵相机产品。 MVS包含了客户端,IP配置工具,固件升级工具,导入/导出属性工具、日志查看工具、网卡配置工具,驱动管理工具,系统信息工具,诊断工具,带宽管理工具,SDK和Demo。

操作系统:Windows 7/10/11 32/64bit
功能特性

1、网口和USB相机可自动搜寻同子网下连接的所有设备,CameraLink相机可手动搜寻所连接设备
2、支持查看和修改相机设备参数、搜索指定参数
3、支持同时连接、采集、预览多个相机
4、支持保存个人喜好参数配置以及整套设备参数方案
5、支持实时预览、图片截取、录像存储
6、网口相机支持修改IP配置方式、IP地址、子码掩码、默认网关
7、支持在线设备升级
8、支持GigE Vision动作指令

更新说明
【MVS V4.3.0】
1.【新增】工具集中新增ISP工具
2.【新增】属性导入导出工具支持采集卡
3.【新增】事件配置工具支持文件导入导出
4.【优化】固件升级工具:优化采集卡设备的固件升级操作。

【工业相机SDK V4.2.1】
1.【新增】支持GE1104采集卡

【工业采集卡SDK V2.3.0】
1.【新增】支持GE1104采集卡
详细更新说明请见MVS安装路径下的ReleaseNote.txt文件

1.2 海康威视虚拟相机

海康威视虚拟相机是对应工业相机实物而言,它是软件模拟出来的相机,本质上是运行在 pc上的一段程序。使用工业相机 SDK 开发需连接工业相机。而搭建真实的相机物理环境,有时候颇费周章。为了解决有时不方便搭建真实环境的问题,使用虚拟相机小工具进行模拟开发。工业相机 SDK 对虚拟相机和工业相机实物的访问完全一致,这样用户在开发阶段就可以使用虚拟相机来代替工业相机实物进行开发调试。

2、安装使用

2.1 海康威视MVS客户端

官网地址:https://www.hikrobotics.com/cn/machinevision/service/download?module=0
打开以上网站,即可见到如下界面
在这里插入图片描述
点击下载后输入需要的信息后,点确定即可进行下载
在这里插入图片描述
将下载的文件解压后得到可执行文件,双击后进入安装流程
在这里插入图片描述
没有特殊使用需求,安装软件默认配置项进行安装即可在这里插入图片描述
安装完成后可以进入以下程序界面
在这里插入图片描述

2.2 海康威视虚拟相机

下载地址:https://download.csdn.net/download/m0_74259636/88597229
该软件来自于对互联网资源的搜集,下载资源后解压双击即可完成安装。
在这里插入图片描述

目前支持相机型号为:MV-CA013-20GM/GC、MV-CA050-10GM/GC、MVCA060-11GM、MV-CA060-10GC、MV-CE200-10GM/GC、MV-CA003-
21UM/UC、MV-CH120-10UM/UC。
仿真模式开启后,MVS 客户端或 SDK 只枚举虚拟相机,不能枚举实际
连接的工业相机。

添加完毕后,通过 MVS 端即可看到添加的相机,也可像操作工业相机实
物一样,连接、预览图像,对相机参数进行设置,如下图所示。
MV-CA013-20GM、MV-CA050-10GM、MV-CA060-11GM 型号虚拟相机的
预览画面默认为固定路径下图片的循环显示;其余新增型号虚拟相机的
预览画面默认为模拟图,可在固定路径下放置符合要求的图片进行循环
显示。
图片存放的固定路径为:C:\Windows\Temp\VirtualCamera\Cameras,黑
白图片放到 Mono8 文件夹下,彩色图片放到 RGB24 文件夹下。
替换的图片须分辨率与虚拟相机型号的分辨率一致,且为 bmp 格式图
片。

2.3 虚拟相机与MVS客户端的基本使用

点击桌面上的VirtualCamTool图标,即可进入虚拟相机操作界面。点击选项卡可以选择相机型号,点击“添加虚拟相机”即可完成添加。若是提示sdk被占用,则请先退出MVS程序。
在这里插入图片描述
重新进入MVS客户端后,即可找到虚拟相机。
在这里插入图片描述
预览画面默认为固定路径下图片的循环显示;其余新增型号虚拟相机的
预览画面默认为模拟图,可在固定路径下放置符合要求的图片进行循环
显示。
在这里插入图片描述

图片存放的固定路径为:C:\Windows\Temp\VirtualCamera\Cameras\相机ID,黑
白图片放到 Mono8 文件夹下,彩色图片放到 RGB24 文件夹下。
替换的图片须分辨率与虚拟相机型号的分辨率一致,且为 bmp 格式图
片。

3、使用案例

在C:\Program Files (x86)\MVS\Development\Samples目录下有以下开发demo程序,其中关于c++程序默认提供的是vs2015的sln文件,可以用vs2019打开。为了简便开发,我们推荐学习使用OpenCV demo。
在这里插入图片描述

3.1 opencv Demo配置

进入以下目录在这里插入图片描述
双击Samples_VS2015.sln可以用vs2019打开解决方案,此时发现opencv相关的inclde都在报错,故此,需要配置opencv。
在这里插入图片描述
opencv的配置可以参考opencv 一 基本运行环境配置(下载安装、编写代码、配置环境),其主要是配置include目录、lib目录和附加依赖,以及将bin目录添加系统环境变量 path中。其中需要注意release|x64的设置。
在这里插入图片描述
在这里插入图片描述

3.2 demo运行效果

demo程序运行效果如下所示,它首先列出了所有的海康威视摄像头id(下图中的device0),然后输入相机id和格式编码即可完成程序运行。
在这里插入图片描述

3.3 关键代码提取

MVS提供的demo程序较为繁琐,为此对其进行整理。整理后的使用代码如下所示:

    MVS_camera_client camera;
    camera.init_camera();
    cv::Mat img = camera.take_photos();
    camera.destory();

完整代码如下所示:

/***************************************************************************************************
*
* Notes about how to configure your OpenCV environment and project.
* 1. You can prepare the required installation package from the official website. https://opencv.org/releases.html
* 2. If the *.lib files doesn't exist in the package download, you need to compile by yourself with the CMake tool.
* 3. Add the 'bin' folder path to the PATH.
* 4. Configure the 'Additional Include Directories', 'Additional Library Directories' and 'Additional Dependencies' for current project property.
*
* If there is any question or request, please feel free to contact us.

***************************************************************************************************/

#include <stdio.h>
#include <string.h>
#include "opencv2/core/core_c.h"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "MvCameraControl.h"

enum CONVERT_TYPE
{
    
    
    OpenCV_Mat = 0,    // ch:Mat图像格式 | en:Mat format
    OpenCV_IplImage = 1,    // ch:IplImage图像格式 | en:IplImage format
};

// ch:显示枚举到的设备信息 | en:Print the discovered devices' information
void PrintDeviceInfo(MV_CC_DEVICE_INFO* pstMVDevInfo)
{
    
    
    if (NULL == pstMVDevInfo)
    {
    
    
        printf("    NULL info.\n\n");
        return;
    }

    // 获取图像数据帧仅支持GigE和U3V设备
    if (MV_GIGE_DEVICE == pstMVDevInfo->nTLayerType)
    {
    
    
        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);

        // ch:显示IP和设备名 | en:Print current ip and user defined name
        printf("    IP: %d.%d.%d.%d\n", nIp1, nIp2, nIp3, nIp4);
        printf("    UserDefinedName: %s\n", pstMVDevInfo->SpecialInfo.stGigEInfo.chUserDefinedName);
        printf("    Device Model Name: %s\n\n", pstMVDevInfo->SpecialInfo.stGigEInfo.chModelName);
    }
    else if (MV_USB_DEVICE == pstMVDevInfo->nTLayerType)
    {
    
    
        printf("    UserDefinedName: %s\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chUserDefinedName);
        printf("    Device Model Name: %s\n\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chModelName);
    }
    else
    {
    
    
        printf("    Not support.\n\n");
    }
}

// ch:帧数据转换为Mat格式图片并保存 | en:Convert data stream to Mat format then save image
bool Convert2Mat(cv::Mat& srcImage, MV_FRAME_OUT_INFO_EX* pstImageInfo, unsigned char* pData)
{
    
    
    if (NULL == pstImageInfo || NULL == pData)
    {
    
    
        printf("NULL info or data.\n");
        return false;
    }

    ;

    if (PixelType_Gvsp_Mono8 == pstImageInfo->enPixelType)                // Mono8类型
    {
    
    
        srcImage = cv::Mat(pstImageInfo->nHeight, pstImageInfo->nWidth, CV_8UC1, pData);
    }
    else if (PixelType_Gvsp_RGB8_Packed == pstImageInfo->enPixelType)     // RGB8类型
    {
    
    
        // Mat像素排列格式为BGR,需要转换
        //RGB2BGR(pData, pstImageInfo->nWidth, pstImageInfo->nHeight);
        srcImage = cv::Mat(pstImageInfo->nHeight, pstImageInfo->nWidth, CV_8UC3, pData);
        cv::cvtColor(srcImage, srcImage, cv::COLOR_RGB2BGR);
    }
    else
    {
    
    
        /* Bayer 格式转换mat格式的方法:
        1. 使用相机句柄销毁前 调用 MV_CC_ConvertPixelType 将PixelType_Gvsp_BayerRG8 等Bayer格式转换成 PixelType_Gvsp_BGR8_Packed
        2. 参考上面 将BGR转换为 mat格式
        */

        printf("Unsupported pixel format\n");
        return false;
    }

    if (NULL == srcImage.data)
    {
    
    
        printf("Creat Mat failed.\n");
        return false;
    }

    try
    {
    
    
        // ch:保存Mat图片 | en:Save converted image in a local file
        cv::imwrite("Image_Mat.bmp", srcImage);
    }
    catch (cv::Exception& ex)
    {
    
    
        fprintf(stderr, "Exception in saving mat image: %s\n", ex.what());
    }
    return true;
}



class MVS_camera_client {
    
    

public:
    int nRet = MV_OK;
    void* handle = NULL;
    unsigned char* pData = NULL;
    unsigned int nPayloadSize;
    MV_FRAME_OUT_INFO_EX stImageInfo = {
    
     0 };
    //获取所有的相机
    MV_CC_DEVICE_INFO_LIST Get_MVS_camera() {
    
    
        MV_CC_DEVICE_INFO_LIST stDeviceList;
        memset(&stDeviceList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));
        int nRet = MV_OK;
        // ch:设备枚举 | en:Enum device
        nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &stDeviceList);
        if (MV_OK != nRet)
        {
    
    
            printf("相机列表获取失败! nRet [0x%x]\n", nRet);
            exit(0);
        }

        // ch:显示设备信息 | en:Show devices
        if (stDeviceList.nDeviceNum > 0)
        {
    
    
            for (unsigned int i = 0; i < stDeviceList.nDeviceNum; i++)
            {
    
    
                printf("[device %d]:\n", i);
                MV_CC_DEVICE_INFO* pDeviceInfo = stDeviceList.pDeviceInfo[i];
                if (NULL == pDeviceInfo)
                {
    
    
                    break;
                }
                PrintDeviceInfo(pDeviceInfo);
            }
            return stDeviceList;
        }
        else
        {
    
    
            printf("没有找到相机!\n");
            exit(0);
        }

    }

    //初始化相机信息, 默认选用第0个相机
    void init_camera(unsigned int nIndex = 0) {
    
    
        MV_CC_DEVICE_INFO_LIST stDeviceList = Get_MVS_camera();
        // ch:创建设备句柄 | en:Create handle
        nRet = MV_CC_CreateHandle(&handle, stDeviceList.pDeviceInfo[nIndex]);
        if (MV_OK != nRet)
        {
    
    
            printf("Create Handle fail! nRet [0x%x]\n", nRet);
            return;
        }

        // ch:打开设备 | en:Open device
        nRet = MV_CC_OpenDevice(handle);
        if (MV_OK != nRet)
        {
    
    
            printf("Open Device fail! nRet [0x%x]\n", nRet);
            return;
        }

        // ch:探测最佳Packet大小(只支持GigE相机) | en:Detection network optimal package size(It only works for the GigE camera)
        if (MV_GIGE_DEVICE == stDeviceList.pDeviceInfo[nIndex]->nTLayerType)
        {
    
    
            int nPacketSize = MV_CC_GetOptimalPacketSize(handle);
            if (nPacketSize > 0)
            {
    
    
                // 设置Packet大小
                nRet = MV_CC_SetIntValue(handle, "GevSCPSPacketSize", nPacketSize);
                if (MV_OK != nRet)
                {
    
    
                    printf("Warning: Set Packet Size fail! nRet [0x%x]!", nRet);
                }
            }
            else
            {
    
    
                printf("Warning: Get Packet Size fail! nRet [0x%x]!", nPacketSize);
            }
        }

        // ch:关闭触发模式 | en:Set trigger mode as off
        nRet = MV_CC_SetEnumValue(handle, "TriggerMode", 0);
        if (MV_OK != nRet)
        {
    
    
            printf("Set Trigger Mode fail! nRet [0x%x]\n", nRet);
            return;
        }

        // ch:获取图像大小 | en:Get payload size
        MVCC_INTVALUE stParam;
        memset(&stParam, 0, sizeof(MVCC_INTVALUE));
        nRet = MV_CC_GetIntValue(handle, "PayloadSize", &stParam);
        if (MV_OK != nRet)
        {
    
    
            printf("Get PayloadSize fail! nRet [0x%x]\n", nRet);
            return;
        }
        nPayloadSize = stParam.nCurValue;

        // ch:初始化图像信息 | en:Init image info

        memset(&stImageInfo, 0, sizeof(MV_FRAME_OUT_INFO_EX));
        pData = (unsigned char*)malloc(sizeof(unsigned char) * (nPayloadSize));
        if (NULL == pData)
        {
    
    
            printf("Allocate memory failed.\n");
            return;
        }
        memset(pData, 0, sizeof(pData));

    }

    //进行拍照
    cv::Mat take_photos() {
    
    
        cv::Mat res;
        nRet = MV_CC_StartGrabbing(handle);
        if (MV_OK != nRet)
        {
    
    
            printf("Start Grabbing fail! nRet [0x%x]\n", nRet);
            return res;
        }

        // ch:获取一帧图像,超时时间1000ms | en:Get one frame from camera with timeout=1000ms
        nRet = MV_CC_GetOneFrameTimeout(handle, pData, nPayloadSize, &stImageInfo, 1000);
        if (MV_OK == nRet)
        {
    
    
            printf("Get One Frame: Width[%d], Height[%d], FrameNum[%d]\n",
                stImageInfo.nWidth, stImageInfo.nHeight, stImageInfo.nFrameNum);
        }
        else
        {
    
    
            printf("Get Frame fail! nRet [0x%x]\n", nRet);
            return res;
        }

        // ch:停止取流 | en:Stop grab image
        nRet = MV_CC_StopGrabbing(handle);
        if (MV_OK != nRet)
        {
    
    
            printf("Stop Grabbing fail! nRet [0x%x]\n", nRet);
            return res;
        }

        // ch:关闭设备 | en:Close device
        nRet = MV_CC_CloseDevice(handle);
        if (MV_OK != nRet)
        {
    
    
            printf("ClosDevice fail! nRet [0x%x]\n", nRet);
            return res;
        }

        // ch:数据转换 | en:Convert image data
        bool bConvertRet = false;
        bConvertRet = Convert2Mat(res, &stImageInfo, pData);
        return res.clone();//返回clone对象,防止句柄释放后出现bug
    }

    //销毁句柄
    void destory() {
    
    
        // ch:销毁句柄 | en:Destroy handle
        if (handle)
        {
    
    
            MV_CC_DestroyHandle(handle);
            handle = NULL;
        }

        // ch:释放内存 | en:Free memery
        if (pData)
        {
    
    
            free(pData);
            pData = NULL;
        }
    }
};

int main()
{
    
    
    MVS_camera_client camera;
    camera.init_camera();
    cv::Mat img = camera.take_photos();
    camera.destory();

    system("pause");
    return 0;
}

3.4 配置项提取

include目录: $(MVCAM_COMMON_RUNENV)\Includes;inc;E:\Lib\opencv454\build\include;

lib目录:
$(MVCAM_COMMON_RUNENV)\Libraries\win64;lib;E:\Lib\opencv454\build\x64\vc15\lib;

附加依赖项:MvCameraControl.lib;opencv_world454.lib;

4、自建项目配置MVS

4.1 环境配置

在vs2019中创建c++新项目,将运行配置点为Release|x64,然后在项目名称上点击右键,
在这里插入图片描述

在弹出的列表中点击属性,进入属性配置,进行以下配置
在这里插入图片描述

在这里插入图片描述

4.2 代码编写

点击源文件,添加新建项
在这里插入图片描述
然后将3.3中的完整代码添加到“源.cpp”中
并将主函数代码改成以下:

int main()
{
    
    
    MVS_camera_client camera;
    camera.init_camera();
    cv::Mat img = camera.take_photos();
    camera.destory();//相机句柄销毁后,所拍摄的图像也被销毁了

    cv::imshow("mat", img);
    cv::waitKey();


    system("pause");
    return 0;
}


4.3 运行效果

此时拍摄的照片与模拟相机设置的一模一样,说明程序开发成功,模拟相机使用成功!
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_74259636/article/details/134792880