Linux环境中对海康威视工业相机SDK进行二次开发(QT+CMake+Opencv+海康SDK)

  • 关于在Windows环境中对海康威视工业相机SDK进行二次开发的话,可以参考这两篇博客。
    海康威视工业相机SDK二次开发(VS+Opencv+QT+海康SDK+C++)(一)
    海康威视工业相机SDK二次开发(VS+Opencv+QT+海康SDK+C++)(二)

  • 然后最近因为××原因,又要转到Linux环境下对海康威视工业相机的SDK进行二次开发使用,还是在虚拟机中搞的。。。

  • 之前一直用的都是Visual Studio编译器,虽然有过Qt的界面开发经验,但都是借助VS中的Qt 设计师,这次在Ubuntu16.04系统中用Qt Creator进行开发,编译用CMake完成。

目录

  • 1.关于CMake编译工具与项目构建
    • 1.1 C++程序编译过程
    • 1.2 Make和Makefile的关系
    • 1.3 CMake和CMakeLists的关系
    • 1.4 关于CMakeLists的编写
  • 2.源码
    • 说明:
      • ①关于SDK的源码版本
      • ②关于彩色和黑白的疑问
      • ③关于Linux中的路径问题
      • ④关于曝光和增益的理解
      • ⑤在QLineEdit中使用setValidator设置区间
    • 2.1 CMakeLists.txt
    • 2.2 MvCamera.h
    • 2.3 mythread.h
    • 2.4 widget.h
    • 2.5 main.cpp
    • 2.6 MvCamera.cpp
    • 2.7 mythread.cpp
    • 2.8 widget.cpp
    • 2.9 widget.ui
    • 2.10 运行效果

1.关于CMake编译工具与项目构建

(由于之前一直都没用过CMake对项目进行管理,特别感谢这篇文章,写的不错。)https://mp.weixin.qq.com/s/WglXaNNDETKKu6zICRYswQ)

1.1 C++程序编译过程

  编译分为四个过程:预处理阶段、编译阶段、汇编阶段、链接阶段。

  •   预处理阶段:处理以#开头的指令,生成.i预编译文件。
  •   编译阶段:将源码的.cpp文件翻译成.s汇编代码。
  •   汇编阶段:将汇编代码.s翻译成机器指令.o文件。
  •   链接阶段:对于汇编阶段生成的.o文件,并不会立刻执行,因为可能出现在源码的.cpp文件中引用了另一个.cpp文件中的东西,则链接的目的就是将这些文件对应的目标文件连接成一个整体,从而生成可执行的程序.exe文件。

1.2 Make和Makefile的关系

  当源文件比较多时,一般不适合直接通过gcc来编译代码,这时就需要一个自动化的编译工具。

  Make(GNU Make)是一个自动化软件,用于将源代码文件编译为可执行的二进制文件从而完成自动化编译。Make工具编译的时候需要Makefile文件提供编译规则,Makefile定义了一系列的编译规则,包括编译的先后顺序,哪些文件需要重新编译等操作。

  利用Make工具可以自动完成编译工作,如果修改了某几个源文件,则只重新编译这几个源文件。如果某个头文件被修改了,则重新编译所有包含该头文件的源文件。利用这种自动编译极大地提高了开发效率,避免了不必要的重新编译。

1.3 CMake和CMakeLists的关系

  简单来说,CMake强大在其是跨平台的项目管理工具,它能够输出各种Makefile文件或工程文件。例如,在Windows环境下它能生成Visual Studio的工程,在Linux环境下它会生成Makefile文件。也就是说,Cmake能够按照同一个抽象规则为各个编译器生成工程文件,从而忽略不同平台的差异,抽象成为一个一致的环境。

  CMake命令的执行所按照的规则也就是由CMakeLists.txt文件编写的。
Linux环境中对海康威视工业相机SDK进行二次开发(QT+CMake+Opencv+海康SDK)_第1张图片
  通过CMake工具可以读入所有源文件,自动生成Makefile。开发的基本流程如下:

  • 编写源文件
  • 编写CMakeLists.txt
  • 由CMake根据CMakeLists.txt生成Makefile
  • 由Make根据Makefile,调用gcc生成可执行文件
    Linux环境中对海康威视工业相机SDK进行二次开发(QT+CMake+Opencv+海康SDK)_第2张图片

1.4 关于CMakeLists的编写

这篇博文写的很详细:https://blog.csdn.net/afei__/article/details/81201039

  CMakeLists.txt的编写主要包含以下步骤

  • cmake_minimum_required(VERSION 2.8.0):用于指定cmake所需最低版本;
  • project(Project) :用于指定项目名称;
  • include_directories() :用于包含头文件目录;
  • aux_source_directory(src dir_srcs):用于包含源文件目录;
  • set(TEST_MATH) :用于设置环境变量,编译用到的源文件全部都要放到这里;
  • add_executable(${PROJECT_NAME} ${TEST_MATH}):用于添加要编译的可执行文件;
  • target_link_libraries(${PROJECT_NAME} m):用于添加可执行文件所需要的库;

  link_libraries和target_link_libraries的区别:

  • link_libraries是指定要链接的库文件路径。自己生成的库文件可以用该指令指定目录的路径以便工程能够找到。
  • target_link_libraries是将目标文件与库文件进行链接,可以指定动态库/静态库,如果只提供库名称,系统会根据链接库目录搜索xxx.so 或者 xxx.a 文件;或者指定给出全路径。

资料参考:
CMAKE find_path和find_library命令的用法和解释
QT 使用cmakelist.txt 导入opencv
CMakeLists.txt添加opencv库注意事项
CMakeList.txt设置OpenCv路径
常用库(QT,PCL,OPENCV,EIGEN3等)的cmakelists.txt模板

2.源码

说明:

①关于SDK的源码版本

  •   一开始我是直接复制的之前在Windows环境下开发的相关代码,经过几个SDK的源码对比,发现还是有一点不一样,有些API可能改名或者就没有了,如果某些功能你在Windows中能够实现,到了Linux环境中却实现不了了,可以修改CameraParams.hMvCameraControl.hMvErrorDefine.hPixelType.h这几个文件,以满足项目的需求。

②关于彩色和黑白的疑问

  •   之前在Windows环境下开发用的是海康的彩色相机,这次在Linux环境下用的是海康的黑白相机,我直接移植了之前的代码并配置了相关环境,发现在Qt中通过QLabel显示的图像和相机实际拍到的不一样(QLabel中显示的图像很模糊),一开始以为是彩色和黑白的区别,但通过保存图像的按钮发现保存的图片没什么问题,那就是QLabel的显示问题了。
    后来查了下QImage图像格式解读:(我也没看懂哪里是灰度图像的格式)https://blog.csdn.net/weixin_39485901/article/details/88047291
    最后将QImage::Format_Indexed8改成了QImage::Format_RGB888,问题就解决了。(这里有个疑问,QImage::Format_RGB888 图像存储使用8-8-8 24位RGB格式,这里明显是彩色图像3个通道的,而黑白的海康威视工业相机我经过打印确认通道是1个,那为什么用QImage::Format_RGB888就可以呢???不理解,如有大佬知晓希望告知。)

③关于Linux中的路径问题

  • 在设置背景图时,我默认Windows环境中的当前工程目录为相对路径,就想弄个图片作为背景图,发现不是同一个路径。
  • 比如我的项目名称是sdkCamera,则该工程项目的文件夹是build-sdkCamera-Desktop_Qt_5_12_9_GCC_64bit-Debug

