最近作的一个项目须要调用一个海康威视的摄像头,获取每一帧的数据。刚拿到手的时候有些不知所措,花了两三个小时看了下官方文档,下面分享一下代码ios
opencv+摄像头依赖bash
摄像头依赖可在海康威视官网找到,内容以下:函数
#头文件 DataType.h DecodeCardSdk.h HCNetSDK.h plaympeg4.h #动态/静态连接库 AnalyzeData.dll AudioIntercom.dll AudioRender.dll D3DCompiler_43.dll d3dx9_43.dll EagleEyeRender.dll GdiPlus.dll GdiPlus.lib HCAlarm.dll HCAlarm.lib HCCore.dll HCCore.lib HCCoreDevCfg.dll HCDisplay.dll HCGeneralCfgMgr.dll HCGeneralCfgMgr.lib HCIndustry.dll HCNetSDK.dll HCNetSDK.lib HCPlayBack.dll HCPreview.dll HCPreview.lib HCVoiceTalk.dll HWDecode.dll libiconv2.dll libmmd.dll MP_Render.dll OpenAL32.dll PlayCtrl.dll PlayCtrl.lib StreamTransClient.dll SuperRender.dll SystemTransform.dll YUVProcess.dll
方案一:经过“抓拍”接口抓取每一帧(实际基本不能实时,大概最快一秒一帧)测试
#define _CRT_SECURE_NO_WARNINGS #include <cstdlib> #include <cstring> #include <direct.h> #include <io.h> #include <iostream> #include <time.h> #include <fstream> #include <cstring> #include "Windows.h" #include "HCNetSDK.h" #include "plaympeg4.h" using namespace std; int main_old() { // 初始化设备 NET_DVR_Init(); //设置链接时间与重连时间 NET_DVR_SetConnectTime(2000, 3); //等待时间,重连次数 NET_DVR_SetReconnect(10000, true); //重连间隔,是否重连 //注册设备 NET_DVR_DEVICEINFO_V30 struDeviceInfo; //定义设备参数的结构体,NET_DVR_Login_V30中初始化 char ip[] = "192.168.0.64"; int port = 8000; char user[] = "account"; char password[] = "password"; LONG lUserID = NET_DVR_Login_V30(ip, port,user,password, &struDeviceInfo); //注册设备,参数存储在struDeviceInfo中,返回用户ID>=0号 //注册失败 if (lUserID < 0) { printf("Login error, %d\n", NET_DVR_GetLastError()); NET_DVR_Cleanup(); return 0; } NET_DVR_JPEGPARA JpegPara; JpegPara.wPicSize = 19; //1920*1080 JpegPara.wPicQuality = 0; //最好质量 const DWORD maxBuffer = 1000000; char *jpeg = (char*)calloc(sizeof(char), maxBuffer); DWORD size = 0; //计算时间 for (int i = 0; i < 100; i++) { clock_t start = clock(); if (!NET_DVR_CaptureJPEGPicture_NEW(lUserID, 1, &JpegPara, jpeg, maxBuffer, &size)) { std::cout << "error:" << NET_DVR_GetLastError() << std::endl; continue; } clock_t end = clock(); std::cout << "帧花费时间:" << ((double)(end - start)) / CLOCKS_PER_SEC << "s" << endl; } //图片写入磁盘 if (_access("Pictures", 0) == -1) { int i = _mkdir("Pictures"); } for (int i = 0; i < 1000; i++) { if (!NET_DVR_CaptureJPEGPicture_NEW(lUserID, 1, &JpegPara, jpeg, maxBuffer, &size)) { std::cout << "error:" << NET_DVR_GetLastError() << std::endl; continue; } std::cout <<"size of "<<i<<".jpeg: "<< size <<"Byte" << std::endl; ofstream outFile; char fileName[100]; sprintf(fileName, "Pictures\\%d.jpeg", i); outFile.open(fileName, ios::binary | ios::out); if (!outFile.is_open()) { std::cout << "fail to create/open Pictures\\" << i << ".jpeg" << std::endl; continue; } outFile.write(jpeg, size); outFile.close(); std::cout << std::endl; } free(jpeg); //注销用户 NET_DVR_Logout(lUserID); //释放SDK资源 NET_DVR_Cleanup(); system("pause"); return 0; }
方案二:经过实时回调获取每一帧(基本能作到实时)spa
#include <cstdlib> #include <cstring> #include <direct.h> #include <stdlib.h> #include <io.h> #include <iostream> #include "Windows.h" #include "HCNetSDK.h" #include "plaympeg4.h" #include <opencv2\opencv.hpp> #include <time.h> using namespace std; using namespace cv; //回调函数声明 void CALLBACK DecCBFun(long nPort, char * pBuf, long nSize, FRAME_INFO * pFrameInfo, long nReserved1, long nReserved2); // 二级回调 void CALLBACK fRealDataCallBack(LONG lRealHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, void *pUser); // 数据触发。(V40句柄,数据类型,缓冲区指针,缓冲区大小,用户数据) void CALLBACK g_ExceptionCallBack(DWORD dwType, LONG lUserID, LONG lHandle, void *pUser); // 异常时触发 //void CALLBACK CBFun(long nPort, char *pBuf, long nSize, long nWidth, long nHeight, long nStamp, long nType, long nReceved); clock_t startTime, endTime; int main() { //初始化摄像头 NET_DVR_Init(); NET_DVR_SetConnectTime(2000, 1); //链接等待2s,重连1次 NET_DVR_SetReconnect(10000, true); //10秒重连,启动重连 //图片写入磁盘,测试使用 if (_access("Pictures_in_T_YV12", 0) == -1) { int i = _mkdir("Pictures_in_T_YV12"); } //定义登陆相关参数 char ip[] = "192.168.0.64"; int port = 8000; char user[] = "account"; char password[] = "password"; NET_DVR_DEVICEINFO_V30 struDeviceInfo; //存储设备相关参数 //启动登陆 LONG userID = NET_DVR_Login_V30(ip, port, user, password, &struDeviceInfo); //注册设备,参数存储在struDeviceInfo中,返回用户ID>=0号 //登陆结果判断 if (userID < 0) { printf("登陆摄像头出错, 错误代码:%d\n", NET_DVR_GetLastError()); NET_DVR_Cleanup(); system("pause"); return 0; } NET_DVR_SetExceptionCallBack_V30(0, NULL, g_ExceptionCallBack, NULL); //设置异常回调 //定义预览参数 NET_DVR_PREVIEWINFO struPlayInfo = { 0 }; struPlayInfo.hPlayWnd = NULL; //不使用预览界面 struPlayInfo.lChannel = 1; //预览通道号 = 1 struPlayInfo.dwStreamType = 0; //0:主码流 struPlayInfo.dwLinkMode = 0; //0- TCP方式,1- UDP方式,2- 多播方式,3- RTP方式,4-RTP/RTSP,5-RSTP/HTTP //设置实时回调 LONG handle = NET_DVR_RealPlay_V40(userID, &struPlayInfo, fRealDataCallBack, NULL); //启动实时预览 //预览判断 if (handle < 0) { printf("实时预览调用出错,错误代码:%d\n", NET_DVR_GetLastError()); NET_DVR_Logout(userID); NET_DVR_Cleanup(); system("pause"); return 0; } //waitKey(); Sleep(-1); //相关释放 NET_DVR_StopRealPlay(handle); //关闭预览 NET_DVR_Logout(userID); //注销用户 NET_DVR_Cleanup(); //释放SDK资源 system("pause"); return 0; } //实时数据触发调用 (V40句柄,数据类型,缓冲区指针,缓冲区大小,用户数据) void CALLBACK fRealDataCallBack(LONG lRealHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, void *pUser) { static LONG nPort = -1; //实时预览通道号 switch (dwDataType) { case NET_DVR_SYSHEAD: //头部数据 if (!PlayM4_GetPort(&nPort)) //申请播放port,存为全局变量,供后面使用 { break; } if (dwBufSize > 0) //数据长度>0 { if (!PlayM4_SetStreamOpenMode(nPort, STREAME_REALTIME)) //设置流处理模式 STREAME_REALTIME:尽力实时,不阻塞 STREAME_FILE:按照时间戳 { break; } if (!PlayM4_OpenStream(nPort, pBuffer, dwBufSize, 1024 * 100000)) //打开流接口,缓冲区设置为最大 { break; } if (!PlayM4_Play(nPort, NULL)) //开始处理,不设置窗口句柄 { break; } if (!PlayM4_SetDecCallBack(nPort, DecCBFun)) //设置自定义的解码回调函数 DecCBFun { break; } } break; case NET_DVR_STREAMDATA: //流数据 if (dwBufSize > 0 && nPort != -1) { if (!PlayM4_InputData(nPort, pBuffer, dwBufSize)) { cout << "error" << PlayM4_GetLastError(nPort) << endl; break; } } break; default: //其余数据 if (dwBufSize > 0 && nPort != -1) { if (!PlayM4_InputData(nPort, pBuffer, dwBufSize)) { break; } } break; } } //实时解码回调 void CALLBACK DecCBFun(long nPort, char * pBuf, long nSize, FRAME_INFO * pFrameInfo, long nReserved1, long nReserved2) { static int number = 0; if (pFrameInfo->nType == T_YV12) //YV12:视频格式 PCM:音频 { Mat src(pFrameInfo->nHeight + pFrameInfo->nHeight / 2, pFrameInfo->nWidth, CV_8UC1, pBuf); cvtColor(src, src, CV_YUV2BGR_YV12); char name[100]; sprintf_s(name, "Pictures_in_T_YV12\\%d.jpg", number); //保存在磁盘为jpg imwrite(name, src); number++; } } //异常触发 void CALLBACK g_ExceptionCallBack(DWORD dwType, LONG lUserID, LONG lHandle, void *pUser) { switch (dwType) { case EXCEPTION_RECONNECT: //预览时触发"重连"信号 printf("设备从新链接,当前时间为:%d\n", (int)time(NULL)); break; default: //默认不做处理 break; } }