C++调用海康相机SDK采集图像(C++\QT Creator\openCV\线程\接口)
C++调用海康相机SDK采集图像(C++\QT Creator\openCV\线程\接口)
之前写了一篇关于C++调用海康相机SDK采集图像的文章,有很多人私下发送消息咨询了一些问题,由于工作繁忙,只答复了一部分问题,今天抽出时间从头梳理了一下大家提出的问题,把我能够回答的问题都解答一次。上一次的程序只是简单的实现了图像的采集,没有使用到线程,今天把程序重新做出调整,把线程和多态加进去。文章最后有项目的下载地址。
我使用的是QT Creator这个IDE,版本信息如下:
我把相机采集的图像转换为openCV能够处理的cv::Mat格式,所以首先要在QT Creator中配置openCV,使用的openCV为3.0版本,具体配置方法不做介绍,网上有非常多的教程。
1.创建QT项目,在pro文件中添加相机的引用文件,pro位置如下:
首先要添加MvCameraControl.lib库文件,该文件位置在\MVS\Development\Libraries\win64下。
此处需要注意一点:我第一次引用这个位置的lib文件的时候遇到了问题,提示找不到文件,考虑是否因为MVS软件安装的上级路径中存在空格等字符,因此把这个文件复制到了E:\Hik_Libs目录下,引用成功。于是就把Hik_Libs目录连同里面的文件复制到了项目目录下。
pro文件中添加如下代码:LIBS += -L$$PWD/Hik_Libs/ -lMvCameraControl
其中-L(大写L)代表目录地址,的 $ $PWD代表项目目录位置,-l(小写l)代表具体文件,引用的lib文件不要添加扩展名(.lib),QT可跨平台,扩展名会根据平台自动选择。
pro文件中添加包含路径,包含的文件在如下位置:\MVS\Development\Includes。
同样存在MVS目录上级目录存在空格符号的问题,我把\MVS\Development\Includes下的内容复制到了QT项目文件下的Hik_Includes目录中。
pro文件中添加如下代码:INCLUDEPATH += $$PWD/Hik_Includes
在截图中,E:/opencv3.0/build_VS2013_x64/install/include这一句是我已经添加的opencv3.0包含路径。
添加完成后右键单击项目文件(如下图),执行qmake,完成相关引用文件的添加。
2.设计QT布局。布局非常简单,在QT中放置一个Label标签,利用这个Label进行图像的显示,添加4个按钮,用于实现连接相机,采集单张图像,采集连续图像和停止连续采集的功能。
3.创建一个抽象类,在抽象类里面添加纯虚函数,作为相机类的基类,实现接口功能。实际上就是多态这个功能,了解的可以跳过。对于不了解的,我就献丑简单的介绍一下。
首先介绍一下为什么要这样操作。之前有人问到过我,在做项目中,避免不了会用到很多种不同品牌的相机,有些情况下,整个设备可能只有相机不同,这时,如果针对不同品牌的相机生成对应的客户端程序版本,这样处理不够合理,也非常繁琐,极易出现问题。因此考虑使用抽象类的方式来解决这个问题,可以利用抽象类创建一个相机变量,再根据具体使用的相机品牌进行具体的实例化,从而实现对该品牌相机的操作。举个例子:电脑上的USB接口,把它理解为一个抽象类,USB接口的物理尺寸、电压、电流、规定的通讯方式等,这些特性就是它的纯虚函数,相关的USB设备,比如鼠标、U盘、USB接口的LED灯等,必须实现每一个纯虚函数(实现纯虚函数可以理解为必须满足这个要求,比如说U盘必须满足USB接口尺寸这个要求,否则就插不进去。有人可能会问了,LED灯满足尺寸、电压、电流的要求,但是没有通讯,这又如何理解?LED灯插到USB接口上了,上位机有和它通讯,LED灯接受到了,它的处理方式就是不做回应,这也是一种处理的方式)。这样就实现了USB接口的功能,只要遵循USB协议的设备,就可以在USB接口上进行使用,从而实现了接口的功能。
我们在程序上如何实现呢?创建一个抽象类,也就是函数中包含纯虚函数,纯虚函数只需要声明,不需要在这个类中实现,声明的方式如下:virtual 返回类型 函数名称(形参)=0;其中结尾处“=0”必须要添加。在这个抽象函数中创建用于控制相机的纯虚函数,作为接口。再编写实际的相机SDK类中,要求集成这个抽象类,然后实现抽象类中的每一次纯虚函数方法(相当于按照接口的规定开发相应的功能)。此处引用我项目中的方式进行介绍,我在项目中创建了一个相机的抽象类CameraInterface,其中添加连接相机的纯虚函数connectCamera,声明方式如下:
然后我在具体的海康相机SDK类(类的名称为HikvisionSDK)中去继承这个抽象类,继承抽象类要求必须覆写抽象类中的纯虚函数,因此我在海康相机SDK类中重新声明并实现这个函数,如下:
这样,在使用的时候,我可以这样操作,CameraInterface* camera= new HikvisionSDK() 。注意,我使用抽象类来声明变量名,用具体的相机SDK类来实例化,从而实现对相机的操作。这样以来,只要添加的具体相机SDK类都继承这个抽象类,并实现对纯虚函数进行实现,那么都可以用这个方式实例化相机对象,也就是说对于不同品牌的相机,只是在实例化的位置选择对应的SDK类即可,对于相机对象这个变量以及实现相应操作的函数名称都无需改动。
在创建相机具体的SDK类的时候,需要包含接口类的头文件和海康相机的相关头文件
3.创建线程类
线程类中实现这样的功能:开启线程后进入一个循环程序,发送软触发----读取图像----发送信号—延时-----发送软触发…
因为涉及执行线程内容、操作相机、读取图像以及发送信号,所以线程类中包含了以下一个方法
void run():继承QThread类,覆写这个方法,run()函数中就是线程中需要执行的内容。
void getCameraPtr(CameraInterface* camera):获取相机对象指针
void getImagePtr(cv::Mat* image):获取用于读取图像的指针
signals: void mess():用于发送信号,从而更新UI
上面的截图是线程类的头文件,其中需要添加包含文件#include"QThread",注意一定要添加 Q_OBJECT这一句,因为使用到了QT中信号和槽的功能。我在添加的时候遇到了问题,程序是按照截图中的方式编写,不存在任何编写错误,但是编译的时候就会报错,最后将#include"QThread"移动到#include"camerainterface.h"下面后,编译通过…再移动回原来位置,编译也是通过,不清楚什么原因。
4.实现相应功能。
在界面类MainWindow的头文件中定义相关的槽信号函数
private slots: void display();
该函数用于和线程中的信号函数相连接,实现界面的刷新。
还需要说明的一点是,我们是用QT控件中的Label标签进行图像的显示,就需要将openCV的Mat格式转换为QImage格式才能够进行显示。这一部分都写在了用于显示图像的槽函数display()中。
之前写过一篇关于海康相机SDK的文章,里面对于功能设置部分有详细的介绍,地址如下:
https://blog.****.net/biggestcherry/article/details/87011094
工程文件源码已经上传,下载地址如下:
https://download.****.net/download/biggestcherry/12426729
水平有限,难免有错误和不足之处,恳请批评指正。