④关于曝光和增益的理解

  • 曝光和增益是直接控制传感器(CCD/CMOS)上读出来的数据,是要优先调节的,以调节曝光时间为主。在不过曝的前提下,增加曝光时间可以增加信噪比,使图像清晰。当然,对于很弱的信号,曝光也不能无限增加,因为随着曝光时间的增加,噪音也会积累, 曝光补偿就是增加拍摄时的曝光量。
  • 增益一般只是在信号弱,但不想增加曝光时间的情况下使用,一般相机增益都产生很大噪音。工业相机在不同增益时图像的成像质量不一样,增益越小,噪点越小;增益越大,噪点越多,特别是在暗处。数码相机的ISO就是这里说的增益,增大ISO,是增加感光器件对光的灵敏度。高感光度对低光照灵敏,同时对噪杂信号也灵敏,信噪比小,所以高感光度噪点也多(可利用图片软件的降噪功能减轻或去除)。
    调节亮度增益说白了就是改变ISO,改变CMOS传感器的感光性能,但是会影响到画质。调节曝光补偿则是为了改变快门速度,不改变ISO不会影响画质。

⑤在QLineEdit中使用setValidator设置区间

参考:https://blog.csdn.net/qq78442761/article/details/80276764/

2.1 CMakeLists.txt

对于一个习惯了用Visual Studio编译器编程、调试、配置环境的人,一开始转到CMake,编写CMakeLists.txt文件时,我是一脸懵逼的,还要用Qt Creator进行调试编译。。。
有幸看了上面一些大佬写的关于CMakeLists.txt文件的编写,再对照当初在Visual Studio中的环境配置过程,慢慢的自己也配置成功了海康威视SDK和OpenCV。

Windows下的MVS配置
附加包含目录:D:MVS\MVS\Development\Includes
附加库目录:D:MVS\MVS\Development\Libraries\win64
附加依赖项:MvCameraControl.lib
工程项目添加:MvCamera.h、MvCamera.cpp

Windows下的OpenCV配置
包含目录:D:\opencv4.4\opencv\build\include\opencv2
D:\opencv4.4\opencv\build\include
库目录: D:\opencv4.4\opencv\build\x64\vc15\lib
链接器: opencv_world440d.lib
opencv_world440.lib

这是我的CMakeLists.txt源文件:

cmake_minimum_required(VERSION 3.5)

