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

Posted boss-dog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux环境中对海康威视工业相机SDK进行二次开发(QT+CMake+Opencv+海康SDK)相关的知识,希望对你有一定的参考价值。

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文件编写的。

  通过CMake工具可以读入所有源文件,自动生成Makefile。开发的基本流程如下:

  • 编写源文件
  • 编写CMakeLists.txt
  • 由CMake根据CMakeLists.txt生成Makefile
  • 由Make根据Makefile,调用gcc生成可执行文件

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中的文件安装目录根据自己的实际安装位置为准。



2.2 MvCamera.h

#ifndef MVCAMERA_H
#define MVCAMERA_H

#include "MvCameraControl.h"
#include <string.h>

#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 <vector>
#include <string>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

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 <QWidget>

#include <QMessageBox>
#include <QCloseEvent>
#include <QSettings>

#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(); <

以上是关于Linux环境中对海康威视工业相机SDK进行二次开发(QT+CMake+Opencv+海康SDK)的主要内容,如果未能解决你的问题,请参考以下文章

rm记录第三阶段:海康威视工业相机的使用,cmake的复习

海康工业相机支持web集成吗

海康威视 摄像头 二次开发Demo 遇到的小问题

java如何通过海康威视SDK捕捉ip摄像头流?

用Java web 实现海康威视监控预览功能

海康威视人脸识别设备对接环境搭建