失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 基于Qt的海康威视SDK二次开发-摄像头登陆 预览和抓图

基于Qt的海康威视SDK二次开发-摄像头登陆 预览和抓图

时间:2023-01-13 21:14:53

相关推荐

基于Qt的海康威视SDK二次开发-摄像头登陆 预览和抓图

最近有个项目涉及海康威视的摄像头部分,需要在服务器端自动定时抓图,由于服务器端采用的是Windows系统,不熟Windows的api,所以直接采用Qt来编写。那么摄像头的激活配置什么的就不再介绍了,直接进入正题。

先下载海康的SDK,/cn/download_61.html,我的电脑系统是64位的,QT版本5.10.0,QT Creator是32位的,编译器是mingw32,介于编译器是32位,同时32位的程序能够在32、64位的系统下运行,但是64位的就只能在64位系统下运行,因此为了后期的兼容性,我下载了32位的SDK,至于能不能下载64位的SDK,可以自行尝试。

其次设置硬件设备,网络摄像头相当于一个服务器,我们的程序要访问它并获取视频数据,因此这个摄像头无论在内网还是外网,只要能访问到就行,最简单的方式就是ping它的IP,能通就行,我的IP是192.168.10.102,然后是服务端口,服务端口可以自行网页登陆摄像头查看,我这里是默认值,8000,然后是账号和密码,账号分为两种,管理员账号admin和普通账号,管理员账号的密码就是激活的时候让输入的密码,普通账号是激活后登陆摄像头自行设置的,我这里还是默认的admin和激活时候设置的密码。硬件环境大致就是这个样子。

然后新建一个Qt工程,我选择是继承于QWidget的类,当然其他基类也行,接着从下载的sdk里将头文件文件夹和库文件文件夹都拷到Qt工程目录下,分别修改为英文,我这里是include和libs,注意这里修改的名字应当和程序中对应;接下来是将库添加到QT工程中,使其编译时能够加载,库目录中有lib和dll,这两个都是库,这里插嘴说一下二者的区别,当Windows下一个工程编译成库时,可以有两种方式,第一种是静态库,第二种是动态库,静态库在编译时读取,动态库在运行时读取,生成静态库时只有lib文件,里边存放的就是函数的实现,生成动态库时,lib和dll文件都有,其中lib中没有函数的实现代码,只存放了该实现代码位于哪个dll中,dll中存放函数的实现代码;我们在调用静态库时,代码在链接阶段,将去对应lib中寻找实现代码,并进行链接,结束后,lib就没用了;而调用动态库时,代码在链接阶段也会去lib中寻找,不同的是,它只会留下标记,标识去哪里找运行代码,而不实际将dll中的实现链接进程序里,因此程序运行时不需要lib,但是必须有dll。言归正传,海康威视的SDK是动态库,我们需要指定lib文件的位置,运行时将dll文件放置在程序运行目录下即可,在QT中指定lib文件的位置是修改pro文件,添加如下代码:

LIBS +=-LH:/QTproject/HKDemo/HKDemo/libs -lHCCore -lHCNetSDK -lPlayCtrlLIBS +=-LH:/QTproject/HKDemo/HKDemo/libs/HCNetSDKCom -lHCAlarm -lHCGeneralCfgMgr -lHCPreview

和Linux系统的加库方法非常像,-L表示库的搜索路径,-l表示链接哪个库,注意这里的路径要写全,我试过相对路径,没有成功,至此编译时的库加入到了QT工程中。

接下来要做的就是写代码了,我们可以根据海康威视提供的文档进行编写,其文档位于开发文档目录下,我使用的是设备网络SDK使用手册.chm,我们可以在里边看到使用流程,及一些接口的依赖关系:

整个大的框架就是初始化,注册,预览,停止预览,注销,释放资源,初始化SDK和释放SDK资源不必多说,是sdk的基础操作,然后注册就是登陆摄像头,注销就是退出登陆,注意抓图分为两种,预览抓图和设备抓图,预览抓图必须先开启预览,而设备抓图不用,因为我是做服务器端程序用的,就使用了设备抓图,即不需要预览就可以抓图。