project(aubo_camera LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set( CMAKE_CXX_FLAGS "-std=c++11" )

set(OpenCV_DIR /home/aubo/opencv-4.4.0/build)
find_package( OpenCV 4 REQUIRED)
include_directories( ${OpenCV_INCLUDE_DIRS} )

# QtCreator supports the following variables for Android, which are identical to qmake Android variables.
# Check http://doc.qt.io/qt-5/deployment-android.html for more information.
# They need to be set before the find_package(Qt5 ...) call.

#if(ANDROID)
#    set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
#    if (ANDROID_ABI STREQUAL "armeabi-v7a")
#        set(ANDROID_EXTRA_LIBS
#            ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so
#            ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so)
#    endif()
#endif()

find_package(Qt5 COMPONENTS Widgets REQUIRED)

if(ANDROID)
  add_library(aubo_camera SHARED
      main.cpp
      widget.cpp
      MvCamera.cpp
      mythread.cpp
      mythread.h
      MvCamera.h
      widget.h
      widget.ui
  )
else()
  add_executable(aubo_camera
      main.cpp
      widget.cpp
      MvCamera.cpp
      mythread.cpp
      mythread.h
      MvCamera.h
      widget.h
      widget.ui
  )
endif()

find_library(CAMERA_LIB libMvCameraControl.so libMvCameraControl.so.3.1.3.0 /home/aubo/MVS-2.1.0_x86_64_20201228/MVS/lib/64/)
find_path(MVS_PATH CameraParams.h MvCameraControl.h MvErrorDefine.h PixelType.h /home/aubo/MVS-2.1.0_x86_64_20201228/MVS/include)
INCLUDE_DIRECTORIES(${MVS_PATH})

target_link_libraries(aubo_camera PRIVATE Qt5::Widgets ${CAMERA_LIB} ${OpenCV_LIBS})

关于Linux环境下海康威视SDK的下载安装和OpenCV的源码编译,请移步于:
VMware虚拟机中Ubuntu16.04系统下通过MVS运行海康威视工业相机
VMware虚拟机中Ubuntu16.04系统下进行OpenCV4.4的安装编译

下面在CMakeList.txt中的文件安装目录根据自己的实际安装位置为准。
Linux环境中对海康威视工业相机SDK进行二次开发(QT+CMake+Opencv+海康SDK)_第3张图片
在这里插入图片描述
Linux环境中对海康威视工业相机SDK进行二次开发(QT+CMake+Opencv+海康SDK)_第4张图片
Linux环境中对海康威视工业相机SDK进行二次开发(QT+CMake+Opencv+海康SDK)_第5张图片

2.2 MvCamera.h

#ifndef MVCAMERA_H
#define MVCAMERA_H

#include "MvCameraControl.h"
#include 

#ifndef MV_NULL
#define MV_NULL 0
#endif

#include "opencv2/opencv.hpp"
#include "opencv2/imgproc/types_c.h"

class CMvCamera
{
public:
    CMvCamera();
    ~CMvCamera();

    // ch:获取SDK版本号 | en:Get SDK Version
    static int GetSDKVersion();

    // ch:枚举设备 | en:Enumerate Device
    static int EnumDevices(unsigned int nTLayerType,
                           MV_CC_DEVICE_INFO_LIST *pstDevList);

    // ch:判断设备是否可达 | en:Is the device accessible
    static bool IsDeviceAccessible(MV_CC_DEVICE_INFO *pstDevInfo,
                                   unsigned int nAccessMode);

    // ch:打开设备 | en:Open Device
    int Open(MV_CC_DEVICE_INFO *pstDeviceInfo);

    // ch:关闭设备 | en:Close Device
    int Close();

    // ch:判断相机是否处于连接状态 | en:Is The Device Connected
    bool IsDeviceConnected();

    // ch:注册图像数据回调 | en:Register Image Data CallBack
    int RegisterImageCallBack(
        void(__stdcall *cbOutput)(unsigned char *pData,
                                  MV_FRAME_OUT_INFO_EX *pFrameInfo,
                                  void *pUser),
        void *pUser);

    // ch:开启抓图 | en:Start Grabbing
    int StartGrabbing();

    // ch:停止抓图 | en:Stop Grabbing
    int StopGrabbing();

    // ch:主动获取一帧图像数据 | en:Get one frame initiatively
    int GetImageBuffer(MV_FRAME_OUT *pFrame, int nMsec);

    // ch:释放图像缓存 | en:Free image buffer
    int FreeImageBuffer(MV_FRAME_OUT *pFrame);

    // ch:主动获取一帧图像数据 | en:Get one frame initiatively
    int GetOneFrameTimeout(unsigned char *pData, unsigned int *pnDataLen,
                           unsigned int nDataSize,
                           MV_FRAME_OUT_INFO_EX *pFrameInfo, int nMsec);

    // ch:显示一帧图像 | en:Display one frame image
    int DisplayOneFrame(MV_DISPLAY_FRAME_INFO *pDisplayInfo);

    // ch:设置SDK内部图像缓存节点个数 | en:Set the number of the internal image
    // cache nodes in SDK
    int SetImageNodeNum(unsigned int nNum);

    // ch:获取设备信息 | en:Get device information
    int GetDeviceInfo(MV_CC_DEVICE_INFO *pstDevInfo);

    // ch:获取GEV相机的统计信息 | en:Get detect info of GEV camera
    int GetGevAllMatchInfo(MV_MATCH_INFO_NET_DETECT *pMatchInfoNetDetect);

    // ch:获取U3V相机的统计信息 | en:Get detect info of U3V camera
    int GetU3VAllMatchInfo(MV_MATCH_INFO_USB_DETECT *pMatchInfoUSBDetect);

    // ch:获取和设置Int型参数,如 Width和Height,详细内容参考SDK安装目录下的
    // MvCameraNode.xlsx 文件 en:Get Int type parameters, such as Width and
    // Height, for details please refer to MvCameraNode.xlsx file under SDK
    // installation directory
    // int GetIntValue(IN const char* strKey, OUT MVCC_INTVALUE_EX* pIntValue);
    int GetIntValue(IN const char *strKey, OUT unsigned int *pnValue);
    int SetIntValue(IN const char *strKey, IN int64_t nValue);

    // ch:获取和设置Enum型参数,如 PixelFormat,详细内容参考SDK安装目录下的
    // MvCameraNode.xlsx 文件 en:Get Enum type parameters, such as PixelFormat,
    // for details please refer to MvCameraNode.xlsx file under SDK installation
    // directory
    int GetEnumValue(IN const char *strKey, OUT MVCC_ENUMVALUE *pEnumValue);
    int SetEnumValue(IN const char *strKey, IN unsigned int nValue);
    int SetEnumValueByString(IN const char *strKey, IN const char *sValue);

    // ch:获取和设置Float型参数,如
    // ExposureTime和Gain,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件
    // en:Get Float type parameters, such as ExposureTime and Gain, for details
    // please refer to MvCameraNode.xlsx file under SDK installation directory
    int GetFloatValue(IN const char *strKey, OUT MVCC_FLOATVALUE *pFloatValue);
    int SetFloatValue(IN const char *strKey, IN float fValue);

    // ch:获取和设置Bool型参数,如 ReverseX,详细内容参考SDK安装目录下的
    // MvCameraNode.xlsx 文件 en:Get Bool type parameters, such as ReverseX, for
    // details please refer to MvCameraNode.xlsx file under SDK installation
    // directory
    int GetBoolValue(IN const char *strKey, OUT bool *pbValue);
    int SetBoolValue(IN const char *strKey, IN bool bValue);

    // ch:获取和设置String型参数,如 DeviceUserID,详细内容参考SDK安装目录下的
    // MvCameraNode.xlsx 文件UserSetSave en:Get String type parameters, such as
    // DeviceUserID, for details please refer to MvCameraNode.xlsx file under
    // SDK installation directory
    int GetStringValue(IN const char *strKey, MVCC_STRINGVALUE *pStringValue);
    int SetStringValue(IN const char *strKey, IN const char *strValue);

    // ch:执行一次Command型命令,如 UserSetSave,详细内容参考SDK安装目录下的
    // MvCameraNode.xlsx 文件 en:Execute Command once, such as UserSetSave, for
    // details please refer to MvCameraNode.xlsx file under SDK installation
    // directory
    int CommandExecute(IN const char *strKey);

    // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal
    // package size(It only works for the GigE camera)
    int GetOptimalPacketSize(unsigned int *pOptimalPacketSize);

    // ch:注册消息异常回调 | en:Register Message Exception CallBack
    int RegisterExceptionCallBack(
        void(__stdcall *cbException)(unsigned int nMsgType, void *pUser),
        void *pUser);

    // ch:注册单个事件回调 | en:Register Event CallBack
    int RegisterEventCallBack(
        const char *pEventName,
        void(__stdcall *cbEvent)(MV_EVENT_OUT_INFO *pEventInfo, void *pUser),
        void *pUser);

    // ch:强制IP | en:Force IP
    int ForceIp(unsigned int nIP, unsigned int nSubNetMask,
                unsigned int nDefaultGateWay);

    // ch:配置IP方式 | en:IP configuration method
    int SetIpConfig(unsigned int nType);

    // ch:设置网络传输模式 | en:Set Net Transfer Mode
    int SetNetTransMode(unsigned int nType);

    // ch:像素格式转换 | en:Pixel format conversion
    int ConvertPixelType(MV_CC_PIXEL_CONVERT_PARAM *pstCvtParam);

    // ch:保存图片 | en:save image
    int SaveImage(MV_SAVE_IMAGE_PARAM_EX *pstParam);

    // ch:保存图片为文件 | en:Save the image as a file
    int SaveImageToFile(MV_SAVE_IMG_TO_FILE_PARAM *pstParam);

    //设置是否为触发模式
    int setTriggerMode(unsigned int TriggerModeNum);

    //设置触发源
    int setTriggerSource(unsigned int TriggerSourceNum);

    //软触发
    int softTrigger();

    //读取buffer
    int ReadBuffer(cv::Mat &image);

    //设置曝光时间
    int setExposureTime(float ExposureTimeNum);

public:
    void *m_hDevHandle;
    unsigned int m_nTLayerType;

public:
    unsigned char *m_pBufForSaveImage; // 用于保存图像的缓存
    unsigned int m_nBufSizeForSaveImage;

    unsigned char *m_pBufForDriver; // 用于从驱动获取图像的缓存
    unsigned int m_nBufSizeForDriver;
};

#endif // MVCAMERA_H

2.3 mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include "QThread"
#include "MvCamera.h"
#include "opencv2/opencv.hpp"
#include "opencv2/core/core.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/highgui/highgui.hpp"

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;
using namespace cv;

class MyThread :public QThread
{
        Q_OBJECT

public:
        MyThread();
        ~MyThread();

        void run();
        void getCameraPtr(CMvCamera* camera);
        void getImagePtr(Mat* image);
        void getCameraIndex(int index);

signals:
        void mess();
        void Display(const Mat* image, int index);

private:
        CMvCamera* cameraPtr = NULL;
        cv::Mat* imagePtr = NULL;
        int cameraIndex = NULL;
        int TriggerMode;

};

#endif // MYTHREAD_H

2.4 widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include 

#include 
#include 
#include 

#include "MvCamera.h"
#include "mythread.h"

#define MAX_DEVICE_NUM     2
#define TRIGGER_SOURCE     7
#define EXPOSURE_TIME      40000
#define FRAME              30
#define TRIGGER_ON         1
#define TRIGGER_OFF        0
#define START_GRABBING_ON  1
#define START_GRABBING_OFF 0
#define IMAGE_NAME_LEN     64

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

public:
    CMvCamera *m_pcMyCamera[MAX_DEVICE_NUM]; // 相机指针对象
    MV_CC_DEVICE_INFO_LIST m_stDevList;      // 存储设备列表
    cv::Mat *myImage_L = new cv::Mat(); //保存左相机图像的图像指针对象
    cv::Mat *myImage_R = new cv::Mat(); //保存右相机有图像的图像指针对象
    int devices_num;

public:
    MyThread *myThread_Camera_show = NULL; //相机实时显示线程对象

private slots:
    void on_pbn_enum_camera_clicked();
    void on_pbn_open_camera_clicked();
    void on_rdo_continue_mode_clicked();
    void on_rdo_softigger_mode_clicked();
    void on_pbn_start_grabbing_clicked();
    void on_pbn_stop_grabbing_clicked();
    void on_pbn_software_once_clicked();
    void display_myImage_L(const Mat *imagePrt, int cameraIndex);
    void on_pbn_close_camera_clicked();
    void on_pbn_save_BMP_clicked();
    void on_pbn_save_JPG_clicked();
    void on_le_set_exposure_textChanged(const QString &arg1);
    void on_le_set_gain_textChanged(const QString &arg1);

public:
    // 状态
    bool m_bOpenDevice;                  // 是否打开设备
    bool m_bStartGrabbing;               // 是否开始抓图
    int m_nTriggerMode;                  // 触发模式
    int m_bContinueStarted;              // 开启过连续采集图像
    MV_SAVE_IAMGE_TYPE m_nSaveImageType; // 保存图像格式

private:
    QString PrintDeviceInfo(MV_CC_DEVICE_INFO *pstMVDevInfo, int num_index);
    void OpenDevices();
    void CloseDevices();
    void SaveImage();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

2.5 main.cpp

#include "widget.h"

#include 

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

2.6 MvCamera.cpp

#include "MvCamera.h"

CMvCamera::CMvCamera()
{
    m_hDevHandle = MV_NULL;
}

CMvCamera::~CMvCamera()
{
    if (m_hDevHandle) {
        MV_CC_DestroyHandle(m_hDevHandle);
        m_hDevHandle = MV_NULL;
    }
}

// ch:获取SDK版本号 | en:Get SDK Version
int CMvCamera::GetSDKVersion()
{
    return MV_CC_GetSDKVersion();
}

// ch:枚举设备 | en:Enumerate Device
int CMvCamera::EnumDevices(unsigned int nTLayerType,
                           MV_CC_DEVICE_INFO_LIST *pstDevList)
{
    return MV_CC_EnumDevices(nTLayerType, pstDevList);
}

// ch:判断设备是否可达 | en:Is the device accessible
bool CMvCamera::IsDeviceAccessible(MV_CC_DEVICE_INFO *pstDevInfo,
                                   unsigned int nAccessMode)
{
    return MV_CC_IsDeviceAccessible(pstDevInfo, nAccessMode);
}

// ch:打开设备 | en:Open Device
int CMvCamera::Open(MV_CC_DEVICE_INFO *pstDeviceInfo)
{
    if (MV_NULL == pstDeviceInfo) {
        return MV_E_PARAMETER;
    }

    if (m_hDevHandle) {
        return MV_E_CALLORDER;
    }

    int nRet = MV_CC_CreateHandle(&m_hDevHandle, pstDeviceInfo);
    if (MV_OK != nRet) {
        return nRet;
    }

    nRet = MV_CC_OpenDevice(m_hDevHandle);
    if (MV_OK != nRet) {
        MV_CC_DestroyHandle(m_hDevHandle);
        m_hDevHandle = MV_NULL;
    }

    return nRet;
}

// ch:关闭设备 | en:Close Device
int CMvCamera::Close()
{
    if (MV_NULL == m_hDevHandle) {
        return MV_E_HANDLE;
    }

    MV_CC_CloseDevice(m_hDevHandle);

    int nRet = MV_CC_DestroyHandle(m_hDevHandle);
    m_hDevHandle = MV_NULL;

    return nRet;
}

// ch:判断相机是否处于连接状态 | en:Is The Device Connected
bool CMvCamera::IsDeviceConnected()
{
    return MV_CC_IsDeviceConnected(m_hDevHandle);
}

// ch:注册图像数据回调 | en:Register Image Data CallBack
int CMvCamera::RegisterImageCallBack(
    void(__stdcall *cbOutput)(unsigned char *pData,
                              MV_FRAME_OUT_INFO_EX *pFrameInfo, void *pUser),
    void *pUser)
{
    return MV_CC_RegisterImageCallBackEx(m_hDevHandle, cbOutput, pUser);
}

// ch:开启抓图 | en:Start Grabbing
int CMvCamera::StartGrabbing()
{
    return MV_CC_StartGrabbing(m_hDevHandle);
}

// ch:停止抓图 | en:Stop Grabbing
int CMvCamera::StopGrabbing()
{
    return MV_CC_StopGrabbing(m_hDevHandle);
}

// ch:主动获取一帧图像数据 | en:Get one frame initiatively
int CMvCamera::GetImageBuffer(MV_FRAME_OUT *pFrame, int nMsec)
{
    return MV_CC_GetImageBuffer(m_hDevHandle, pFrame, nMsec);
}

// ch:释放图像缓存 | en:Free image buffer
int CMvCamera::FreeImageBuffer(MV_FRAME_OUT *pFrame)
{
    return MV_CC_FreeImageBuffer(m_hDevHandle, pFrame);
}

// ch:主动获取一帧图像数据 | en:Get one frame initiatively
int CMvCamera::GetOneFrameTimeout(unsigned char *pData, unsigned int *pnDataLen,
                                  unsigned int nDataSize,
                                  MV_FRAME_OUT_INFO_EX *pFrameInfo, int nMsec)
{
    if (NULL == pnDataLen) {
        return MV_E_PARAMETER;
    }

    int nRet = MV_OK;

    *pnDataLen = 0;

    nRet = MV_CC_GetOneFrameTimeout(m_hDevHandle, pData, nDataSize, pFrameInfo,
                                    nMsec);
    if (MV_OK != nRet) {
        return nRet;
    }

    *pnDataLen = pFrameInfo->nFrameLen;

    return nRet;
}

// ch:设置显示窗口句柄 | en:Set Display Window Handle
int CMvCamera::DisplayOneFrame(MV_DISPLAY_FRAME_INFO *pDisplayInfo)
{
    return MV_CC_DisplayOneFrame(m_hDevHandle, pDisplayInfo);
}

// ch:设置SDK内部图像缓存节点个数 | en:Set the number of the internal image
// cache nodes in SDK
int CMvCamera::SetImageNodeNum(unsigned int nNum)
{
    return MV_CC_SetImageNodeNum(m_hDevHandle, nNum);
}

// ch:获取设备信息 | en:Get device information
int CMvCamera::GetDeviceInfo(MV_CC_DEVICE_INFO *pstDevInfo)
{
    return MV_CC_GetDeviceInfo(m_hDevHandle, pstDevInfo);
}

// ch:获取GEV相机的统计信息 | en:Get detect info of GEV camera
int CMvCamera::GetGevAllMatchInfo(MV_MATCH_INFO_NET_DETECT *pMatchInfoNetDetect)
{
    if (MV_NULL == pMatchInfoNetDetect) {
        return MV_E_PARAMETER;
    }

    MV_CC_DEVICE_INFO stDevInfo = { 0 };
    GetDeviceInfo(&stDevInfo);
    if (stDevInfo.nTLayerType != MV_GIGE_DEVICE) {
        return MV_E_SUPPORT;
    }

    MV_ALL_MATCH_INFO struMatchInfo = { 0 };

    struMatchInfo.nType = MV_MATCH_TYPE_NET_DETECT;
    struMatchInfo.pInfo = pMatchInfoNetDetect;
    struMatchInfo.nInfoSize = sizeof(MV_MATCH_INFO_NET_DETECT);
    memset(struMatchInfo.pInfo, 0, sizeof(MV_MATCH_INFO_NET_DETECT));

    return MV_CC_GetAllMatchInfo(m_hDevHandle, &struMatchInfo);
}

// ch:获取U3V相机的统计信息 | en:Get detect info of U3V camera
int CMvCamera::GetU3VAllMatchInfo(MV_MATCH_INFO_USB_DETECT *pMatchInfoUSBDetect)
{
    if (MV_NULL == pMatchInfoUSBDetect) {
        return MV_E_PARAMETER;
    }

    MV_CC_DEVICE_INFO stDevInfo = { 0 };
    GetDeviceInfo(&stDevInfo);
    if (stDevInfo.nTLayerType != MV_USB_DEVICE) {
        return MV_E_SUPPORT;
    }

    MV_ALL_MATCH_INFO struMatchInfo = { 0 };

    struMatchInfo.nType = MV_MATCH_TYPE_USB_DETECT;
    struMatchInfo.pInfo = pMatchInfoUSBDetect;
    struMatchInfo.nInfoSize = sizeof(MV_MATCH_INFO_USB_DETECT);
    memset(struMatchInfo.pInfo, 0, sizeof(MV_MATCH_INFO_USB_DETECT));

    return MV_CC_GetAllMatchInfo(m_hDevHandle, &struMatchInfo);
}

// ch:获取和设置Int型参数,如 Width和Height,详细内容参考SDK安装目录下的
// MvCameraNode.xlsx 文件 en:Get Int type parameters, such as Width and Height,
// for details please refer to MvCameraNode.xlsx file under SDK installation
// directory
int CMvCamera::GetIntValue(IN const char *strKey, OUT unsigned int *pnValue)
{
    if (NULL == strKey || NULL == pnValue) {
        return MV_E_PARAMETER;
    }

    MVCC_INTVALUE stParam;
    memset(&stParam, 0, sizeof(MVCC_INTVALUE));
    int nRet = MV_CC_GetIntValue(m_hDevHandle, strKey, &stParam);
    if (MV_OK != nRet) {
        return nRet;
    }

    *pnValue = stParam.nCurValue;

    return MV_OK;
}

int CMvCamera::SetIntValue(IN const char *strKey, IN int64_t nValue)
{
    return MV_CC_SetIntValueEx(m_hDevHandle, strKey, nValue);
}

// ch:获取和设置Enum型参数,如 PixelFormat,详细内容参考SDK安装目录下的
// MvCameraNode.xlsx 文件 en:Get Enum type parameters, such as PixelFormat, for
// details please refer to MvCameraNode.xlsx file under SDK installation
// directory
int CMvCamera::GetEnumValue(IN const char *strKey,
                            OUT MVCC_ENUMVALUE *pEnumValue)
{
    return MV_CC_GetEnumValue(m_hDevHandle, strKey, pEnumValue);
}

int CMvCamera::SetEnumValue(IN const char *strKey, IN unsigned int nValue)
{
    return MV_CC_SetEnumValue(m_hDevHandle, strKey, nValue);
}

int CMvCamera::SetEnumValueByString(IN const char *strKey,
                                    IN const char *sValue)
{
    return MV_CC_SetEnumValueByString(m_hDevHandle, strKey, sValue);
}

// ch:获取和设置Float型参数,如 ExposureTime和Gain,详细内容参考SDK安装目录下的
// MvCameraNode.xlsx 文件 en:Get Float type parameters, such as ExposureTime and
// Gain, for details please refer to MvCameraNode.xlsx file under SDK
// installation directory
int CMvCamera::GetFloatValue(IN const char *strKey,
                             OUT MVCC_FLOATVALUE *pFloatValue)
{
    return MV_CC_GetFloatValue(m_hDevHandle, strKey, pFloatValue);
}

int CMvCamera::SetFloatValue(IN const char *strKey, IN float fValue)
{
    return MV_CC_SetFloatValue(m_hDevHandle, strKey, fValue);
}

// ch:获取和设置Bool型参数,如 ReverseX,详细内容参考SDK安装目录下的
// MvCameraNode.xlsx 文件 en:Get Bool type parameters, such as ReverseX, for
// details please refer to MvCameraNode.xlsx file under SDK installation
// directory
int CMvCamera::GetBoolValue(IN const char *strKey, OUT bool *pbValue)
{
    return MV_CC_GetBoolValue(m_hDevHandle, strKey, pbValue);
}

int CMvCamera::SetBoolValue(IN const char *strKey, IN bool bValue)
{
    return MV_CC_SetBoolValue(m_hDevHandle, strKey, bValue);
}

// ch:获取和设置String型参数,如 DeviceUserID,详细内容参考SDK安装目录下的
// MvCameraNode.xlsx 文件UserSetSave en:Get String type parameters, such as
// DeviceUserID, for details please refer to MvCameraNode.xlsx file under SDK
// installation directory
int CMvCamera::GetStringValue(IN const char *strKey,
                              MVCC_STRINGVALUE *pStringValue)
{
    return MV_CC_GetStringValue(m_hDevHandle, strKey, pStringValue);
}

int CMvCamera::SetStringValue(IN const char *strKey, IN const char *strValue)
{
    return MV_CC_SetStringValue(m_hDevHandle, strKey, strValue);
}

// ch:执行一次Command型命令,如 UserSetSave,详细内容参考SDK安装目录下的
// MvCameraNode.xlsx 文件 en:Execute Command once, such as UserSetSave, for
// details please refer to MvCameraNode.xlsx file under SDK installation
// directory
int CMvCamera::CommandExecute(IN const char *strKey)
{
    return MV_CC_SetCommandValue(m_hDevHandle, strKey);
}

// ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal
// package size(It only works for the GigE camera)
int CMvCamera::GetOptimalPacketSize(unsigned int *pOptimalPacketSize)
{
    if (MV_NULL == pOptimalPacketSize) {
        return MV_E_PARAMETER;
    }

    int nRet = MV_CC_GetOptimalPacketSize(m_hDevHandle);
    if (nRet < MV_OK) {
        return nRet;
    }

    *pOptimalPacketSize = (unsigned int)nRet;

    return MV_OK;
}

// ch:注册消息异常回调 | en:Register Message Exception CallBack
int CMvCamera::RegisterExceptionCallBack(
    void(__stdcall *cbException)(unsigned int nMsgType, void *pUser),
    void *pUser)
{
    return MV_CC_RegisterExceptionCallBack(m_hDevHandle, cbException, pUser);
}

// ch:注册单个事件回调 | en:Register Event CallBack
int CMvCamera::RegisterEventCallBack(
    const char *pEventName,
    void(__stdcall *cbEvent)(MV_EVENT_OUT_INFO *pEventInfo, void *pUser),
    void *pUser)
{
    return MV_CC_RegisterEventCallBackEx(m_hDevHandle, pEventName, cbEvent,
                                         pUser);
}

// ch:强制IP | en:Force IP
int CMvCamera::ForceIp(unsigned int nIP, unsigned int nSubNetMask,
                       unsigned int nDefaultGateWay)
{
    return MV_GIGE_ForceIpEx(m_hDevHandle, nIP, nSubNetMask, nDefaultGateWay);
}

// ch:配置IP方式 | en:IP configuration method
int CMvCamera::SetIpConfig(unsigned int nType)
{
    return MV_GIGE_SetIpConfig(m_hDevHandle, nType);
}

// ch:设置网络传输模式 | en:Set Net Transfer Mode
int CMvCamera::SetNetTransMode(unsigned int nType)
{
    return MV_GIGE_SetNetTransMode(m_hDevHandle, nType);
}

// ch:像素格式转换 | en:Pixel format conversion
int CMvCamera::ConvertPixelType(MV_CC_PIXEL_CONVERT_PARAM *pstCvtParam)
{
    return MV_CC_ConvertPixelType(m_hDevHandle, pstCvtParam);
}

// ch:保存图片 | en:save image
int CMvCamera::SaveImage(MV_SAVE_IMAGE_PARAM_EX *pstParam)
{
    return MV_CC_SaveImageEx2(m_hDevHandle, pstParam);
}

 ch:保存图片为文件 | en:Save the image as a file
// int CMvCamera::SaveImageToFile(MV_SAVE_IMG_TO_FILE_PARAM *pstSaveFileParam)
//{
//    return MV_CC_SaveImageToFile(m_hDevHandle, pstSaveFileParam);
//}

//设置是否为触发模式
int CMvCamera::setTriggerMode(unsigned int TriggerModeNum)
{
    // 0:Off  1:On
    int tempValue =
        MV_CC_SetEnumValue(m_hDevHandle, "TriggerMode", TriggerModeNum);
    if (tempValue != 0) {
        return -1;
    } else {
        return 0;
    }
}

//设置触发源
int CMvCamera::setTriggerSource(unsigned int TriggerSourceNum)
{
    // 0:Line0  1:Line1  7:Software
    int tempValue =
        MV_CC_SetEnumValue(m_hDevHandle, "TriggerSource", TriggerSourceNum);
    if (tempValue != 0) {
        return -1;
    } else {
        return 0;
    }
}

//发送软触发
int CMvCamera::softTrigger()
{
    int tempValue = MV_CC_SetCommandValue(m_hDevHandle, "TriggerSoftware");
    if (tempValue != 0) {
        return -1;
    } else {
        return 0;
    }
}

//读取相机中的图像
// int ReadBuffer(cv::Mat &image);
int CMvCamera::ReadBuffer(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(m_hDevHandle, "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(m_hDevHandle, 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);
        // imwrite("d:\\测试opencv_Mono.tif", image);
    } else {
        //转换图像格式为BGR8
        MV_CC_PIXEL_CONVERT_PARAM stConvertParam = { 0 };
        memset(&stConvertParam, 0, sizeof(MV_CC_PIXEL_CONVERT_PARAM));
        stConvertParam.nWidth = stImageInfo.nWidth; // ch:图像宽 | en:image
                                                    // width
        stConvertParam.nHeight =
            stImageInfo.nHeight; // ch:图像高 | en:image height
        // stConvertParam.pSrcData = m_pBufForDriver; //ch:输入数据缓存 |
        // en:input data buffer
        stConvertParam.pSrcData =
            pDate; // ch:输入数据缓存 | en:input data buffer
        stConvertParam.nSrcDataLen =
            stImageInfo.nFrameLen; // ch:输入数据大小 | en:input data size
        stConvertParam.enSrcPixelType =
            stImageInfo.enPixelType; // ch:输入像素格式 | en:input pixel format
        stConvertParam.enDstPixelType =
            PixelType_Gvsp_BGR8_Packed; // ch:输出像素格式 | en:output pixel
                                        // format  适用于OPENCV的图像格式
        // stConvertParam.enDstPixelType = PixelType_Gvsp_RGB8_Packed;
        //输出像素格式 | en:output pixel format
        stConvertParam.pDstBuffer =
            m_pBufForSaveImage; // ch:输出数据缓存 | en:output data buffer
        stConvertParam.nDstBufferSize =
            m_nBufSizeForSaveImage; // ch:输出缓存大小 | en:output buffer size
        MV_CC_ConvertPixelType(m_hDevHandle, &stConvertParam);

        *getImage = cv::Mat(stImageInfo.nHeight, stImageInfo.nWidth, CV_8UC3,
                            m_pBufForSaveImage);
    }
    (*getImage).copyTo(image);
    (*getImage).release();
    free(pDate);
    free(m_pBufForSaveImage);
    return 0;
}

//设置曝光时间
int CMvCamera::setExposureTime(float ExposureTimeNum)
{
    int tempValue =
        MV_CC_SetFloatValue(m_hDevHandle, "ExposureTime", ExposureTimeNum);
    if (tempValue != 0) {
        return -1;
    } else {
        return 0;
    }
}

2.7 mythread.cpp

#include "mythread.h"

MyThread::MyThread()
{
}

MyThread::~MyThread()
{
    terminate();
    if (cameraPtr != NULL) {
        delete cameraPtr;
    }
    if (imagePtr != NULL) {
        delete imagePtr;
    }
}

void MyThread::getCameraPtr(CMvCamera *camera)
{
    cameraPtr = camera;
}

void MyThread::getImagePtr(Mat *image)
{
    imagePtr = image;
}

void MyThread::getCameraIndex(int index)
{
    cameraIndex = index;
}

void MyThread::run()
{
    if (cameraPtr == NULL) {
        return;
    }

    if (imagePtr == NULL) {
        return;
    }

    while (!isInterruptionRequested()) {
        std::cout << "Thread_Trigger:" << cameraPtr->softTrigger() << std::endl;
        std::cout << "Thread_Readbuffer:" << cameraPtr->ReadBuffer(*imagePtr)
                  << std::endl;
        /*emit mess();*/
        emit Display(imagePtr, cameraIndex); //发送信号lbl_camera_L接收并显示
        msleep(30);
    }
}

2.8 widget.cpp

#include "widget.h"
#include "./ui_widget.h"

#include 
#include 
#include 
#include 
#include 
#include 

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);
    ui->lbl_camera_L->setPixmap(QPixmap("back_img.jpg"));
    ui->lbl_camera_L->setScaledContents(true);

    ui->lbl_camera_R->setPixmap(QPixmap("back_img.jpg"));
    ui->lbl_camera_R->setScaledContents(true);

    // 相机初始化控件
    ui->pbn_enum_camera->setEnabled(true);
    ui->pbn_open_camera->setEnabled(false);
    ui->pbn_close_camera->setEnabled(false);
    ui->cmb_camera_index->setEnabled(false);

    // 图像采集控件
    ui->rdo_continue_mode->setEnabled(false);
    ui->rdo_softigger_mode->setEnabled(false);
    ui->pbn_start_grabbing->setEnabled(false);
    ui->pbn_stop_grabbing->setEnabled(false);
    ui->pbn_software_once->setEnabled(false);

    // 参数控件
    ui->le_set_exposure->setEnabled(false);
    ui->le_set_gain->setEnabled(false);

    // 保存图像控件
    ui->pbn_save_BMP->setEnabled(false);
    ui->pbn_save_JPG->setEnabled(false);

    // 线程对象实例化
    myThread_Camera_show = new MyThread; //左相机线程对象

    // 初始化变量
    int devices_num = 0;
    int m_nTriggerMode = TRIGGER_ON;
    int m_bStartGrabbing = START_GRABBING_ON;
    int m_bContinueStarted = 0;
    MV_SAVE_IAMGE_TYPE m_nSaveImageType = MV_Image_Bmp;

    connect(myThread_Camera_show, SIGNAL(Display(const Mat *, int)), this,
            SLOT(display_myImage_L(const Mat *, int)));

    // 曝光和增益的输入控件限制值
    QRegExp int_rx("100000|([0-9]{0,5})");
    ui->le_set_exposure->setValidator(new QRegExpValidator(int_rx, this));
    QRegExp double_rx("15|([0-9]{0,1}[0-5]{1,2}[\.][0-9]{0,1})");
    ui->le_set_gain->setValidator(new QRegExpValidator(double_rx, this));
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_pbn_enum_camera_clicked()
{
    memset(&m_stDevList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));
    int nRet = MV_OK;
    nRet = CMvCamera::EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &m_stDevList);

    devices_num = m_stDevList.nDeviceNum;
    if (devices_num == 0) {
        QString cameraInfo;
        cameraInfo =
            QString::fromLocal8Bit("暂无设备可连接,请检查设备是否连接正确!");
        ui->lbl_camera_messagee->setText(cameraInfo);
    }
    if (devices_num > 0) {
        QString cameraInfo;
        for (int i = 0; i < devices_num; i++) {
            MV_CC_DEVICE_INFO *pDeviceInfo = m_stDevList.pDeviceInfo[i];
            QString cameraInfo_i = PrintDeviceInfo(pDeviceInfo, i);
            cameraInfo.append(cameraInfo_i);
            cameraInfo.append("\n");
            ui->cmb_camera_index->addItem(QString::number(i));
        }
        ui->lbl_camera_messagee->setText(cameraInfo);
        ui->pbn_open_camera->setEnabled(true);
        ui->cmb_camera_index->setEnabled(true);
    }
}

