Linux环境中对海康威视工业相机SDK进行二次开发(QT+CMake+Opencv+海康SDK)
Posted boss-dog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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编译工具与项目构建
(由于之前一直都没用过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.h
,MvCameraControl.h
,MvErrorDefine.h
,PixelType.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.cppWindows下的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)的主要内容,如果未能解决你的问题,请参考以下文章