日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2023/12/20 编程问答 108 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于Qt的海康威视SDK二次开发-摄像头登陆、预览和抓图 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最近有個項目涉及海康威視的攝像頭部分,需要在服務器端自動定時抓圖,由于服務器端采用的是Windows系統,不熟Windows的api,所以直接采用Qt來編寫。那么攝像頭的激活配置什么的就不再介紹了,直接進入正題。

先下載海康的SDK,https://www.hikvision.com/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 -lPlayCtrl LIBS +=-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和端口,可以在源碼中修改為窗體輸入。https://download.csdn.net/download/cx296649890/11574696

總結

以上是生活随笔為你收集整理的基于Qt的海康威视SDK二次开发-摄像头登陆、预览和抓图的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。