QString Widget::PrintDeviceInfo(MV_CC_DEVICE_INFO *pstMVDevInfo, int num_index)
{
    QString cameraInfo_index;
    cameraInfo_index = QString::fromLocal8Bit("相机序号:");
    cameraInfo_index.append(QString::number(num_index));
    cameraInfo_index.append("\t\t");
    // 海康GIGE协议的相机
    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);

        cameraInfo_index.append(QString::fromLocal8Bit("相机型号:"));
        std::string str_name =
            (char *)pstMVDevInfo->SpecialInfo.stGigEInfo.chModelName;
        cameraInfo_index.append(QString::fromStdString(str_name));
        cameraInfo_index.append("\n");
        cameraInfo_index.append(QString::fromLocal8Bit("当前相机IP地址:"));
        cameraInfo_index.append(QString::number(nIp1));
        cameraInfo_index.append(".");
        cameraInfo_index.append(QString::number(nIp2));
        cameraInfo_index.append(".");
        cameraInfo_index.append(QString::number(nIp3));
        cameraInfo_index.append(".");
        cameraInfo_index.append(QString::number(nIp4));
        cameraInfo_index.append("\t");
    } else if (pstMVDevInfo->nTLayerType == MV_USB_DEVICE) {
        cameraInfo_index.append(QString::fromLocal8Bit("相机型号:"));
        std::string str_name =
            (char *)pstMVDevInfo->SpecialInfo.stUsb3VInfo.chModelName;
        cameraInfo_index.append(QString::fromStdString(str_name));
        cameraInfo_index.append("\n");
    } else {
        cameraInfo_index.append(QString::fromLocal8Bit("相机型号:未知"));
    }
    cameraInfo_index.append(QString::fromLocal8Bit("相机品牌:海康"));
    return cameraInfo_index;
}