初始化SDK和释放SDK资源

SDK中初始化资源函数为NET_DVR_Init(),资源释放函数为NET_DVR_Cleanup()。

由于这是SDK的基础操作,我们在窗体的构造函数执行初始化SDK的操作,在析构函数中执行释放SDK资源的操作,初始化SDK和释放SDK的代码如下:

bool Widget::initSDK(){bool isok = NET_DVR_Init();if(isok == false){qDebug()<< "NET_DVR_Init error;error number is " <<NET_DVR_GetLastError();QMessageBox::warning(this,"error","NET_DVR_Init error;error number is "+QString::number(NET_DVR_GetLastError()));return isok;}//设置连接时间与重连时间NET_DVR_SetConnectTime(2000, 1);NET_DVR_SetReconnect(10000, true);return isok;}bool Widget::uninitSDK(){bool isok = NET_DVR_Cleanup();if(isok == false){qDebug()<< "NET_DVR_Cleanup error;error number is " <<NET_DVR_GetLastError();QMessageBox::warning(this,"error","NET_DVR_Cleanup error;error number "+QString::number(NET_DVR_GetLastError()));return isok;}return isok;}

登录和退出登录

其余接口不再累述,自己查即可,这里我用的是NET_DVR_Login_V30函数和NET_DVR_Logout,代码如下:

void Widget::OnClickedLogin(){NET_DVR_DEVICEINFO_V30 DeviceInfoTmp;userID=NET_DVR_Login_V30("192.168.10.102",8000,"admin","1234536asd",&DeviceInfoTmp);//参数依次为IP地址、服务端口、账号、密码,最后一个参数是为了获得硬件信息的if(userID<0){qDebug() << "NET_DVR_Login_V30 error;" << "error number is " << NET_DVR_GetLastError();QMessageBox::warning(this,"error","NET_DVR_Login_V30 error;error number "+QString::number(NET_DVR_GetLastError()));return;}qDebug()<<"Login Success,userID:" << userID<<endl;}void Widget::OnClickedLogout(){if(userID!=-1){if(NET_DVR_Logout(userID)==false){qDebug() << "NET_DVR_Logout error;" << "error number is " << NET_DVR_GetLastError();QMessageBox::warning(this,"error","NET_DVR_Logout error;error number "+QString::number(NET_DVR_GetLastError()));return;}userID=-1;qDebug() <<"Logout Success!"<<endl;}}

预览和停止预览

预览函数需要获得窗体句柄,并且是Windows api中定义的句柄,本质上来讲,QT写出的窗体也是windows窗体,我们这里直接定义一个label控件,控件中有个成员函数是专门获得windows下的窗体句柄的,传入该句柄后,函数就会自动向窗体传递图像信息并显示,不需我们的任何操作,同时也不会阻塞在这个函数,应该是直接利用了windows api的消息机制,代码如下:

void Widget::OnClickedPreview(){if(userID==-1){qDebug() <<"Need Login!"<<endl;QMessageBox::warning(this,"error","Need Login!");return;}HWND hWnd = (HWND)ui->label->winId();//HWND是windows api的窗体句柄类型NET_DVR_PREVIEWINFO struPlayInfo;previewID = play(hWnd,struPlayInfo);if(previewID==-1){return;}qDebug()<<"Preview Success!" << userID<<endl;}void Widget::OnClickedStopPreview(){if(previewID!=-1){if(NET_DVR_StopRealPlay(previewID)==false){qDebug() << "NET_DVR_StopRealPlay error;" << "error number is " << NET_DVR_GetLastError();QMessageBox::warning(this,"error","NET_DVR_StopRealPlay error;error number "+QString::number(NET_DVR_GetLastError()));return;}previewID=-1;qDebug() <<"Stop Preview Success!"<<endl;}}

抓图

这里使用的是设备抓图,即可以在登录后直接抓图,不需要预览,但是这个函数只能获取jpeg图像,会损失精度,可以采用预览抓图函数,其可以设置获取BMP图像还是jpeg图像。注意文件路径必须包括文件名字,还有Windows下的要加双斜杠,另外文件路径中的文件夹应当在该函数之前创建,代码如下:

void Widget::OnClickedCapture(){if(userID!=-1){NET_DVR_JPEGPARA IpJpegPara2;IpJpegPara2.wPicQuality=0;IpJpegPara2.wPicSize=0xff;QDateTime current_date_time =QDateTime::currentDateTime();QString current_date =current_date_time.toString("yyyy-MM-dd_hh-mm-ss_zzz");current_date="C:\\Picture\\"+current_date+".jpg";char* fileName;QByteArray ba = current_date.toLatin1(); // mustfileName=ba.data();if(NET_DVR_CaptureJPEGPicture(userID,1,&IpJpegPara2,fileName)==false){qDebug() << "NET_DVR_CaptureJPEGPicture error;" << "error number is " << NET_DVR_GetLastError();QMessageBox::warning(this,"error","NET_DVR_CaptureJPEGPicture error;error number "+QString::number(NET_DVR_GetLastError()));return;}qDebug() <<"Capture Success!"<<endl;}}

整体流程就是这个样子,下面给出完整代码。

main.cpp

#include "widget.h"#include <QApplication>int main(int argc, char *argv[]){QApplication a(argc, argv);Widget w;w.show();return a.exec();}

widget.h

#ifndef WIDGET_H#define WIDGET_H#include <QWidget>#include <QDateTime>#include "include/HCNetSDK.h"#include <windows.h>#include <QMessageBox>namespace Ui {class Widget;}class Widget : public QWidget{Q_OBJECTpublic:explicit Widget(QWidget *parent = 0);~Widget();long play(HWND hWnd,NET_DVR_PREVIEWINFO struPlayInfo);bool initSDK();bool uninitSDK();public slots:void OnClickedLogin();void OnClickedLogout();void OnClickedPreview();void OnClickedStopPreview();void OnClickedCapture();private:Ui::Widget *ui;long userID;long previewID;};#endif // WIDGET_H

widget.cpp

#include "widget.h"#include "ui_widget.h"#include <QDebug>Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget){ui->setupUi(this);userID=-1;previewID=-1;connect(ui->LoginButton,&QPushButton::clicked,this,&Widget::OnClickedLogin);connect(ui->LogoutButton,&QPushButton::clicked,this,&Widget::OnClickedLogout);connect(ui->PreviewButton,&QPushButton::clicked,this,&Widget::OnClickedPreview);connect(ui->StopPreviewButton,&QPushButton::clicked,this,&Widget::OnClickedStopPreview);connect(ui->CaptureButton,&QPushButton::clicked,this,&Widget::OnClickedCapture);if(initSDK())qDebug()<<"SDK init Success!"<<endl;}Widget::~Widget(){if(uninitSDK())qDebug()<<"SDK uninit Success!"<<endl;delete ui;}long Widget::play(HWND hWnd, NET_DVR_PREVIEWINFO struPlayInfo){struPlayInfo={0};struPlayInfo.hPlayWnd = hWnd;//需要 SDK 解码时句柄设为有效值,仅取流不解码时可设为空struPlayInfo.lChannel = 1;//预览通道号struPlayInfo.dwStreamType = 0;//码流类型:0-主码流,1-子码流,2-三码流,3-虚拟码流,以此类推struPlayInfo.dwLinkMode = 0;//0- TCP 方式,1- UDP 方式,2- 多播方式,3- RTP 方式,4-RTP/RTSP,5-RSTP/HTTPstruPlayInfo.bBlocked = 1;//0- 非阻塞取流,1- 阻塞取流long IRealPlayHandle = NET_DVR_RealPlay_V40(userID,&struPlayInfo,NULL,NULL);if(IRealPlayHandle <0){qDebug() << "NET_DVR_RealPlay_V40 error;error number " <<NET_DVR_GetLastError();QMessageBox::warning(this,"error","NET_DVR_RealPlay_V40 error;error number "+QString::number(NET_DVR_GetLastError()));NET_DVR_Logout(userID);userID=-1;return -1;}return IRealPlayHandle;}bool Widget::initSDK(){bool isok = NET_DVR_Init();if(isok == false){qDebug()<< "NET_DVR_Init error;error number is " <<NET_DVR_GetLastError();QMessageBox::warning(this,"error","NET_DVR_Init error;error number is "+QString::number(NET_DVR_GetLastError()));return isok;}//设置连接时间与重连时间NET_DVR_SetConnectTime(2000, 1);NET_DVR_SetReconnect(10000, true);return isok;}bool Widget::uninitSDK(){bool isok = NET_DVR_Cleanup();if(isok == false){qDebug()<< "NET_DVR_Cleanup error;error number is " <<NET_DVR_GetLastError();QMessageBox::warning(this,"error","NET_DVR_Cleanup error;error number "+QString::number(NET_DVR_GetLastError()));return isok;}return isok;}void Widget::OnClickedLogin(){NET_DVR_DEVICEINFO_V30 DeviceInfoTmp;userID=NET_DVR_Login_V30("192.168.10.102",8000,"admin","5456123asdas",&DeviceInfoTmp);if(userID<0){qDebug() << "NET_DVR_Login_V30 error;" << "error number is " << NET_DVR_GetLastError();QMessageBox::warning(this,"error","NET_DVR_Login_V30 error;error number "+QString::number(NET_DVR_GetLastError()));return;}qDebug()<<"Login Success,userID:" << userID<<endl;}void Widget::OnClickedLogout(){if(userID!=-1){if(NET_DVR_Logout(userID)==false){qDebug() << "NET_DVR_Logout error;" << "error number is " << NET_DVR_GetLastError();QMessageBox::warning(this,"error","NET_DVR_Logout error;error number "+QString::number(NET_DVR_GetLastError()));return;}userID=-1;qDebug() <<"Logout Success!"<<endl;}}void Widget::OnClickedPreview(){if(userID==-1){qDebug() <<"Need Login!"<<endl;QMessageBox::warning(this,"error","Need Login!");return;}HWND hWnd = (HWND)ui->label->winId();NET_DVR_PREVIEWINFO struPlayInfo;previewID = play(hWnd,struPlayInfo);if(previewID==-1){return;}qDebug()<<"Preview Success!" << userID<<endl;}void Widget::OnClickedStopPreview(){if(previewID!=-1){if(NET_DVR_StopRealPlay(previewID)==false){qDebug() << "NET_DVR_StopRealPlay error;" << "error number is " << NET_DVR_GetLastError();QMessageBox::warning(this,"error","NET_DVR_StopRealPlay error;error number "+QString::number(NET_DVR_GetLastError()));return;}previewID=-1;qDebug() <<"Stop Preview Success!"<<endl;}}void Widget::OnClickedCapture(){if(userID!=-1){NET_DVR_JPEGPARA IpJpegPara2;IpJpegPara2.wPicQuality=0;IpJpegPara2.wPicSize=0xff;QDateTime current_date_time =QDateTime::currentDateTime();QString current_date =current_date_time.toString("yyyy-MM-dd_hh-mm-ss_zzz");current_date="C:\\Picture\\"+current_date+".jpg";char* fileName;QByteArray ba = current_date.toLatin1(); // mustfileName=ba.data();if(NET_DVR_CaptureJPEGPicture(userID,1,&IpJpegPara2,fileName)==false){qDebug() << "NET_DVR_CaptureJPEGPicture error;" << "error number is " << NET_DVR_GetLastError();QMessageBox::warning(this,"error","NET_DVR_CaptureJPEGPicture error;error number "+QString::number(NET_DVR_GetLastError()));return;}qDebug() <<"Capture Success!"<<endl;}}

发布应用

发布应用应当以release模式编译,然后使用windeployqt 工具进行qt依赖项的导出,接着要将海康威视的dll也放入可执行文件目录下,这里为简单起见,直接将下载的海康威视的sdk中的库文件中的所有文件、目录复制到可执行文件目录下,如下图所示:

仍无法实现的,可以下载我打包好的,包括源代码和可执行文件及其依赖项。发布的应用里直接写死了IP和端口,可以在源码中修改为窗体输入。/download/cx296649890/11574696

如果觉得《基于Qt的海康威视SDK二次开发-摄像头登陆 预览和抓图》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。