精华内容
下载资源
问答
  • 海康威视工业相机MV-CE060-10UC使用指北
    2022-03-05 23:20:16

    海康威视工业相机MV-CE060-10UC使用指北

    海康威视工业面阵相机MV-CE060-10UC非UVC设备,欲使用该工业相机进行二次开发,需使用MVS机器视觉工业相机客户端。本文以x86架构下Linux系统为例,具体操作系统为Ubuntu 20.04,介绍该工业相机的使用方法。

    设备参数简介

    海康威视工业面阵相机MV-CE060-10UC的具体性能参数如下:

    条目
    传感器类型CMOS,卷帘快门
    传感器型号IMX178
    像元尺寸2.4 µm×2.4 µm
    靶面尺寸1/1.8"
    分辨率3072×2048
    最大帧率42.7 fps@3072×2048
    动态范围71.3 dB
    信噪比41.3 dB
    增益0 dB ~20 dB
    曝光时间24 μs ~ 1 sec
    快门模式支持自动曝光、手动曝光、一键曝光以及 Global Reset
    黑白/彩色彩色
    像素格式Mono 8/10/12 Bayer RG 8/10/10p/12/12p YUV422Packed,YUV422_YUYV_Packed RGB 8,BGR 8
    Binning支持 1×1,2×2
    下采样不支持
    镜像支持水平镜像

    资料下载

    技术资料下载

    工业相机MVS下载(本文使用MVS V2.1.1 Linux为例)

    MVS安装

    将MVS_STD_GML_V2.1.1_211224.zip下载到本机,将其解压可得到aarch64, armhf, i386, x86_64等不同架构下的安装包,本文选择x86_64 deb包,使用dpkg安装。如使用aarch环境,则使用 MVS-2.1.1_aarch64_20211224.deb 这个包

    $ unzip MVS_STD_GML_V2.1.1_211224.zip
    $ sudo dpkg -i MVS-2.1.1_x86_64_20211224.deb
    

    等待安装完毕,默认情况下该软件安装到 /opt/MVS/

    使用以下命令打开MVS应用程序

    $ /opt/MVS/bin/MVS.sh
    # 若出现无法打开的问题,尝试切换到 /opt/MVS/bin/ 目录下重试
    $ cd /opt/MVS/bin/
    $ ./MVS.sh
    

    通常情况下,MVS应用程序供初次使用该相机时调试相机参数使用,例如曝光时间,增益参数等,这样在二次开发时无需重新设置参数。但是请注意,设置好的参数在相机断电后不会保存,所以应及时保存用户设置,如需下次上电后自动选择之前的参数,应在MVS应用程序中做设置。

    代码指北

    本文介绍如何从MV工业相机中采集图像,转换到OpenCV(本文以3.4.5为例) cv::Mat图像格式,便于进一步开发。

    在进行编程之前,应在编译规则中加入(以CMake为例):

    include_directories(/opt/MVS/include/)
    link_directories(/opt/MVS/lib/64/)
    # 若在 aarch 架构下使用,请使用 link_directories(/opt/MVS/lib/aarch64/)
    target_link_libraries(${PROJECT_NAME} 
    MvCameraControl)
    # 由于使用了OpenCV,也应加入:
    find_package(OpenCV 3 REQUIRED)
    include_directories(${OpenCV_INCLUDE_DIRS})
    target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS})
    
    MV工业相机的使用遵循以下流程:

    枚举设备 => 选择设备并创建句柄 => 打开设备 => 注册抓图回调 => 开始取流 => (回调函数逻辑)=> 停止取流 => 关闭设备 => 销毁句柄

    在MVS安装好后,将能够调用摄像头相关的API,常用API如下:

    // 头文件
    #include "MvCameraControl.h"
    #include "opencv2/core.hpp"
    
    int deviceIndex = 0;
    void *handle = nullptr;
    MV_CC_DEVICE_INFO_LIST stDeviceList;
    MVCC_INTVALUE stParam;
    unsigned char *pData;
    cv::Mat curFrame;
    
    // 回调函数
    void __stdcall ImageCallBackExForBGR8(unsigned char *pData, MV_FRAME_OUT_INFO_EX *pFrameInfo, void *pUser) {
    	curCamera->curFrame = cv::Mat(pFrameInfo->nHeight, pFrameInfo->nWidth, CV_8UC3, pData);
    }
    
    // 枚举设备
    memset(&stDeviceList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));
    MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &stDeviceList);
    
    if (stDeviceList.nDeviceNum > 0) {
    		for (int i = 0; i < stDeviceList.nDeviceNum; ++i) {
    			printf("[device %d]:\n", i);
    			MV_CC_DEVICE_INFO *pDeviceInfo = stDeviceList.pDeviceInfo[i];
    		}
    	} else {
    		printf("Find No Devices!\n");
    	}
    
    // 选择设备并创建句柄
    MV_CC_CreateHandle(&handle, stDeviceList.pDeviceInfo[deviceIndex]);
    
    // 打开设备
    MV_CC_OpenDevice(handle);
    
    // 注册抓图回调
    MV_CC_RegisterImageCallBackForBGR(handle, ImageCallBackExForBGR8, handle);
    
    // 开始取流
    MV_CC_StartGrabbing(handle);
    MV_FRAME_OUT_INFO_EX stImageInfo = {0};
    memset(&stImageInfo, 0, sizeof(MV_FRAME_OUT_INFO_EX));
    pData = (unsigned char *)malloc(sizeof(unsigned char) * stParam.nCurValue);
    
    // 停止取流
    MV_CC_StopGrabbing(handle);
    
    // 关闭设备
    MV_CC_CloseDevice(handle);
    
    // 销毁句柄
    MV_CC_DestroyHandle(handle);
    

    详细使用方法已上传到Gitee,并且已封装好。参见https://gitee.com/shenhaoyuan/hikrobot-mvcamera


    作者:Hoyin

    最后编辑时间:2022/2/21

    联系作者:work_hoyin@163.com

    更多相关内容
  • 基于Opencv进行二次开发海康工业相机的调用流程,和阈值处理
  • 目前正在学习工业视觉,使用的是海康威视的相机,压缩包里,是海康威视工业相机C#接口,具有的功能有自动查找设备,打开所选设备,关闭所选设备,采集图像有连续模式和触发模式,可保存采集BMP格式图像和JPG图像,...
  • 环境说明:Ubuntu16.04 海康威视SDK包:MVS-2.1.0_x86_64_20201228.tar.gz 记录自己的学习过程,方便以后查阅。

    环境说明:Ubuntu16.04
    海康威视SDK包:MVS-2.1.0_x86_64_20201228.tar.gz

    如若在Windows环境下配合Visual Studio使用请移至
    海康威视工业相机SDK二次开发(VS+Opencv+QT+海康SDK+C++)(一)
    海康威视工业相机SDK二次开发(VS+Opencv+QT+海康SDK+C++)(二)

    记录自己的学习过程,方便以后查阅,若有错误或遗漏,欢迎大佬指正补充。

    在这里插入图片描述

    1.准备

      首先是安装海康威视的MVS软件,VMware虚拟机中Ubuntu16.04系统下通过MVS运行海康威视工业相机

    1.1 相关资料

    • 工业相机SDK(C)开发指南
      这是最重要的资料,里面有(环境配置:SDK编程环境配置,包括网络配置、驱动安装等)、(编程导引:相机连接流程和取图方式介绍)、相机的常用节点等等。
      在这里插入图片描述
      在这里插入图片描述
    • 相机的常用节点查询
      这部分主要是用于SDK提供API接口中的参数设置,如设置曝光模式、曝光值、增益模式、增益值、外触发等等。
      在这里插入图片描述
      根据我实际开发过程中常用的相机节点值如下:
      在这里插入图片描述
    • CameraParams.h:包含编程需要的所有结构体、宏定义和枚举量
    • MvCameraControl.h包含所有控制相机的API接口
    • 相关示例程序
      在这里插入图片描述

    1.2 Debug常备

      如果遇到问题,比如相机未正常打开、相机无法取图等等,及时打印每次调用SDK接口返回的输出值,对照错误码定义去排查问题(记得将输出值转化为十六进制)事半功倍。

      如果函数正常完成而没有检测到任何错误,则返回值为MV_OK,否则返回错误码 。
    在这里插入图片描述

    2.通过海康相机SDK熟悉C接口取图流程和取图方式

    个人总结:句柄(void *handle)是相机开发中重要的一环,SDK中的接口中,大部分都是针对句柄的操作,如果有多个相机,要将每个相机和其对应的句柄关联好,防止后期使用的过程中未及时释放句柄、造成混乱等。

    2.1 设备连接接口流程

      对设备进行操作,实现图像采集、参数配置等功能,需要先连接设备(打开设备),具体流程如下图所示:
    在这里插入图片描述
      1.调用 MV_CC_EnumDevices() 枚举子网内指定传输协议对应的所有设备。可以通过 pstDevList 在结构 MV_CC_DEVICE_INFO_LIST 中找到设备的信息。
    在这里插入图片描述

    #include "MvCameraControl.h"
    
    void main()
    {
        unsigned int nTLayerType = MV_GIGE_DEVICE | MV_USB_DEVICE;
    
        MV_CC_DEVICE_INFO_LIST m_stDevList = {0};
        int nRet = MV_CC_EnumDevices(nTLayerType, &m_stDevList);
        if (MV_OK != nRet)
        {
            printf("error: EnumDevices fail [%x]\n", nRet);
        }
    }
    

      关于搜索到的所有相机设备信息在 MV_CC_DEVICE_INFO_LIST结构体中,

    /// \~chinese 设备信息列表    \~english Device Information List
    typedef struct _MV_CC_DEVICE_INFO_LIST_
    {
        unsigned int        nDeviceNum;                         ///< [OUT] \~chinese 在线设备数量       \~english Online Device Number
        MV_CC_DEVICE_INFO*  pDeviceInfo[MV_MAX_DEVICE_NUM];     ///< [OUT] \~chinese 支持最多256个设备  \~english Support up to 256 devices
    
    }MV_CC_DEVICE_INFO_LIST;
    

      通过MV_CC_DEVICE_INFO结构体可以访问每个设备的详细信息,

    /// \~chinese 设备信息    \~english Device info
    typedef struct _MV_CC_DEVICE_INFO_
    {
        unsigned short      nMajorVer;                  ///< [OUT] \~chinese 主要版本                                 \~english Major Version
        unsigned short      nMinorVer;                  ///< [OUT] \~chinese 次要版本                                 \~english Minor Version
        unsigned int        nMacAddrHigh;               ///< [OUT] \~chinese 高MAC地址                                \~english High MAC Address
        unsigned int        nMacAddrLow;                ///< [OUT] \~chinese 低MAC地址                                \~english Low MAC Address
    
        unsigned int        nTLayerType;                ///< [OUT] \~chinese 设备传输层协议类型,e.g. MV_GIGE_DEVICE  \~english Device Transport Layer Protocol Type, e.g. MV_GIGE_DEVICE
    
        unsigned int        nReserved[4];               ///<       \~chinese 预留                                     \~english Reserved
    
        union
        {
            MV_GIGE_DEVICE_INFO stGigEInfo;             ///< [OUT] \~chinese GigE设备信息                             \~english GigE Device Info
            MV_USB3_DEVICE_INFO stUsb3VInfo;            ///< [OUT] \~chinese USB设备信息                              \~english USB Device Info
            MV_CamL_DEV_INFO    stCamLInfo;             ///< [OUT] \~chinese CameraLink设备信息                          \~english CameraLink Device Info
            // more ...
        }SpecialInfo;
    
    }MV_CC_DEVICE_INFO;
    

      这里以我使用的网口相机GigE设备为例,要获取到设备的详细内容:

    // 我通过std::map<std::string, std::tuple<void*,MV_CC_DEVICE_INFO*>>m_dev_info_list_;来存储枚举到的所示设备。
    // 第一个参数的设备的名称,这个可以自己定义,方便后面对哪一个相机进行操作;
    // 第二个参数是句柄
    // 第三个参数就是MV_CC_DEVICE_INFO设备信息的结构体
    MV_CC_DEVICE_INFO* pstMVDevInfo = std::get<1>(m_dev_info_list_[dev_name]);
    
    if (pstMVDevInfo->nTLayerType == MV_GIGE_DEVICE) {
            std::string model =
                (char*)pstMVDevInfo->SpecialInfo.stGigEInfo.chModelName;
            std::string cam_ip = "Current IP Address: " ;
            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);
        }
    

      有些参数我也没搞懂是什么信息。。。
    在这里插入图片描述
      2.在打开指定设备之前,调用 MV_CC_IsDeviceAccessible() 检查指定设备是否可访问。 (这一步在实际使用中并未用到)
    在这里插入图片描述
      3.调用 MV_CC_CreateHandle() 以创建设备句柄。
    在这里插入图片描述

    #include "MvCameraControl.h"
    
    void main()
    {
        int nRet = -1;
        void*  m_handle = NULL;
    
        //枚举子网内指定的传输协议对应的所有设备
         unsigned int nTLayerType = MV_GIGE_DEVICE | MV_USB_DEVICE;
        MV_CC_DEVICE_INFO_LIST m_stDevList = {0};
        int nRet = MV_CC_EnumDevices(nTLayerType, &m_stDevList);
        if (MV_OK != nRet)
        {
            printf("error: EnumDevices fail [%x]\n", nRet);
            return;
        }
    
        int i = 0;
        if (m_stDevList.nDeviceNum == 0)
        {
            printf("no camera found!\n");
            return;
        }
    
        //选择查找到的第一台在线设备,创建设备句柄
         int nDeviceIndex = 0;
    
        MV_CC_DEVICE_INFO m_stDevInfo = {0};
        memcpy(&m_stDevInfo, m_stDevList.pDeviceInfo[nDeviceIndex], sizeof(MV_CC_DEVICE_INFO));
    
        nRet = MV_CC_CreateHandle(&m_handle, &m_stDevInfo);
    
        if (MV_OK != nRet)
        {
            printf("error: CreateHandle fail [%x]\n", nRet);
            return;
        }
    
        //...其他处理
     
        //销毁句柄,释放资源
         nRet = MV_CC_DestroyHandle(m_handle);
        if (MV_OK != nRet)
        {
            printf("error: DestroyHandle fail [%x]\n", nRet);
            return;
        }
    }
    

      4.调用 MV_CC_OpenDevice() 打开设备。
    在这里插入图片描述
      去该API定义后发现,后面两个参数有默认值,所以实际使用中只需要输入第一个参数设备的句柄即可。

    /********************************************************************//**
     *  @~chinese
     *  @brief  打开设备
     *  @param  handle                      [IN]            设备句柄
     *  @param  nAccessMode                 [IN]            访问权限
     *  @param  nSwitchoverKey              [IN]            切换访问权限时的密钥
     *  @return 成功,返回MV_OK;错误,返回错误码 
     *  @remarks 根据设置的设备参数,找到对应的设备,连接设备。\n 
                 调用接口时可不传入nAccessMode和nSwitchoverKey,此时默认设备访问模式为独占权限。目前设备暂不支持MV_ACCESS_ExclusiveWithSwitch、MV_ACCESS_ControlWithSwitch、MV_ACCESS_ControlSwitchEnable、MV_ACCESS_ControlSwitchEnableWithKey这四种抢占模式。\n 
                 对于U3V设备,nAccessMode、nSwitchoverKey这两个参数无效。  */
    #ifndef __cplusplus
    MV_CAMCTRL_API int __stdcall MV_CC_OpenDevice(IN void* handle, IN unsigned int nAccessMode, IN unsigned short nSwitchoverKey);
    #else
    MV_CAMCTRL_API int __stdcall MV_CC_OpenDevice(IN void* handle, IN unsigned int nAccessMode = MV_ACCESS_Exclusive, IN unsigned short nSwitchoverKey = 0);
    #endif
    
    int nRet = MV_CC_OpenDevice(m_handle);
    

      5.调用 MV_CC_CloseDevice() 关闭设备。
    在这里插入图片描述
      6.调用 MV_CC_DestroyHandle() 来销毁句柄并释放资源。
    在这里插入图片描述

    2.2 相机取图——主动取流

      SDK提供主动获取图像的接口,用户可以在开启取流后直接调用此接口获取图像,也可以使用异步方式(线程、定时器等)获取图像。示例代码详见 GrabImage.cpp 和 GrabImage_HighPerformance.cpp 。
    在这里插入图片描述

    • 主动获取图像有两种方式(两种方式不能同时使用)
      方式一:调用 MV_CC_StartGrabbing() 开始采集,需要自己开启一个buffer,然后在应用层循环调用 MV_CC_GetOneFrameTimeout() 获取指定像素格式的帧数据,获取帧数据时上层应用程序需要根据帧率控制好调用该接口的频率。
      方式二:调用 MV_CC_StartGrabbing() 开始采集,然后在应用层调用 MV_CC_GetImageBuffer() 获取指定像素格式的帧数据,然后调用 MV_CC_FreeImageBuffer() 释放buffer,获取帧数据时上层应用程序需要根据帧率控制好调用该接口的频率。
    • 主动取图方式使用的场景
      主动取图方式需要先调用 MV_CC_StartGrabbing() 启动图像采集。上层应用程序需要根据帧率,控制好调用主动取图接口的频率。两种主动取图方式都支持设置超时时间,SDK内部等待直到有数据时返回,可以增加取流平稳性,适合用于对平稳性要求较高的场合。
    • 两种主动取图方式的区别
      a、 MV_CC_GetImageBuffer() 需要与 MV_CC_FreeImageBuffer() 配套使用,当处理完取到的数据后,需要用 MV_CC_FreeImageBuffer() 接口将pstFrame内的数据指针权限进行释放。
      b、 MV_CC_GetImageBuffer()MV_CC_GetOneFrameTimeout() 相比,有着更高的效率。且其取流缓存的分配是由sdk内部自动分配的,而 MV_CC_GetOneFrameTimeout() 接口是需要客户自行分配。

    这里我使用方式一的取图流程。

      1.开始取流。
    在这里插入图片描述
      2.停止取流。
    在这里插入图片描述
      3.方式一的取图方式,采用超时机制获取一帧图片,SDK内部等待直到有数据时返回。
    在这里插入图片描述

    #include "MvCameraControl.h"
    
    void main()
    {
        int nRet = -1;
        void* m_handle = NULL;
    
        //枚举子网内指定的传输协议对应的所有设备
         unsigned int nTLayerType = MV_GIGE_DEVICE | MV_USB_DEVICE;
        MV_CC_DEVICE_INFO_LIST m_stDevList = {0};
        int nRet = MV_CC_EnumDevices(nTLayerType, &m_stDevList);
        if (MV_OK != nRet)
        {
            printf("error: EnumDevices fail [%x]\n", nRet);
            return;
        }
    
        int i = 0;
        if (m_stDevList.nDeviceNum == 0)
        {
            printf("no camera found!\n");
            return;
        }
    
        //选择查找到的第一台在线设备,创建设备句柄
        int nDeviceIndex = 0;
    
        MV_CC_DEVICE_INFO m_stDevInfo = {0};
        memcpy(&m_stDevInfo, m_stDevList.pDeviceInfo[nDeviceIndex], sizeof(MV_CC_DEVICE_INFO));
    
        nRet = MV_CC_CreateHandle(&m_handle, &m_stDevInfo);
    
        if (MV_OK != nRet)
        {
            printf("error: CreateHandle fail [%x]\n", nRet);
            return;
        }
    
        //连接设备
         nRet = MV_CC_OpenDevice(m_handle, nAccessMode, nSwitchoverKey);
        if (MV_OK != nRet)
        {
            printf("error: OpenDevice fail [%x]\n", nRet);
            return;
        }
        //...其他处理 
    
        //开始采集图像
         nRet = MV_CC_StartGrabbing(m_handle);
        if (MV_OK != nRet)
        {
            printf("error: StartGrabbing fail [%x]\n", nRet);
            return;
        }
    
        //获取一帧数据的大小
        MVCC_INTVALUE stIntvalue = {0};
        nRet = MV_CC_GetIntValue(m_handle, "PayloadSize", &stIntvalue);
        if (nRet != MV_OK)
        {
            printf("Get PayloadSize failed! nRet [%x]\n", nRet);
            return;
        }
        int nBufSize = stIntvalue.nCurValue; //一帧数据大小
    
        unsigned int    nTestFrameSize = 0;
        unsigned char*  pFrameBuf = NULL;
        pFrameBuf = (unsigned char*)malloc(nBufSize);
    
        MV_FRAME_OUT_INFO_EX stInfo;
        memset(&stInfo, 0, sizeof(MV_FRAME_OUT_INFO_EX));
    
        //上层应用程序需要根据帧率,控制好调用该接口的频率
        //此次代码仅供参考,实际应用建议另建线程进行图像帧采集和处理
         while(1)
        {
            if (nTestFrameSize > 99) 
            {
                break;
            }
            nRet = MV_CC_GetOneFrameTimeout(m_handle, pFrameBuf, nBufSize, &stInfo, 1000);
            if (MV_OK != nRet)
            {
                Sleep(10);
            }
            else
            {
                //...图像数据处理
                nTestFrameSize++;
            }
        }
    
        //...其他处理
    
        //停止采集图像 
         nRet = MV_CC_StopGrabbing(m_handle);
        if (MV_OK != nRet)
        {
            printf("error: StopGrabbing fail [%x]\n", nRet);
            return;
        }
    
        //关闭设备,释放资源
         nRet = MV_CC_CloseDevice(m_handle);
        if (MV_OK != nRet)
        {
            printf("error: CloseDevice fail [%x]\n", nRet);
            return;
        }
    
        //销毁句柄,释放资源
         nRet = MV_CC_DestroyHandle(m_handle);
        if (MV_OK != nRet)
        {
            printf("error: DestroyHandle fail [%x]\n", nRet);
            return;
        }    
    }
    

    SDK还提供了回调出流的方法,这里我没研究,如果大佬采用的这种方式,也可以一起交流,方便我学习。

    2.3 设置相机的一些参数

    /********************************************************************//**
     *  @~chinese
     *  @brief  设置Enum型属性值
     *  @param  handle                      [IN]            设备句柄
     *  @param  strKey                      [IN]            属性键值,如获取像素格式信息则为"PixelFormat"
     *  @param  nValue                      [IN]            想要设置的设备的属性值
     *  @return 成功,返回MV_OK,失败,返回错误码
     *  @remarks 连接设备之后调用该接口可以设置Enum类型的指定节点的值。strKey取值可以参考XML节点参数类型列表,表格里面数据类型为“IEnumeration”的节点值都可以通过该接口设置,strKey参数取值对应列表里面的“名称”一列。
    ************************************************************************/
    MV_CAMCTRL_API int __stdcall MV_CC_SetEnumValue(IN void* handle,IN const char* strKey,IN unsigned int nValue);
    
    /********************************************************************//**
     *  @~chinese
     *  @brief  设置float型属性值
     *  @param  handle                      [IN]            设备句柄
     *  @param  strKey                      [IN]            属性键值
     *  @param  fValue                      [IN]            想要设置的设备的属性值
     *  @return 成功,返回MV_OK,失败,返回错误码
     *  @remarks 连接设备之后调用该接口可以设置float类型的指定节点的值。strKey取值可以参考XML节点参数类型列表,表格里面数据类型为“IFloat”的节点值都可以通过该接口设置,strKey参数取值对应列表里面的“名称”一列。 ************************************************************************/
    MV_CAMCTRL_API int __stdcall MV_CC_SetFloatValue(IN void* handle,IN const char* strKey,IN float fValue);
    

      关于输入参数参考相机中的节点。

    int setCameraParametMode(const char* str_key, unsigned int val)
    {
        // TriggerMode    0: Off  1: On
        // TriggerSource  0:Line0  1:Line1  7:Software
        // GainAuto       0: Off    1: Once   2: Continuous
        int temp_val = MV_CC_SetEnumValue(m_handle, str_key, val);
        if (temp_val != 0) {
            return -1;
        }
        else {
            return 0;
        }
    }
    
    int setCameraParametValue(const char* str_type, float num_val)
    {
        // ExposureTime
        // Gain
        int temp_value = MV_CC_SetFloatValue(m_handle, str_type, num_val);
        if (temp_value != 0) {
            return -1;
        }
        else {
            return 0;
        }
    }
    

      使用:

    camera_obj->setCameraParametMode("ExposureAuto", 0);
    camera_obj->setCameraParametValue("ExposureTime", exposure_time);
    camera_obj->setCameraParametMode("GainAuto", 0);
    camera_obj->setCameraParametValue("Gain", gain);
    

    3.将相机抓取到的图像转为Mat格式,方便后续使用

    /************************************************************************
     *  @fn     MV_CAMCTRL_API int __stdcall MV_CC_GetIntValue(IN void* handle,
                                                               IN const char* strKey,
                                                               OUT MVCC_INTVALUE *pIntValue);
     *  @brief  获取Integer属性值(建议改用MV_CC_GetIntValueEx接口)
     *  @param  void* handle                [IN]        相机句柄
     *  @param  char* strKey                [IN]        属性键值,如获取宽度信息则为"Width"
     *  @param  MVCC_INTVALUE* pstValue     [IN][OUT]   返回给调用者有关相机属性结构体指针
     *  @return 成功,返回MV_OK,失败,返回错误码
    ************************************************************************/
    MV_CAMCTRL_API int __stdcall MV_CC_GetIntValue(IN void* handle,IN const char* strKey,OUT MVCC_INTVALUE *pIntValue);
    
    • 相机采集到的图像格式是buffer,需要将其转化为Mat类型。
    int HikCamera::CameraOneFrameImageToMat(void* dev_handle,const std::string& dev_name, cv::Mat& image)
    {
        cv::Mat* getImage = new cv::Mat();
        unsigned int nRecvBufSize = 0;
        MVCC_INTVALUE stParam;
        memset(&stParam, 0, sizeof(MVCC_INTVALUE));
        int tempValue = MV_CC_GetIntValue(dev_handle, "PayloadSize", &stParam);
        if (tempValue != 0) {
            return -1;
        }
        nRecvBufSize = stParam.nCurValue;
        unsigned char* pDate;
        pDate = (unsigned char*)malloc(nRecvBufSize);
    
        MV_FRAME_OUT_INFO_EX stImageInfo = { 0 };
        tempValue = MV_CC_GetOneFrameTimeout(dev_handle, pDate, nRecvBufSize,
            &stImageInfo, 500);
        if (tempValue != 0) {
            return -1;
        }
        m_nBufSizeForSaveImage_ =
            stImageInfo.nWidth * stImageInfo.nHeight * 3 + 2048;
        unsigned char* m_pBufForSaveImage;
        m_pBufForSaveImage = (unsigned char*)malloc(m_nBufSizeForSaveImage_);
    
        bool isMono; //判断是否为黑白图像
        switch (stImageInfo.enPixelType) {
        case PixelType_Gvsp_Mono8:
        case PixelType_Gvsp_Mono10:
        case PixelType_Gvsp_Mono10_Packed:
        case PixelType_Gvsp_Mono12:
        case PixelType_Gvsp_Mono12_Packed:
            isMono = true;
            break;
        default:
            isMono = false;
            break;
        }
        if (isMono) {
            *getImage =
                cv::Mat(stImageInfo.nHeight, stImageInfo.nWidth, CV_8UC1, pDate);
        }
        else {
            // 转换图像格式为BGR8
            MV_CC_PIXEL_CONVERT_PARAM stConvertParam = { 0 };
            memset(&stConvertParam, 0, sizeof(MV_CC_PIXEL_CONVERT_PARAM));
            stConvertParam.nWidth = stImageInfo.nWidth;
            stConvertParam.nHeight = stImageInfo.nHeight;
            stConvertParam.pSrcData = pDate;
            stConvertParam.nSrcDataLen = stImageInfo.nFrameLen; // 输入数据大小
            stConvertParam.enSrcPixelType = stImageInfo.enPixelType; // 输入像素格式
            stConvertParam.enDstPixelType = PixelType_Gvsp_BGR8_Packed; // 输出像素格式
    
            stConvertParam.pDstBuffer = m_pBufForSaveImage; // 输出数据缓存
            stConvertParam.nDstBufferSize = m_nBufSizeForSaveImage_; // 输出缓存大小
            MV_CC_ConvertPixelType(dev_handle, &stConvertParam);
    
            *getImage = cv::Mat(stImageInfo.nHeight, stImageInfo.nWidth, CV_8UC3, m_pBufForSaveImage);
        }
        (*getImage).copyTo(image);
        (*getImage).release();
        free(pDate);
        free(m_pBufForSaveImage);
        return 0;
    }
    

    4.将Mat格式图像转为QImage格式,用于UI界面上控件的显示

      转化为Mat后,通过display_myImage_L再将Mat转化为QImage类型,进行在控件上显示。软触发的话,就是采集到当前帧图像,通过display_myImage_L显示,连续采集的话,通过多线程,将线程对象myThread_camera_L_show发送信号display给主线程,主线程调用display_myImage_L将相机采集到的图像进行显示。

    void display_myImage_L(const cv::Mat* image_ptr)
    {
        cv::Mat rgb;
        // cv::cvtColor(*imagePrt, rgb, CV_BGR2RGB);
    
        //判断是黑白、彩色图像
        QImage QmyImage_L;
        if (lbl_camera_L_image->channels() > 1) {
            cv::cvtColor(*image_ptr, rgb, CV_BGR2RGB);
            QmyImage_L = QImage((const unsigned char*)(rgb.data), rgb.cols,
                rgb.rows, QImage::Format_RGB888);
        }
        else {
            cv::cvtColor(*image_ptr, rgb, CV_GRAY2RGB);
            QmyImage_L = QImage((const unsigned char*)(rgb.data), rgb.cols,
                rgb.rows, QImage::Format_RGB888);
        }
    
        QmyImage_L = (QmyImage_L).scaled(ui.lbl_camera_L->size(), Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
    
        ui.lbl_camera_L->setPixmap(QPixmap::fromImage(QmyImage_L));
    }
    

    参考博文:
    https://cloud.tencent.com/developer/article/1730933
    https://blog.csdn.net/weixin_46421489/article/details/116381368
    关于相机SDK开发
    https://cloud.tencent.com/developer/article/1730940

    展开全文
  • 海康威视工业相机使用

    千次阅读 热门讨论 2020-12-26 21:40:51
    需要用摄像头,而实验室只有一个海康威视的MV-CA013-20GC(另一个大恒的更难搞),拿工业相机当普通相机用是不是有点暴殄天物了。 1. 相机接线 工业相机一般都需要独立供电,12v接上相机的正负极,另外网口接上...

    需要用摄像头,而实验室只有一个海康威视的MV-CA013-20GC(另一个大恒的更难搞),拿工业相机当普通相机用是不是有点暴殄天物了。

     

    1. 相机接线

    工业相机一般都需要独立供电,12v接上相机的正负极,另外网口接上电脑或交换机Lan口,建议使用千兆网口,不然帧率跟不上(也可以使用网口转usb3.0).

    2.客户端使用

    官网下载下面两个软件安装,一个是客户端,另一个是开发运行环境。

    打开软件如图所示

    软件会自动搜索可连接的设备,查找到设备后修改相机的ip,连接上相机,然后就可以调节参数了。这里如果画面很黑,首先调小相机的光圈,增大进光量,开启自动曝光与自动增益、伽马校正。如果使用的百兆网口会出现帧率低的情况,这里要么就更换千兆网口,要么将图像类型设置为mono8.

    3.sdk的二次开发

    进入到安装目录下有一个Development文件夹,里面有头文件和库文件以及各种语言的开发说明和demo。

    这里以C++为例(VS2019)

    大致流程如下,具体实现请参考文档和demo

    首先新建项目,将开发需要的头文件和库文件拷出来放到项目文件中,注意库文件有32和64之分。在属性里面配置头文件和库文件。如图所示

    示例代码,先捕获摄像头图像,再用opencv显示

    #include "MvCameraControl.h"
    #include "opencv2/opencv.hpp"
    
    #include <stdio.h>
    #include <conio.h>
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    bool printDeviceInfo(MV_CC_DEVICE_INFO* hk_device);
    bool hk2cv(MV_FRAME_OUT_INFO_EX* hk_imginfo, unsigned char* data, cv::Mat &src_img);
    
    
    int main(int argv, char** argc) {
    
    
    	int ret = MV_OK;
    	void* handle = NULL;
    
    	MV_CC_DEVICE_INFO_LIST hk_devices;
    	memset(&hk_devices, 0, sizeof(MV_CC_DEVICE_INFO_LIST));
    	ret = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &hk_devices);
    	if (ret != MV_OK) {
    		cout << "enum devices faild!" << endl;
    		return -1;
    	}
    	if (hk_devices.nDeviceNum > 0) {
    		MV_CC_DEVICE_INFO* hk_camera = hk_devices.pDeviceInfo[0];
    		if (printDeviceInfo(hk_camera) == false) {
    			return -1;
    		}
        }
        else {
            cout << "no device found" << endl;
            return -1;
        }
    
        ret = MV_CC_CreateHandle(&handle, hk_devices.pDeviceInfo[0]);
        if (ret != MV_OK) {
            return -1;
        }
        ret = MV_CC_OpenDevice(handle);
        if (ret != MV_OK) {
            return -1;
        }
    
        ret = MV_CC_SetEnumValue(handle, "TriggerMode", 0);
        if (ret != MV_OK) {
            return -1;
        }
    
        MVCC_INTVALUE hk_param;
        memset(&hk_param, 0, sizeof(MVCC_INTVALUE));
        ret = MV_CC_GetIntValue(handle, "PayloadSize", &hk_param);
        if (ret != MV_OK) {
            return -1;
        }
        unsigned int payload_size = hk_param.nCurValue;
    
        // load config
        ret = MV_CC_FeatureLoad(handle, "FeatureFile.ini");
        if (ret != MV_OK){
            cout << "loading config file faild" << endl;
            return -1;
        }
    
    
        // save config
       /* ret = MV_CC_FeatureSave(handle, "FeatureFile.ini");
        if (ret != MV_OK) {
            return -1;
        }*/
    
        // start grabbing images
        ret = MV_CC_StartGrabbing(handle);
        if (ret != MV_OK) {
            cout << "grab image failed!" << endl;
            return -1;
        }
        MV_FRAME_OUT_INFO_EX hk_imginfo;
        memset(&hk_imginfo, 0, sizeof(MV_FRAME_OUT_INFO_EX));
        unsigned char* data = (unsigned char*)malloc(sizeof(unsigned char) * (payload_size));
        if (data == NULL) {
            return -1;
        }
        cv::Mat src_img;
        while (!(_kbhit() && _getch() == 0x1b)) {
            ret = MV_CC_GetOneFrameTimeout(handle, data, payload_size, &hk_imginfo, 1000);
            if (ret != MV_OK) {
                free(data);
                data = NULL;
                return -1;
            }
            if (hk2cv(&hk_imginfo, data, src_img) == false) {
                continue;
            }
            cv::imshow("test", src_img);
            cv::waitKey(30);
        }
        // stop grap image
        ret = MV_CC_StopGrabbing(handle);
        if (ret != MV_OK) {
            return -1;
    
        }
        // close device
        ret = MV_CC_CloseDevice(handle);
        if (ret != MV_OK) {
            return -1;
    
        }
        ret = MV_CC_DestroyHandle(handle);
        if (ret != MV_OK) {
            return -1;
    
        }
        system("pause");
        return 0;
    }
    
    bool printDeviceInfo(MV_CC_DEVICE_INFO* hk_device) {
        if (NULL == hk_device)
        {
            printf("The Pointer of hk_device is NULL!\n");
            return false;
        }
        if (hk_device->nTLayerType == MV_GIGE_DEVICE)
        {
            int nIp1 = ((hk_device->SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24);
            int nIp2 = ((hk_device->SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16);
            int nIp3 = ((hk_device->SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8);
            int nIp4 = (hk_device->SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff);
    
            // print current ip and user defined name
            printf("CurrentIp: %d.%d.%d.%d\n", nIp1, nIp2, nIp3, nIp4);
            printf("UserDefinedName: %s\n\n", hk_device->SpecialInfo.stGigEInfo.chUserDefinedName);
        }
        else if (hk_device->nTLayerType == MV_USB_DEVICE)
        {
            printf("UserDefinedName: %s\n", hk_device->SpecialInfo.stUsb3VInfo.chUserDefinedName);
            printf("Serial Number: %s\n", hk_device->SpecialInfo.stUsb3VInfo.chSerialNumber);
            printf("Device Number: %d\n\n", hk_device->SpecialInfo.stUsb3VInfo.nDeviceNumber);
        }
        else
        {
            printf("Not support.\n");
        }
    
        return true;
    }
    
    bool hk2cv(MV_FRAME_OUT_INFO_EX* hk_imginfo, unsigned char* data, cv::Mat& src_img) {
        cv::Mat cv_img;
        if (hk_imginfo->enPixelType == PixelType_Gvsp_Mono8){
            cv_img = cv::Mat(hk_imginfo->nHeight, hk_imginfo->nWidth, CV_8UC1, data);
        }else if (hk_imginfo->enPixelType == PixelType_Gvsp_RGB8_Packed){
    
            
            for (unsigned int j = 0; j < hk_imginfo->nHeight; j++){
                for (unsigned int i = 0; i < hk_imginfo->nWidth; i++){
                    unsigned char red = data[j * (hk_imginfo->nWidth * 3) + i * 3];
                    data[j * (hk_imginfo->nWidth * 3) + i * 3] = data[j * (hk_imginfo->nWidth * 3) + i * 3 + 2];
                    data[j * (hk_imginfo->nWidth * 3) + i * 3 + 2] = red;
                }
            }
            cv_img = cv::Mat(hk_imginfo->nHeight, hk_imginfo->nWidth, CV_8UC3, data);
        }else{
            printf("unsupported pixel format\n");
            return false;
        }
    
        if (cv_img.data == NULL){
            return false;
        }
        cv_img.copyTo(src_img);
        return true;
    }

    因为每次断电后都要重新设置,这里我取了一个巧,先用客户端配置好参数,然后保存参数,以后每次运行只要加载参数就行了。如果运行提示没有找到dll文件,那么就是你runtime运行环境没有安装,或者没有将安装路径添加到系统环境变量。

     

    正如开头所说的,只是拿来当普通摄像头用,所以代码很简单,后面有机会再深入研究。

    展开全文
  • 相机方面选择了海康威视,网上关于海康威视工业相机SDK的开发资料很少,自己也摸索了一段时间,请教大佬,终于有了些收获,记录下来,方面以后查阅。 目录1.说明1.1软硬件相关配置1.1.1硬件选择1.1.2软件选择1.2...

    最近在做一个项目,涉及到工业相机,需要对其进行二次开发。相机方面选择了海康威视,网上关于海康威视工业相机SDK的开发资料很少,官方文档里面虽然写的是支持C++开发的,但其实是C。自己也摸索了一段时间,请教大佬,终于有了些收获,记录下来,方面以后查阅。

    1.说明

    1.1软硬件相关配置

    1.1.1硬件选择

    工业相机我买的是海康威视的,具体的参数如下:
    在这里插入图片描述
    工业相机资料:https://c109334.hi1718.com/news/201831317343619.html
    在这里插入图片描述
    镜头资料:https://c109334.hi1718.com/news/2018319114719513.html

    1.1.2软件选择

    VS2019+Opencv4.4+QT5.13.2+海康威视SDKMVS_SDK_V3_2_0
    ①VS工程配置Opencv(参考如下博客)
    Opencv4.4文件:
    链接:https://pan.baidu.com/s/1EpOfbkrzkpLyX14w7vINUw
    提取码:7qxl
    【opencv4.3.0教程】01之opencv介绍与配置
    https://blog.csdn.net/shuiyixin/article/details/105998661

    ②VS中安装Qt(配置步骤参考下面两个博客)
    Qt相关文件:
    链接:https://pan.baidu.com/s/1r0gISpfQFuowwA7q2BL3og
    提取码:gll1
    https://blog.csdn.net/visual_eagle/article/details/106236109
    Windows安装qt与VS2019添加QT工具过程
    https://blog.csdn.net/ljb9854/article/details/102600931

    ③安装海康威视提供的MVS客户端操作,我是安装了然后直接就能打开了,若不能打开就设置一下电脑与相机的IP,MVS_SDK_V3_2_0_VC90_Runtime_190626文件是用来更新原来电脑上的MVS版本。
    MVS文件:
    链接:https://pan.baidu.com/s/1RanOEDx-HQ4zJgBpSobAqg
    提取码:d3cy
    参考博客:https://blog.csdn.net/u014779536/article/details/106577273

    1.2关于安防相机与工业相机

    一开始在网上搜索相关海康威视SDK二次开发的时候,发现有很多的资料,然后就对着开始操作,自己琢磨了好久激活相机修改密码等等,发现都无济于事。后来一问客服才知道,那些是安防相机的相关资料,不是工业相机。
    嗯,,,心态炸裂。。。
    关于安防相机和工业相机(网络设备SDK和工业相机SDK)的区别,可以自行百度,这里提个醒防止走入误区。
    安防相机买回来是需要激活重新设置密码的,工业相机买回来直接用。
    这里贴出关于安防相机SDK二次开发的资料,给有需要的人做个参考。

    关于安防相机的SDK相关资料下载:https://www.hikvision.com/cn/
    这些SDK和工业相机的完全不一样,都不用,网上大部分的都是海康安防相机的SDK开发资料,什么实时预览&抓图&云台控制等等。
    关于安防相机的SDK开发资料:
    https://blog.csdn.net/o_ha_yo_yepeng/article/details/79537452
    https://blog.csdn.net/o_ha_yo_yepeng/article/details/79825648
    https://www.jianshu.com/p/1368c8ea24ff
    https://blog.csdn.net/qq_15029743/article/details/79733960
    https://www.bilibili.com/video/BV1ui4y1t72x?t=1326

    2.相关资料与官方文档

    2.1官方文档

    买了相机之后,问下客服要一下MVS软件,安装之后,关于软件的使用说明和IP设置说明参考如下文件,关于如何查看相机IP等等,
    千兆网口工业面阵相机用户手册V3.0.1
    海康威视相机IP设置说明
    链接:https://pan.baidu.com/s/11FD3GIhz5E1O5-vJ2u-_tA
    提取码:n8oa

    海康威视工业相机官网,里面有关于工业相机的介绍及客户端MVS软件等等。
    https://www.hikrobotics.com/

    2.2网上相关的资料

    ①《海康威视工业相机SDK二次开发》这篇是MFC的,且官方提供的界面功能软件都是基于MFC的,配置好环境可以直接打开使用。
    https://blog.csdn.net/weixin_47364204/article/details/108537518

    ②《C++调用海康相机SDK采集图像(C++\QT Creator\OpenCV\线程\接口)》
    这篇是基于QTCreater的,没有在VS环境中,源码我下载下来了,给有需要的人。
    链接:https://pan.baidu.com/s/1FsJg1hDCBdoJ_8hye6j1rw
    提取码:z94k
    https://blog.csdn.net/biggestcherry/article/details/106154321

    3.海康威视工业相机SDK官方例程的修改

    3.1环境配置

    PS:不管运行海康威视的哪个例程,都需要先配置下环境
    在VS项目中配置opencv和mvs的动态链接库等(用到Opencv的话)
    ①在VS中配置Opencv
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    ②在VS中配置MVS
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    3.2官方例程

    ConnectSpecCamera.cpp

    在这里插入图片描述
    功能:通过ip地址连接相机
    该示例程序说明了如何通过ip地址连接网口相机。通过输入需要连接的相机ip(Camera Ip)和相机对应的网卡ip(Export Ip)来连接相机,输入的格式为xx.xx.xx.xx。
    修改的地方:
    在这里插入图片描述
    一开始官方例程中的scanf会报错说这个函数不安全,这不是错误但在高版本VS下会认为这是个错误,解决方法有二:在项目设置中增加一行预处理定义可以自行百度。或者选择修改为scanf_s。
    我选择改成scanf_s,且后面还要加个参数20,表示输入的最大字符数大小,ip地址加上三个点是15个字符,这里填个20。
    参考:https://baike.baidu.com/item/scanf_s/443572?fr=aladdin
    修改后的源码如下:

    #include <stdio.h>
    #include <Windows.h>
    #include <process.h>
    #include <conio.h>
    #include "MvCameraControl.h"
    
    bool g_bExit = false;
    unsigned int g_nPayloadSize = 0;
    
    // ch:等待按键输入 | en:Wait for key press
    void WaitForKeyPress(void)
    {
        while (!_kbhit())
        {
            Sleep(10);
        }
        _getch();
    }
    
    static  unsigned int __stdcall WorkThread(void* pUser)
    {
        int nRet = MV_OK;
    
        MV_FRAME_OUT_INFO_EX stImageInfo = { 0 };
        memset(&stImageInfo, 0, sizeof(MV_FRAME_OUT_INFO_EX));
        unsigned char* pData = (unsigned char*)malloc(sizeof(unsigned char) * (g_nPayloadSize));
        unsigned int nDataSize = g_nPayloadSize;
    
        while (1)
        {
            nRet = MV_CC_GetOneFrameTimeout(pUser, pData, nDataSize, &stImageInfo, 1000);
            if (nRet == MV_OK)
            {
                printf("Get One Frame: Width[%d], Height[%d], nFrameNum[%d]\n",
                    stImageInfo.nWidth, stImageInfo.nHeight, stImageInfo.nFrameNum);
            }
            else
            {
                printf("No data[0x%x]\n", nRet);
                break;
            }
    
            if (g_bExit)
            {
                break;
            }
        }
    
        free(pData);
        return 0;
    }
    
    int main()
    {
        int nRet = MV_OK;
        void* handle = NULL;
        MV_CC_DEVICE_INFO stDevInfo = { 0 };
        MV_GIGE_DEVICE_INFO stGigEDev = { 0 };
    
        // ch:需要连接的相机ip(根据实际填充) | en:The camera IP that needs to be connected (based on actual padding)
        printf("Please input Current Camera Ip : ");
        char nCurrentIp[128];
        scanf_s("%s", &nCurrentIp, 20);
        // ch:相机对应的网卡ip(根据实际填充) | en:The pc IP that needs to be connected (based on actual padding)
        printf("Please input Net Export Ip : ");
        char nNetExport[128];
        scanf_s("%s", &nNetExport, 20);
    
    
        unsigned int nIp1, nIp2, nIp3, nIp4, nIp;
    
        sscanf_s(nCurrentIp, "%d.%d.%d.%d", &nIp1, &nIp2, &nIp3, &nIp4);
        nIp = (nIp1 << 24) | (nIp2 << 16) | (nIp3 << 8) | nIp4;
        stGigEDev.nCurrentIp = nIp;
    
        sscanf_s(nNetExport, "%d.%d.%d.%d", &nIp1, &nIp2, &nIp3, &nIp4);
        nIp = (nIp1 << 24) | (nIp2 << 16) | (nIp3 << 8) | nIp4;
        stGigEDev.nNetExport = nIp;
    
        stDevInfo.nTLayerType = MV_GIGE_DEVICE;// ch:仅支持GigE相机 | en:Only support GigE camera
        stDevInfo.SpecialInfo.stGigEInfo = stGigEDev;
    
        do
        {
            // ch:选择设备并创建句柄 | en:Select device and create handle
            nRet = MV_CC_CreateHandle(&handle, &stDevInfo);
            if (MV_OK != nRet)
            {
                printf("Create Handle fail! nRet[0x%x]\n", nRet);
                break;
            }
    
            // ch:打开设备 | en:Open device
            nRet = MV_CC_OpenDevice(handle);
            if (MV_OK != nRet)
            {
                printf("Open Device fail! nRet [0x%x]\n", nRet);
                break;
            }
    
            // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)
            if (stDevInfo.nTLayerType == MV_GIGE_DEVICE)
            {
                int nPacketSize = MV_CC_GetOptimalPacketSize(handle);
                if (nPacketSize > 0)
                {
                    nRet = MV_CC_SetIntValue(handle, "GevSCPSPacketSize", nPacketSize);
                    if (nRet != MV_OK)
                    {
                        printf("Warning: Set Packet Size fail nRet [0x%x]!", nRet);
                    }
                }
                else
                {
                    printf("Warning: Get Packet Size fail nRet [0x%x]!", nPacketSize);
                }
            }
    
            // ch:设置触发模式为off | en:Set trigger mode as off
            nRet = MV_CC_SetEnumValue(handle, "TriggerMode", MV_TRIGGER_MODE_OFF);
            if (MV_OK != nRet)
            {
                printf("Set Trigger Mode fail! nRet [0x%x]\n", nRet);
                break;
            }
    
            // 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);
                break;
            }
            g_nPayloadSize = stParam.nCurValue;
    
            // ch:开始取流 | en:Start grab image
            nRet = MV_CC_StartGrabbing(handle);
            if (MV_OK != nRet)
            {
                printf("Start Grabbing fail! nRet [0x%x]\n", nRet);
                break;
            }
    
            unsigned int nThreadID = 0;
            void* hThreadHandle = (void*)_beginthreadex(NULL, 0, WorkThread, handle, 0, &nThreadID);
            if (NULL == hThreadHandle)
            {
                break;
            }
    
            printf("Press a key to stop grabbing.\n");
            WaitForKeyPress();
    
            g_bExit = true;
            Sleep(1000);
    
            // ch:停止取流 | en:Stop grab image
            nRet = MV_CC_StopGrabbing(handle);
            if (MV_OK != nRet)
            {
                printf("Stop Grabbing fail! nRet [0x%x]\n", nRet);
                break;
            }
    
            // ch:关闭设备 | en:Close device
            nRet = MV_CC_CloseDevice(handle);
            if (MV_OK != nRet)
            {
                printf("Close Device fail! nRet [0x%x]\n", nRet);
                break;
            }
    
            // ch:销毁句柄 | en:Destroy handle
            nRet = MV_CC_DestroyHandle(handle);
            if (MV_OK != nRet)
            {
                printf("Destroy Handle fail! nRet [0x%x]\n", nRet);
                break;
            }
            handle = NULL;
        } while (0);
    
    
        if (nRet != MV_OK)
        {
            if (handle != NULL)
            {
                MV_CC_DestroyHandle(handle);
                handle = NULL;
            }
        }
    
        printf("Press a key to exit.\n");
        WaitForKeyPress();
    
        return 0;
    }
    

    运行效果:
    将工业相机接上电源和连接电脑,通过打开MVS客户端软件,知道你电脑网口的IP地址和工业相机的IP地址:
    在这里插入图片描述
    在这里插入图片描述
    表示相机正在采集中。。。

    GrabImage_Display.cpp

    在这里插入图片描述
    功能:图像采集并显示
    该示例程序演示如何取图并显示取到的每一帧图像。
    修改的地方
    一开始官方例程中会报错"const char"类型的实参与"LPCWSTR"类型的形参不兼容和不能将"const char"类型的值分配到"LPCWSTR"类型的实体,解决办法如下:
    项目——项目属性——常规——项目默认值——字符集,把字符集设为未设置,确定。
    在这里插入图片描述
    源码如下:

    #include <stdio.h>
    #include <process.h>
    #include <conio.h>
    #include "windows.h"
    #include "MvCameraControl.h"
    
    HWND g_hwnd = NULL;
    bool g_bExit = false;
    unsigned int g_nPayloadSize = 0;
    
    // ch:等待按键输入 | en:Wait for key press
    void WaitForKeyPress(void)
    {
        while (!_kbhit())
        {
            Sleep(10);
        }
        _getch();
    }
    
    bool PrintDeviceInfo(MV_CC_DEVICE_INFO* pstMVDevInfo)
    {
        if (NULL == pstMVDevInfo)
        {
            printf("The Pointer of pstMVDevInfo is NULL!\n");
            return false;
        }
        if (pstMVDevInfo->nTLayerType == MV_GIGE_DEVICE)
        {
            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("CurrentIp: %d.%d.%d.%d\n", nIp1, nIp2, nIp3, nIp4);
            printf("UserDefinedName: %s\n\n", pstMVDevInfo->SpecialInfo.stGigEInfo.chUserDefinedName);
        }
        else if (pstMVDevInfo->nTLayerType == MV_USB_DEVICE)
        {
            printf("UserDefinedName: %s\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chUserDefinedName);
            printf("Serial Number: %s\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chSerialNumber);
            printf("Device Number: %d\n\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.nDeviceNumber);
        }
        else
        {
            printf("Not support.\n");
        }
    
        return true;
    }
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
        switch (msg)
        {
        case WM_DESTROY:
            PostQuitMessage(0);
            g_hwnd = NULL;
            break;
        }
    
        return DefWindowProc(hWnd, msg, wParam, lParam);
    }
    
    static  unsigned int __stdcall CreateRenderWindow(void* pUser)
    {
        HINSTANCE hInstance = ::GetModuleHandle(NULL);              //获取应用程序的模块句柄
        WNDCLASSEX wc;
        wc.cbSize = sizeof(wc);
        wc.style = CS_HREDRAW | CS_VREDRAW;              //窗口的风格
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hInstance = hInstance;
        wc.hIcon = ::LoadIcon(NULL, IDI_APPLICATION);    //图标风格
        wc.hIconSm = ::LoadIcon(NULL, IDI_APPLICATION);
        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);          //背景色
        wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);        //鼠标风格
        wc.lpfnWndProc = WndProc;                              //自定义消息处理函数
        wc.lpszMenuName = NULL;
        wc.lpszClassName = "RenderWindow";                       //该窗口类的名称
    
        if (!RegisterClassEx(&wc))
        {
            return 0;
        }
    
        DWORD style = WS_OVERLAPPEDWINDOW;
        DWORD styleEx = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
        RECT rect = { 0, 0, 640, 480 };
    
        AdjustWindowRectEx(&rect, style, false, styleEx);
    
        HWND hWnd = CreateWindowEx(styleEx, "RenderWindow", "Display", style, 0, 0,
            rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, hInstance, NULL);
        if (hWnd == NULL)
        {
            return 0;
        }
    
        ::UpdateWindow(hWnd);
        ::ShowWindow(hWnd, SW_SHOW);
    
        g_hwnd = hWnd;
    
        MSG msg = { 0 };
        while (msg.message != WM_QUIT)
        {
            if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
    
        return 0;
    }
    
    static  unsigned int __stdcall WorkThread(void* pUser)
    {
        int nRet = MV_OK;
    
        MV_FRAME_OUT_INFO_EX stImageInfo = { 0 };
        MV_DISPLAY_FRAME_INFO stDisplayInfo = { 0 };
        unsigned char* pData = (unsigned char*)malloc(sizeof(unsigned char) * (g_nPayloadSize));
        if (pData == NULL)
        {
            return 0;
        }
        unsigned int nDataSize = g_nPayloadSize;
    
        while (1)
        {
            nRet = MV_CC_GetOneFrameTimeout(pUser, pData, nDataSize, &stImageInfo, 1000);
            if (nRet == MV_OK)
            {
                printf("Get One Frame: Width[%d], Height[%d], nFrameNum[%d]\n",
                    stImageInfo.nWidth, stImageInfo.nHeight, stImageInfo.nFrameNum);
    
                if (g_hwnd)
                {
                    stDisplayInfo.hWnd = g_hwnd;
                    stDisplayInfo.pData = pData;
                    stDisplayInfo.nDataLen = stImageInfo.nFrameLen;
                    stDisplayInfo.nWidth = stImageInfo.nWidth;
                    stDisplayInfo.nHeight = stImageInfo.nHeight;
                    stDisplayInfo.enPixelType = stImageInfo.enPixelType;
    
                    MV_CC_DisplayOneFrame(pUser, &stDisplayInfo);
                }
            }
            else
            {
                printf("No data[0x%x]\n", nRet);
            }
            if (g_bExit)
            {
                break;
            }
        }
    
        free(pData);
    
        return 0;
    }
    
    int main()
    {
        int nRet = MV_OK;
        void* handle = NULL;
    
        do
        {
            // ch:枚举设备 | en:Enum device
            MV_CC_DEVICE_INFO_LIST stDeviceList = { 0 };
            nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &stDeviceList);
            if (MV_OK != nRet)
            {
                printf("Enum Devices fail! nRet [0x%x]\n", nRet);
                break;
            }
    
            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);
                }
            }
            else
            {
                printf("Find No Devices!\n");
                break;
            }
    
            printf("Please Input camera index:");
            unsigned int nIndex = 0;
            scanf_s("%d", &nIndex);
    
            if (nIndex >= stDeviceList.nDeviceNum)
            {
                printf("Input error!\n");
                break;
            }
    
            // ch:选择设备并创建句柄 | en:Select device and create handle
            nRet = MV_CC_CreateHandle(&handle, stDeviceList.pDeviceInfo[nIndex]);
            if (MV_OK != nRet)
            {
                printf("Create Handle fail! nRet [0x%x]\n", nRet);
                break;
            }
    
            // ch:打开设备 | en:Open device
            nRet = MV_CC_OpenDevice(handle);
            if (MV_OK != nRet)
            {
                printf("Open Device fail! nRet [0x%x]\n", nRet);
                break;
            }
    
            // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)
            if (stDeviceList.pDeviceInfo[nIndex]->nTLayerType == MV_GIGE_DEVICE)
            {
                int nPacketSize = MV_CC_GetOptimalPacketSize(handle);
                if (nPacketSize > 0)
                {
                    nRet = MV_CC_SetIntValue(handle, "GevSCPSPacketSize", nPacketSize);
                    if (nRet != MV_OK)
                    {
                        printf("Warning: Set Packet Size fail nRet [0x%x]!", nRet);
                    }
                }
                else
                {
                    printf("Warning: Get Packet Size fail nRet [0x%x]!", nPacketSize);
                }
            }
    
            // ch:设置触发模式为off | 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);
                break;
            }
    
            // ch:获取数据包大小 | en:Get payload size
            MVCC_INTVALUE stParam = { 0 };
            nRet = MV_CC_GetIntValue(handle, "PayloadSize", &stParam);
            if (MV_OK != nRet)
            {
                printf("Get PayloadSize fail! nRet [0x%x]\n", nRet);
                break;
            }
            g_nPayloadSize = stParam.nCurValue;
    
            unsigned int nThreadID = 0;
            void* hCreateWindow = (void*)_beginthreadex(NULL, 0, CreateRenderWindow, handle, 0, &nThreadID);
            if (NULL == hCreateWindow)
            {
                break;
            }
    
            // ch:开始取流 | en:Start grab image
            nRet = MV_CC_StartGrabbing(handle);
            if (MV_OK != nRet)
            {
                printf("Start Grabbing fail! nRet [0x%x]\n", nRet);
                break;
            }
    
            nThreadID = 0;
            void* hThreadHandle = (void*)_beginthreadex(NULL, 0, WorkThread, handle, 0, &nThreadID);
            if (NULL == hThreadHandle)
            {
                break;
            }
    
            printf("Press a key to stop grabbing.\n");
            WaitForKeyPress();
    
            g_bExit = true;
            WaitForSingleObject(hThreadHandle, INFINITE);
            CloseHandle(hThreadHandle);
    
            // ch:停止取流 | en:Stop grab image
            nRet = MV_CC_StopGrabbing(handle);
            if (MV_OK != nRet)
            {
                printf("Stop Grabbing fail! nRet [0x%x]\n", nRet);
                break;
            }
    
            // ch:关闭设备 | Close device
            nRet = MV_CC_CloseDevice(handle);
            if (MV_OK != nRet)
            {
                printf("ClosDevice fail! nRet [0x%x]\n", nRet);
                break;
            }
    
            // ch:销毁句柄 | Destroy handle
            nRet = MV_CC_DestroyHandle(handle);
            if (MV_OK != nRet)
            {
                printf("Destroy Handle fail! nRet [0x%x]\n", nRet);
                break;
            }
        } while (0);
    
    
        if (nRet != MV_OK)
        {
            if (handle != NULL)
            {
                MV_CC_DestroyHandle(handle);
                handle = NULL;
            }
        }
    
        printf("Press a key to exit.\n");
        WaitForKeyPress();
    
        return 0;
    }
    

    运行效果:
    在这里插入图片描述
    在这里插入图片描述

    3.3关于MVS中的资料

    在这里插入图片描述

    D:\MVS\MVS\Development\Documentations 里面有各种语言及相关的SDK开发指南,如果是C++,也看《工业相机SDK开发指南 C》,里面关于工业相机的各种操作如取流、图像采集、图像处理等等都有详细的API调用,需要什么,就去这个文档中去查阅。
    在这里插入图片描述
    D:\MVS\MVS\Development\Samples\VC\VS 里面是VS项目的开发示例,前面六个是已经写好的MFC界面程序,具体的操控看示例程序说明VS2008.pdf,SimpleSamples中的是一个个小示例,在《工业相机SDK开发指南 C》里面有讲解。

    展开全文
  • 该文档是官方海康威视工业相机的使用手册,介绍了海康系列面阵相机的详细使用。
  • 海康威视工业相机SDK二次开发

    万次阅读 多人点赞 2020-09-11 17:53:56
    海康威视工业相机SDK二次开发 好气,第一次写文章,结果没不小心保存关掉,什么都没了。 本人是一名在读研究生,被导师分配了做项目中海康工业相机的二次开发。实现8相机同时打开视频流,分相机采图保存到各自的...
  • 个人整理的海康威视工业视觉500万像素工业相机的相关参数,有需要的同学可以下载,省去你们额外查询的时间。
  • 海康威视工业相机IP设置说明

    千次阅读 2021-10-20 18:28:52
    2.刷新出所使用的相机型号时,鼠标放在相机位置,鼠标左键点击一下,选择修改IP 3.选择静态IP----->设置与本机IP同一网段(最后一位不同)------>点击确认 4.点击此处进行相机连接 还.
  • 海康威视工业相机驱动下载地址

    千次阅读 2021-05-13 11:47:06
    https://www.hikrobotics.com/machinevision/service/download?module=0
  • QT + C++ + 海康威视工业相机二次开发 2021-05-12

    千次阅读 热门讨论 2021-05-12 10:25:08
    1.了解海康威视工业相机 本人学习参考的是:boss_dog的博客,里面有详细的分析相机的数据,各种相机的区别,在VS中部署SDK的环境变量以及官方例程. 1.1.下载SDK 海康威视的工业相机二次开发首先是需要在...
  • 1、概述:工业相机SDK是用于控制相机的一个独立组件,支持获取实时图像数据、配置参数、对图像进行后续处理等功能。工业相机SDK兼容GigE Vision协议、USB3 Vision协议、Camera Link协议、CoaXPress协议,目前支持...
  • 目前缺芯的大环境也影响到工业相机上面了,使用支持国产海康机器人的工业相机进行视觉开发是不错的替代方案。价格交期很是感人呐! 参考文章python调用海康工业相机并用opencv显示(整体实现) 博主写的很全面非常...
  • 1海康威视相机demo和PDF说明\Samples\DirectShow\DirectShowDisplay\lib\x64\uuid.lib4.73 MB2018/12/29 10:59:062海康威视相机demo和PDF说明\Documentations\示例程序说明VB.pdf1.24 MB2018/12/29 10:58:593...
  • 该文档是海康威视工业面阵相机的用户手册,可根据此手册进行海康相机的配置工作。
  • Linux下海康威视工业相机的二次开发,参数设置最详细教程
  • 相机到了,这也是我的第一次使用相机,然后呢...我们使用的是海康的工业相机,先了解一下什么是工业相机去! 首先我们在官网上下载客户端和sdk,然后我下载的是arrch64的,这个是网站:https://www.hikrobotics.com/ma
  • 2021年最新的海康威视IP相机选型手册,英文版本,但不影响阅读。
  • 本文章开头会先讲一下如何找到SDK包和demo,功能的实现我会直接用平时常用的DLL以及根据海康威视给的demo封装好的常用功能类,这些都会分享到文末的链接中。注:halcon虽然有读取相...
  • Qt联合海康威视工业相机采集,在线转Halcon变量并显示(支持黑白相机和彩色相机)。 ID:77100668685372998大周周ld
  • 下载得到如下压缩包,解压有一个安装包,安装,SDK安装路径下Development目录下: 详细说明可看Documentations目录下开发指南: 工业相机Windows版本SDK安装包包含了SDK接口说明和示例部分及相机驱动两个部分:相机...
  • 有的是彩色相机,采集到的图像是三通道的,有的是黑白相机图像是单通道的。 函数形式: void cvCvtColor( const CvArr* src, CvArr* dst, int code ); 功能:cvCvtColor是opencv库中的一个函数,实现色彩空间转换。 ...
  • 记录自己在Linux环境下对海康威视工业相机SDK进行的二次开发(QT+CMake+OpenCV+海康SDK),提供源码。
  • 海康相机全系列面阵相机手册,选型指南,相机参数设定,功能详解
  • 海康威视工业相机SDK二次开发软件及demo示例,包括c,c++,c#,Python等,以及相关的示例程序说明PDF文件。
  • VS2017+海康威视工业相机调用查找不到设备的问题 问题;按照网上安装好了MVS,配置了环境变量,在VS2017里面也配置了MVS,然后调用安装包里的示例代码也没有出错,但最后运行的时候总是提示找不到设备。(我重新安装...
  • 该文档是海康威视系列相机的使用手册,介绍的是关于工业线阵相机的详细使用说明,用户可根据此手册进行海康线阵相机的详细配置。
  • 下载海康威视工业相机的软件;地址(https://www.hikrobotics.com/service/soft.htm?type=1) 2.检查是否已经有如下两个环境变量,如果没有自行添加; 3.在VS中添加引用 MvCameraControl.Net.dll——MVS安装路径:C:...
  • 本文接上次的博客海康威视工业相机SDK二次开发(VS+Opencv+QT+海康SDK+C++)(一),上个博客中并未用到QT,本文介绍项目内容及源码,供大家参考。 由于我的项目中是用海康相机作为拍照的一个中介,重点是在目标...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 679
精华内容 271
关键字:

海康威视工业相机