void Widget::on_pbn_open_camera_clicked()
{
    ui->pbn_open_camera->setEnabled(false);
    ui->pbn_close_camera->setEnabled(true);
    ui->rdo_continue_mode->setEnabled(true);
    ui->rdo_softigger_mode->setEnabled(true);

    ui->rdo_continue_mode->setCheckable(true);
    // 参数据控件
    ui->le_set_exposure->setEnabled(true);
    ui->le_set_gain->setEnabled(true);

    OpenDevices();
}

void Widget::OpenDevices()
{
    int nRet = MV_OK;
    // 创建相机指针对象
    for (unsigned int i = 0, j = 0; j < m_stDevList.nDeviceNum; j++, i++) {
        m_pcMyCamera[i] = new CMvCamera;
        // 相机对象初始化
        m_pcMyCamera[i]->m_pBufForDriver = NULL;
        m_pcMyCamera[i]->m_pBufForSaveImage = NULL;
        m_pcMyCamera[i]->m_nBufSizeForDriver = 0;
        m_pcMyCamera[i]->m_nBufSizeForSaveImage = 0;
        m_pcMyCamera[i]->m_nTLayerType =
            m_stDevList.pDeviceInfo[j]->nTLayerType;

        nRet = m_pcMyCamera[i]->Open(m_stDevList.pDeviceInfo[j]); //打开相机
        //设置触发模式
        m_pcMyCamera[i]->setTriggerMode(TRIGGER_ON);
        //设置触发源为软触发
        m_pcMyCamera[i]->setTriggerSource(TRIGGER_SOURCE);
        //设置曝光时间,初始为40000,并关闭自动曝光模式
        m_pcMyCamera[i]->setExposureTime(EXPOSURE_TIME);
        m_pcMyCamera[i]->SetEnumValue("ExposureAuto",
                                      MV_EXPOSURE_AUTO_MODE_OFF);
    }
}

