在笔记1中,学会了用opencv打开USB摄像头,但是有时候我们需要用到网络摄像头,我们该怎么去调用,并用opencv做图像处理呢?我们以海康威视网络摄像头举例:
首先配置好环境:
在官网下载SDK文件,点击打开链接,对照自己的开发平台,选择下载,我下载的是设备网络SDK-Win32。下载好之后,将其解压到本地中。
VC++包含目录中添加头文件,我的地址是:E:\CH-HCNetSDK(Windows32)V5.3.1.20_build20170820\CH-HCNetSDK(Windows32)V5.3.1.20_build20170820\include。
同样,VC++库目录中添加lib路径,我的地址是:E:\CH-HCNetSDK(Windows32)V5.3.1.20_build20170820\CH-HCNetSDK(Windows32)V5.3.1.20_build20170820\lib。
链接器、输入、附加依赖项里,添加SDK中的lib:GdiPlus.lib、HCCore.lib、HCCore.lib、PlayCtrl.lib。
做好上面的步骤,保存就行了。
接下来就是编写代码:
#include <cstdlib>
#include <cstring>
#include <iostream>
#include "Windows.h"
#include "HCNetSDK.h"
#include "plaympeg4.h"
#include <opencv2\opencv.hpp>
#include <time.h>
using namespace std;
using namespace cv;
LONG nPort = -1;
volatile int gbHandling = 3;
//解码回调 视频为YUV数据(YV12),音频为PCM数据
void CALLBACK DecCBFun(long nPort, char * pBuf, long nSize, FRAME_INFO * pFrameInfo, long nReserved1, long nReserved2)
{
if (gbHandling)
{
gbHandling--;
return;
}
long lFrameType = pFrameInfo->nType;
if (lFrameType == T_YV12)
{
Mat pImg(pFrameInfo->nHeight, pFrameInfo->nWidth, CV_8UC3);
Mat src(pFrameInfo->nHeight + pFrameInfo->nHeight / 2, pFrameInfo->nWidth, CV_8UC1, pBuf);
cvtColor(src, pImg, CV_YUV2BGR_YV12);
imshow("opencamera", pImg);
waitKey(1);
}
gbHandling = 3;
}
///实时流回调
void CALLBACK fRealDataCallBack(LONG lRealHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, void *pUser)
{
switch (dwDataType)
{
case NET_DVR_SYSHEAD: //系统头
if (!PlayM4_GetPort(&nPort)) //获取播放库未使用的通道号
{
break;
}
//m_iPort = lPort; //第一次回调的是系统头,将获取的播放库port号赋值给全局port,下次回调数据时即使用此port号播放
if (dwBufSize > 0)
{
if (!PlayM4_SetStreamOpenMode(nPort, STREAME_REALTIME)) //设置实时流播放模式
{
break;
}
if (!PlayM4_OpenStream(nPort, pBuffer, dwBufSize, 10 * 1024 * 1024)) //打开流接口
{
break;
}
if (!PlayM4_Play(nPort, NULL)) //播放开始
{
break;
}
if (!PlayM4_SetDecCallBack(nPort, 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 g_ExceptionCallBack(DWORD dwType, LONG lUserID, LONG lHandle, void *pUser)
{
char tempbuf[256] = { 0 };
switch (dwType)
{
case EXCEPTION_RECONNECT: //预览时重连
printf("----------reconnect--------%d\n", time(NULL));
break;
default:
break;
}
}
void main()
{
// 初始化
NET_DVR_Init();
//设置连接时间与重连时间
NET_DVR_SetConnectTime(2000, 1);
NET_DVR_SetReconnect(10000, true);
// 注册设备
LONG lUserID;
NET_DVR_DEVICEINFO_V30 struDeviceInfo;
lUserID = NET_DVR_Login_V30("10.170.6.185", 8000, "admin", "abc20170620", &struDeviceInfo);
if (lUserID < 0)
{
printf("Login error, %d\n", NET_DVR_GetLastError());
NET_DVR_Cleanup();
return;
}
//设置异常消息回调函数
NET_DVR_SetExceptionCallBack_V30(0, NULL, g_ExceptionCallBack, NULL);
//启动预览并设置回调数据流
NET_DVR_CLIENTINFO ClientInfo;
ClientInfo.lChannel = 1; //Channel number 设备通道号
ClientInfo.hPlayWnd = NULL; //窗口为空,设备SDK不解码只取流
ClientInfo.lLinkMode = 0; //Main Stream
ClientInfo.sMultiCastIP = NULL;
LONG lRealPlayHandle;
lRealPlayHandle = NET_DVR_RealPlay_V30(lUserID, &ClientInfo, fRealDataCallBack, NULL, TRUE);
if (lRealPlayHandle<0)
{
printf("NET_DVR_RealPlay_V30 failed! Error number: %d\n", NET_DVR_GetLastError());
return;
}
//cvWaitKey(0);
Sleep(-1);
//fclose(fp);
//关闭预览
if (!NET_DVR_StopRealPlay(lRealPlayHandle))
{
printf("NET_DVR_StopRealPlay error! Error number: %d\n", NET_DVR_GetLastError());
return;
}
//注销用户
NET_DVR_Logout(lUserID);
NET_DVR_Cleanup();
return;
}
解码回调函数里我们用了cvtcolor函数将采集到的YUV格式转换为RGB,这样可以让opencv进行处理。接下来做图像处理时,一个比较好的思路是将一帧一帧的数据送到队列中,再开启一个线程从队列取出进行处理就可以了。 程序运行:
工程下载:点击打开链接(内附海康威视错误代码大全)
参考博客:http://blog.csdn.net/wanghuiqi2008/article/details/31410509
http://blog.csdn.net/m0_37901643/article/details/72817862