void Widget::on_rdo_continue_mode_clicked()
{
    ui->pbn_start_grabbing->setEnabled(true);
    m_nTriggerMode = TRIGGER_ON;
}

void Widget::on_rdo_softigger_mode_clicked()
{
    // 如果开始选择的连续模式,切换到触发模式之前,需要先停止采集
    if (m_bContinueStarted == 1) {
        on_pbn_stop_grabbing_clicked(); //先执行停止采集
    }

    ui->pbn_start_grabbing->setEnabled(false);
    ui->pbn_software_once->setEnabled(true);

    m_nTriggerMode = TRIGGER_OFF;
    for (unsigned int i = 0; i < m_stDevList.nDeviceNum; i++) {
        m_pcMyCamera[i]->setTriggerMode(m_nTriggerMode);
    }
}

void Widget::on_pbn_start_grabbing_clicked()
{
    // 触发模式标记一下,切换触发模式时先执行停止采集图像函数
    m_bContinueStarted = 1;

    // 图像采集控件
    ui->pbn_start_grabbing->setEnabled(false);
    ui->pbn_stop_grabbing->setEnabled(true);
    // 保存图像控件
    ui->pbn_save_BMP->setEnabled(true);
    ui->pbn_save_JPG->setEnabled(true);

    int camera_Index = 0;

    // 先判断什么模式,再判断是否正在采集
    if (m_nTriggerMode == TRIGGER_ON) {
        // 开始采集之后才创建workthread线程
        for (unsigned int i = 0; i < m_stDevList.nDeviceNum; i++) {
            //开启相机采集
            m_pcMyCamera[i]->StartGrabbing();
            camera_Index = i;
            if (camera_Index == 0) {
                myThread_Camera_show->getCameraPtr(
                    m_pcMyCamera[0]); //线程获取左相机指针
                myThread_Camera_show->getImagePtr(
                    myImage_L); //线程获取左图像指针
                myThread_Camera_show->getCameraIndex(0); //左相机 Index==0

                if (!myThread_Camera_show->isRunning()) {
                    myThread_Camera_show->start();
                    m_pcMyCamera[0]->softTrigger();
                    m_pcMyCamera[0]->ReadBuffer(*myImage_L); //读取Mat格式的图像
                }
            }
        }
    }
}

void Widget::on_pbn_stop_grabbing_clicked()
{
    ui->pbn_start_grabbing->setEnabled(true);
    ui->pbn_stop_grabbing->setEnabled(false);

    for (unsigned int i = 0; i < m_stDevList.nDeviceNum; i++) {
        //关闭相机
        if (myThread_Camera_show->isRunning()) {
            m_pcMyCamera[0]->StopGrabbing();
            myThread_Camera_show->requestInterruption();
            myThread_Camera_show->wait();
        }
    }
}

void Widget::on_pbn_software_once_clicked()
{
    // 保存图像控件
    ui->pbn_save_BMP->setEnabled(true);
    ui->pbn_save_JPG->setEnabled(true);

    if (m_nTriggerMode == TRIGGER_OFF) {
        int nRet = MV_OK;
        for (unsigned int i = 0; i < m_stDevList.nDeviceNum; i++) {
            //开启相机采集
            m_pcMyCamera[i]->StartGrabbing();

            if (i == 0) {
                nRet = m_pcMyCamera[i]->CommandExecute("TriggerSoftware");
                m_pcMyCamera[i]->ReadBuffer(*myImage_L);
                display_myImage_L(myImage_L, i); //左相机图像
            }
        }
    }
}

void Widget::display_myImage_L(const Mat *imagePrt, int cameraIndex)
{
    cv::Mat rgb;
    cv::cvtColor(*imagePrt, rgb, CV_BGR2RGB);

    QImage QmyImage_L;
    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));
}

void Widget::CloseDevices()
{
    for (unsigned int i = 0; i < m_stDevList.nDeviceNum; i++) {
        // 关闭线程、相机
        if (myThread_Camera_show->isRunning()) {
            myThread_Camera_show->requestInterruption();
            myThread_Camera_show->wait();
            m_pcMyCamera[0]->StopGrabbing();
        }

        m_pcMyCamera[i]->Close();
    }

    // 关闭之后再枚举一遍
    memset(&m_stDevList, 0,
           sizeof(MV_CC_DEVICE_INFO_LIST)); // 初始化设备信息列表
    int devices_num = MV_OK;
    devices_num =
        CMvCamera::EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE,
                               &m_stDevList); // 枚举子网内所有设备,相机设备数量
}

void Widget::on_pbn_close_camera_clicked()
{
    ui->pbn_open_camera->setEnabled(true);
    ui->pbn_close_camera->setEnabled(false);
    // 图像采集控件
    ui->rdo_continue_mode->setEnabled(false);
    ui->rdo_softigger_mode->setEnabled(false);
    ui->pbn_start_grabbing->setEnabled(false);
    ui->pbn_stop_grabbing->setEnabled(false);
    ui->pbn_software_once->setEnabled(false);
    // 参数控件
    ui->le_set_exposure->setEnabled(false);
    ui->le_set_gain->setEnabled(false);
    // 保存图像控件
    ui->pbn_save_BMP->setEnabled(false);
    ui->pbn_save_JPG->setEnabled(false);

    // 关闭设备,销毁线程
    CloseDevices();
    ui->lbl_camera_messagee->clear();
    ui->lbl_camera_L->clear();
    ui->lbl_camera_R->clear();
}

void Widget::on_pbn_save_BMP_clicked()
{
    m_nSaveImageType = MV_Image_Bmp;
    SaveImage();
}

void Widget::on_pbn_save_JPG_clicked()
{
    m_nSaveImageType = MV_Image_Jpeg;
    SaveImage();
}

void Widget::SaveImage()
{
    // 获取1张图
    MV_FRAME_OUT_INFO_EX stImageInfo = { 0 };
    memset(&stImageInfo, 0, sizeof(MV_FRAME_OUT_INFO_EX));
    unsigned int nDataLen = 0;
    int nRet = MV_OK;
    for (int i = 0; i < devices_num; i++) {
        // 仅在第一次保存图像时申请缓存,在CloseDevice时释放
        if (NULL == m_pcMyCamera[i]->m_pBufForDriver) {
            unsigned int nRecvBufSize = 0;
            unsigned int nRet =
                m_pcMyCamera[i]->GetIntValue("PayloadSize", &nRecvBufSize);

            m_pcMyCamera[i]->m_nBufSizeForDriver = nRecvBufSize; // 一帧数据大小

            m_pcMyCamera[i]->m_pBufForDriver =
                (unsigned char *)malloc(m_pcMyCamera[i]->m_nBufSizeForDriver);
        }

        nRet = m_pcMyCamera[i]->GetOneFrameTimeout(
            m_pcMyCamera[i]->m_pBufForDriver, &nDataLen,
            m_pcMyCamera[i]->m_nBufSizeForDriver, &stImageInfo, 1000);
        if (MV_OK == nRet) {
            // 仅在第一次保存图像时申请缓存,在 CloseDevice 时释放
            if (NULL == m_pcMyCamera[i]->m_pBufForSaveImage) {
                // BMP图片大小:width * height * 3 + 2048(预留BMP头大小)
                m_pcMyCamera[i]->m_nBufSizeForSaveImage =
                    stImageInfo.nWidth * stImageInfo.nHeight * 3 + 2048;

                m_pcMyCamera[i]->m_pBufForSaveImage = (unsigned char *)malloc(
                    m_pcMyCamera[i]->m_nBufSizeForSaveImage);
            }
            // 设置对应的相机参数
            MV_SAVE_IMAGE_PARAM_EX stParam = { 0 };
            stParam.enImageType = m_nSaveImageType; // 需要保存的图像类型
            stParam.enPixelType = stImageInfo.enPixelType; // 相机对应的像素格式
            stParam.nBufferSize =
                m_pcMyCamera[i]->m_nBufSizeForSaveImage; // 存储节点的大小
            stParam.nWidth = stImageInfo.nWidth;         // 相机对应的宽
            stParam.nHeight = stImageInfo.nHeight;       // 相机对应的高
            stParam.nDataLen = stImageInfo.nFrameLen;
            stParam.pData = m_pcMyCamera[i]->m_pBufForDriver;
            stParam.pImageBuffer = m_pcMyCamera[i]->m_pBufForSaveImage;
            stParam.nJpgQuality = 90; // jpg编码,仅在保存Jpg图像时有效

            nRet = m_pcMyCamera[i]->SaveImage(&stParam);

            QString image_name;
            char chImageName[IMAGE_NAME_LEN] = { 0 };
            if (MV_Image_Bmp == stParam.enImageType) {
                if (i == 0) {
                    snprintf(chImageName, IMAGE_NAME_LEN,
                             "Image_w%d_h%d_fn%d_L.bmp", stImageInfo.nWidth,
                             stImageInfo.nHeight, stImageInfo.nFrameNum);
                    image_name = "Image_w";
                    image_name.append(QString::number(stImageInfo.nWidth));
                    image_name.append("_h");
                    image_name.append(QString::number(stImageInfo.nHeight));
                    image_name.append("_fn");
                    image_name.append(QString::number(stImageInfo.nFrameNum));
                    image_name.append("_L.bmp");
                }
                if (i == 1) {
                    snprintf(chImageName, IMAGE_NAME_LEN,
                             "Image_w%d_h%d_fn%03d_R.bmp", stImageInfo.nWidth,
                             stImageInfo.nHeight, stImageInfo.nFrameNum);
                }

            } else if (MV_Image_Jpeg == stParam.enImageType) {
                if (i == 0) {
                    snprintf(chImageName, IMAGE_NAME_LEN,
                             "Image_w%d_h%d_fn%d_L.jpg", stImageInfo.nWidth,
                             stImageInfo.nHeight, stImageInfo.nFrameNum);
                    image_name = "Image_w";
                    image_name.append(QString::number(stImageInfo.nWidth));
                    image_name.append("_h");
                    image_name.append(QString::number(stImageInfo.nHeight));
                    image_name.append("_fn");
                    image_name.append(QString::number(stImageInfo.nFrameNum));
                    image_name.append("_L.jpg");
                }
                if (i == 1) {
                    snprintf(chImageName, IMAGE_NAME_LEN,
                             "Image_w%d_h%d_fn%03d_R.jpg", stImageInfo.nWidth,
                             stImageInfo.nHeight, stImageInfo.nFrameNum);
                }
            }

            FILE *fp = fopen(chImageName, "wb");

            fwrite(m_pcMyCamera[i]->m_pBufForSaveImage, 1, stParam.nImageLen,
                   fp);
            fclose(fp);

            ui->lbl_camera_R->setPixmap(QPixmap(image_name));
            ui->lbl_camera_R->setScaledContents(true);
        }
    }
}

void Widget::on_le_set_exposure_textChanged(const QString &arg1)
{
    //设置曝光时间
    QString str = ui->le_set_exposure->text(); // 读取
    int exposure_Time = str.toInt();

    for (int i = 0; i < devices_num; i++) {
        m_pcMyCamera[i]->SetEnumValue("ExposureAuto",
                                      MV_EXPOSURE_AUTO_MODE_OFF);
        m_pcMyCamera[i]->SetFloatValue("ExposureTime", exposure_Time);
    }
}

void Widget::on_le_set_gain_textChanged(const QString &arg1)
{
    QString str = ui->le_set_gain->text(); // 读取
    float gain = str.toFloat();

    for (int i = 0; i < devices_num; i++) {
        m_pcMyCamera[i]->SetEnumValue("GainAuto", 0);
        int nRet = m_pcMyCamera[i]->SetFloatValue("Gain", gain);
    }
}

2.9 widget.ui

Linux环境中对海康威视工业相机SDK进行二次开发(QT+CMake+Opencv+海康SDK)_第6张图片

2.10 运行效果

Linux环境中对海康威视工业相机SDK进行二次开发(QT+CMake+Opencv+海康SDK)_第7张图片

Linux环境中对海康威视工业相机SDK进行二次开发(QT+CMake+Opencv+海康SDK)_第8张图片
Linux环境中对海康威视工业相机SDK进行二次开发(QT+CMake+Opencv+海康SDK)_第9张图片
Linux环境中对海康威视工业相机SDK进行二次开发(QT+CMake+Opencv+海康SDK)_第10张图片
Linux环境中对海康威视工业相机SDK进行二次开发(QT+CMake+Opencv+海康SDK)_第11张图片

参考:
海康Camera MVS Linux SDK二次开发封装ROS packge过程记录(c++):
https://blog.csdn.net/weixin_41965898/article/details/116801491
linux下qt封装海康SDK(这个是安防相机的,up主提供了qt的源码):https://www.bilibili.com/video/BV1u64y1o76T?spm_id_from=333.1007.top_right_bar_window_history.content.click

你可能感兴趣的