海康威视IPCamera图像捕获
捕获海康威视IPCamera图像,转成OpenCV可以处理的IplImage图像(一)
捕获海康威视IPCamera图像,转成OpenCV可以处理的IplImage图像(二)
所使用海康威视摄像头型号:DS-2CD4026FWD-(A)(P)
海康威视IPCamera图像捕获方法有两种:
(1)利用SDK里面的NET_DVR_CaptureJPEGPicture_NEW进行视频抓图
(2)捕获实时流,将实时流解码成YV12,然后转换成RGB
在上一篇博文里,我介绍了第一种方法,但是由于NET_DVR_CaptureJPEGPicture_NEW该函数执行需要较长时间,无法实时,所以必须继续第二种方法。
在这篇博文里,我将介绍第二种方法,将捕获到的海康威视IPCamera摄像头图像转成OpenCV能处理的IplImage图像。
在实现完捕获海康威视IPCamera图像,转成OpenCV可以处理的IplImage图像(一)里面的方法后,发现不能实时,这个系统我是要做给给人看的,是需要实时演示的,这样子肯定是不行的。纠结了好久!然后查看海康威视《设备网络SDK使用手册_V4.2》,里面有一个预览模块示例程序,可惜我一直运行不了,报出的错误是PROCGETCONSOLEWINDOW GetConsoleWindow中的GetConsoleWindow被重定义,后来一直调试没调成功。
实在是没辙了,打海康客服,不过海康的客服我实在无语,北京的完全无法接通,直接打杭州的,打了四五遍终于有个人接电话了,对方不懂,然后说让个工程师回电话。OK,终于回了。他告诉我http://www.hikvision.com/cn/download_more_401.html 这里是有例程的,有分功能示例!突然间有了希望了,例程是VC6.0工程,改了一些地方后,终于能运行了。于是,将他的MFC工程相关的代码抠出来,重组。于是实现了捕获YV12格式的视频流的功能,光有YV12还是不行的,需要将YV12转成YUV4:4:4的,然后再将YUV色度空间转换成RGB色度空间,这个过程是在信件的DecBFun回调函数(回调函数请看这里!)里面执行的。
不多说了,上代码!
- #include <cstdio>
- #include <cstring>
- #include <iostream>
- #include "Windows.h"
- #include "HCNetSDK.h"
- #include "PlayM4.h"
- #include <opencv2\opencv.hpp>
- #include "cv.h"
- #include "highgui.h"
- #include <time.h>
- #define USECOLOR 1
- using namespace std;
- using namespace std;
-
-
- int iPicNum=0;
- LONG nPort=-1;
- HWND hWnd=NULL;
-
-
- void yv12toYUV(char *outYuv, char *inYv12, int width, int height,int widthStep)
- {
- int col,row;
- unsigned int Y,U,V;
- int tmp;
- int idx;
-
-
-
- for (row=0; row<height; row++)
- {
- idx=row * widthStep;
- int rowptr=row*width;
-
- for (col=0; col<width; col++)
- {
-
- tmp = (row/2)*(width/2)+(col/2);
-
-
-
-
-
- Y=(unsigned int) inYv12[row*width+col];
- U=(unsigned int) inYv12[width*height+width*height/4+tmp];
- V=(unsigned int) inYv12[width*height+tmp];
-
-
-
-
-
-
- if((idx+col*3+2)> (1200 * widthStep))
- {
-
- }
- outYuv[idx+col*3] = Y;
- outYuv[idx+col*3+1] = U;
- outYuv[idx+col*3+2] = V;
- }
- }
-
- }
-
-
-
-
- void CALLBACK DecCBFun(long nPort,char * pBuf,long nSize,FRAME_INFO * pFrameInfo, long nReserved1,long nReserved2)
- {
- long lFrameType = pFrameInfo->nType;
-
- if(lFrameType ==T_YV12)
- {
- #if USECOLOR
-
- IplImage* pImgYCrCb = cvCreateImage(cvSize(pFrameInfo->nWidth,pFrameInfo->nHeight), 8, 3);
- yv12toYUV(pImgYCrCb->imageData, pBuf, pFrameInfo->nWidth,pFrameInfo->nHeight,pImgYCrCb->widthStep);
- IplImage* pImg = cvCreateImage(cvSize(pFrameInfo->nWidth,pFrameInfo->nHeight), 8, 3);
- cvCvtColor(pImgYCrCb,pImg,CV_YCrCb2RGB);
-
- #else
- IplImage* pImg = cvCreateImage(cvSize(pFrameInfo->nWidth,pFrameInfo->nHeight), 8, 1);
- memcpy(pImg->imageData,pBuf,pFrameInfo->nWidth*pFrameInfo->nHeight);
- #endif
-
- cvShowImage("IPCamera",pImg);
- cvWaitKey(1);
- #if USECOLOR
- cvReleaseImage(&pImgYCrCb);
- cvReleaseImage(&pImg);
- #else
- cvReleaseImage(&pImg);
- #endif
-
-
- }
-
-
-
-
-
-
-
-
-
-
-
-
- }
-
-
-
- void CALLBACK fRealDataCallBack(LONG lRealHandle,DWORD dwDataType,BYTE *pBuffer,DWORD dwBufSize,void *pUser)
- {
- DWORD dRet;
- switch (dwDataType)
- {
- case NET_DVR_SYSHEAD:
- if (!PlayM4_GetPort(&nPort))
- {
- break;
- }
- if(dwBufSize > 0)
- {
- if (!PlayM4_OpenStream(nPort,pBuffer,dwBufSize,1024*1024))
- {
- dRet=PlayM4_GetLastError(nPort);
- break;
- }
-
- if (!PlayM4_SetDecCallBack(nPort,DecCBFun))
- {
- dRet=PlayM4_GetLastError(nPort);
- break;
- }
-
-
-
-
-
-
-
-
-
- if (!PlayM4_Play(nPort,hWnd))
- {
- dRet=PlayM4_GetLastError(nPort);
- break;
- }
-
-
- if (!PlayM4_PlaySound(nPort))
- {
- dRet=PlayM4_GetLastError(nPort);
- break;
- }
- }
- break;
-
- case NET_DVR_STREAMDATA:
- if (dwBufSize > 0 && nPort != -1)
- {
- BOOL inData=PlayM4_InputData(nPort,pBuffer,dwBufSize);
- while (!inData)
- {
- Sleep(10);
- inData=PlayM4_InputData(nPort,pBuffer,dwBufSize);
- OutputDebugString(L"PlayM4_InputData failed \n");
- }
- }
- 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.102.7.88", 8000, "admin", "12345", &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;
- ClientInfo.hPlayWnd = NULL;
- ClientInfo.lLinkMode = 0;
- 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;
- }
-
-
- Sleep(-1);
-
-
-
-
- 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;
- }
终于能够实时捕获图像了,而且转换成了OpenCV能够处理的图像格式。
在这个过程中搜了很多资料,但是没有一个地方能详细说明,不过最终还是把这个给解决了。
附加说明:如果最后要做图像处理而不是像我这样只是将采集的图像显示出来,那么下面的语句是不需要的。
- #if USECOLOR
- cvReleaseImage(&pImgYCrCb);
- cvReleaseImage(&pImg);
- #else
- cvReleaseImage(&pImg);
- #endif
后记:虽然这个功能实现了,但是与我的图像处理函数如何结合到一起?我想到的是用链队列,双线程。链队列代码请看这里!
写这两篇博文的目的其实也是想让处于探索过程中的开发人员能少走些弯路,节省些时间,衷心希望本文能够帮到你!
因为本人已经毕业,项目也早就已经结题了,手头上不再具有可供调试的硬件设备,因此对于大家所碰到的问题,我基本上也已经无法回答了,非常抱歉!如果大家在开发海康威视摄像头的过程中遇到了什么问题可以去跟海康客服去沟通,如果您所在地区的客服无法联系上的话,请直接联系杭州总部的客服。
最后,对之前很长一段时间对大家所提出的问题一直置之不理再次表示道歉!谢谢大家的支持!
**************************************************************************************
转载请注明出处:http://blog.csdn.net/wanghuiqi2008/article/details/31410509
**************************************************************************************
28楼 LHY_045 2016-05-22 21:37发表 [回复]-
-
我有一个问题,我认为队列种的图像处理的速度比摄像头写入的速度慢,因为如果作人脸识别或者是行人识别那么处理速度会很慢,写入的速度快的话会造成队列的长度越来越大,这个问题怎么解决???
27楼 qq_32414847 2016-03-12 15:39发表 [回复]-
-
如果不用Opencv处理,用C++实现,请问大概流程?
26楼 竹斋 2016-03-11 00:12发表 [回复]-
-
调取解码之后,不知道怎么调用做接下来的图像处理啊,麻烦大神给我指点一下啊,万分感谢!
25楼 wangfei198857 2016-01-06 13:55发表 [回复]-
-
楼主你好!请问你的代码运行在什么环境?
我的在VC6.0 + opencv1.0下报错
error C2664: 'OutputDebugStringA' : cannot convert parameter 1 from 'unsigned short [26]' to 'const char *'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
请问楼主的#include <opencv2\opencv.hpp>是opencv2版本的吗?
24楼 qq_33021543 2015-12-22 14:46发表 [回复]-
-
楼主,我在控制台运行时,运行一段时间,就会出现error happened,输出错误是PlayM4_InputData failed.您知道这是因为什么吗?请您有时间回复一下,或者qq1498177249,谢谢了
23楼 fangice66 2015-10-22 17:19发表 [回复]-
-
楼主,想问下一直提示playM4_InputData failed怎么解决呀
Re: invadertroy 2015-11-27 10:19发表 [回复]-
-
回复fangice66:之前这个问题你解决了吗?想请教你一下
22楼 dimaliu 2015-09-15 11:25发表 [回复]-
-
把上面的代码贴上去之后,回调函数进去了,但是播放器回调进不去。控件不显示视频,opencv也不显示。不知道为什么,哪位能帮我解决下该问题
Re: invadertroy 2015-11-26 16:46发表 [回复]-
-
回复dimaliu:你好,回调函数进不去的问题你解决了吗?我最近用这个也是碰到这个问题!
21楼 止的不是战 2015-09-10 21:11发表 [回复]-
-
博主,为什么在运行了这个程序后,出现了一个窗口,不显示视频,然后很快就自动退出了?
Re: a496817765 2015-09-11 09:22发表 [回复]-
-
回复止的不是战:有可能你摄像头IP设置错误了,我也有遇到这个情况
Re: 止的不是战 2015-09-12 12:34发表 [回复]-
-
回复a496817765:IP地址已经改了,还是这样。496817765是你扣扣吗?能交流一下吗?
20楼 a496817765 2015-09-10 16:37发表 [回复]-
-
博主,你的程序我调试通过可以运行起来,但是运行一段时间后直接会在console中提示error happened.
然后在输出调试中提示PlayM4_InputData failed
这个是什么问题导致的?内存溢出吗?
Re: a496817765 2015-09-17 14:27发表 [回复]-
-
回复a496817765:询问了海康的技术人员,还有查看了相关的SDK文档,在实时解码回调方法中进行长时间操作会导致解码回调方法阻塞,这里是将获取的数据取到回调方法外部进行处理。
Re: qq_33021543 2015-12-22 14:41发表 [回复]-
-
回复a496817765:请问针对这个问题您是怎么解决的,真的很需要您的帮助,谢谢了,请您有空回复我一下,或者我的qq1498177249,谢谢了
19楼 li367383592 2015-08-18 17:22发表 [回复]-
-
您好,我用您的程序运行后,能注册,但运行后显示NET_DVR_RealPlay_V30 failed! Error number:107,是什么原因呢?
Re: a496817765 2015-09-10 15:58发表 [回复]-
-
回复li367383592:询问过海康那边,错误代码107是因为SDK库文件导入不全。
18楼 不要做程序员的小松鼠 2015-08-13 09:18发表 [回复]-
-
不知道楼主还记得不,海康给的例子是不是有内存泄漏?
Re: 雪水 2015-08-15 13:20发表 [回复]-
-
回复不要做程序员的小松鼠:当时我也没有仔细研究他们给的例程,只是根据他们的例程将整个流程打通了。
17楼 shhdgl 2015-04-18 15:33发表 [回复]-
-
很不错,学习了,但是用主码流我的延时很大,差不多有40~50s的样子,这个跟电脑的配置很有关系的吧?
Re: hnu2016 2016-05-26 07:14发表 [回复]-
-
回复shhdgl:这个主要是上面的yv12toYUV函数与cvtColor这两个函数造成的,所以延时很大,特别是在用主流时,传回来的图像特别的大,处理起来很麻烦
16楼 zhaozhaoni 2015-03-24 10:11发表 [回复]-
-
楼主你好!感谢分享!!
我用这段程序运行看不到视频,只卡在黑色DOS界面上,感觉在不停取帧,但是没有显示,是怎么回事?
PS:我用的是openCV 1.0 ,跟这个有关吗?
15楼 kwanqueen 2015-02-02 17:22发表 [回复]-
-
感谢博主分享,但是我的有个问题,视频很卡,什么原因?
14楼 leifeng_soul 2015-01-30 13:52发表 [回复]-
-
正好在用海康像机进行二次开发,需要用到这个,收藏之,多谢楼主分享,有问题再咨询
13楼 kwanqueen 2015-01-29 16:58发表 [回复]-
-
无法打开包括文件:“PlayM4.h”,我也是下载的这个版本的SDK,求解决
Re: shhdgl 2015-04-18 15:14发表 [回复]-
-
回复kwanqueen:这个应该是海康的库更新了,现在变成了plaympeg4.h
12楼 hxx_Helen 2015-01-22 10:32发表 [回复]-
-
博主你好,我用了你的程序得到的lRealPlayHandle是小于0的,控制台上输出的是“NET_DVR_RealPlay_V30 failed! Error number:84”,请问是什么原因呢?
Re: 雪水 2015-01-24 16:04发表 [回复]-
-
回复hxx_Helen:84号错误对应的错误解释:加载标准协议通讯库StreamTransClient失败。我感觉是你IP没配好吧。你用海康威视自带的软件能否看到摄像头视频,如果可以看到再用这段代码。
11楼 sufangqi123 2014-12-30 19:22发表 [回复]-
-
我现在是想实时处理视频并显示人脸检测结果,但是加上人脸检测结果后根本无法实时显示,请问楼主做过实时处理实时显示的程序没?
Re: 雪水 2014-12-30 19:56发表 [回复]-
-
回复sufangqi123:我做的就是实时处理实时显示。显示的时候有几秒钟的绝对延时,但是确实是实时显示的。
你的实时处理速度是否能跟得上采集速度,如果处理速度很慢,那么处理后在显示出来,那当然显示的不是实时的。
10楼 plhrbust 2014-12-29 15:45发表 [回复]-
-
非常感谢 很实用 谢谢啦大牛 32个赞
9楼 lonerzf 2014-12-07 15:41发表 [回复]-
-
楼主,我弄出来以后发现图像大约会延时10S的样子,请问您有出现这个问题吗?
Re: 雪水 2014-12-12 20:12发表 [回复]-
-
回复lonerzf:会有一定延时,但我的延时在5S以内的样子。
8楼 河海壹粟 2014-11-25 21:59发表 [回复]-
-
大神,我想请教你一个问题,我现在又两个海康威视的网络摄像机,请问怎么同时获取两路视频流呢?
弄两个回调函数?分别处理视频流? 博主能给个交流qq吗?谢谢了
Re: 雪水 2014-12-07 00:26发表 [回复]-
-
回复河海壹粟:我觉得开两个线程就可以了。输入不同的配置参数。
7楼 lvl000 2014-09-29 09:42发表 [回复]-
-
楼主转换格式后,出现卡顿现象了吗?如何解决的?
Re: qq_22338395 2015-11-17 23:12发表 [回复]-
-
回复lvl000:请问您卡顿问题有没有解决
Re: 雪水 2014-09-29 19:51发表 [回复]-
-
回复lvl000:卡顿是不是因为计算机CPU处理能力不够,导致卡顿的?
用这种方法没有出现卡顿现象的。
6楼 此生-未名 2014-09-23 12:51发表 [回复]-
-
楼主好,请问您说的“是有例程的,有分功能示例” ,分功能示例是在哪
Re: 雪水 2014-09-29 19:52发表 [回复]-
-
回复此生-未名:看橘黄色字体,这些都是超链接的。里面有。
5楼 ProMonkeySun 2014-09-16 20:31发表 [回复]-
-
楼主的代码很好的实现了格式的转换,我现在又遇到一个问题,我在使用两个摄像机读入两路视频,将两个摄像机读入的视频图像都实现上面的格式转换,转成opencv能处理的图像,此时在使用回调函数时,无法区分两个摄像机各自的图像,也就是无法将两路视频分别显示在两个cvNamedWindow中,这个问题有什么解决方法吗,感谢楼主!!
Re: 雪水 2014-10-03 21:20发表 [回复]-
-
回复ProMonkeySun:建议你用两个线程去处理。或者在回调函数的参数里加上一个标志位,显示的时候判断一下标志位。
4楼 lvl000 2014-09-15 17:47发表 [回复]-
-
博主如何确定已经捕获到视频流的?
Re: 雪水 2014-09-15 22:53发表 [回复]-
-
回复lvl000:imshow可以看得到视频的
Re: hnu2016 2016-05-26 07:17发表 [回复]-
-
回复雪水:请问楼主,取流回来后进行播放,不存在很大的延迟吗,就是视频变得一卡一卡的
Re: lvl000 2014-09-16 10:22发表 [回复]-
-
回复雪水:或者博主能告诉海康demo中那个“实时流回调解码获取YUV”仅仅是获取视频流数据什么都不作为还是说捕获后,存放于某个文件中
Re: 雪水 2014-09-16 22:07发表 [回复]-
-
回复lvl000:获取到YUV后暂时是存在内存里面的,没有做任何用途。要做什么事情,你得自己去定义
Re: lvl000 2014-09-16 09:56发表 [回复]-
-
回复雪水:我的看不到视频是怎么回事?我先是改海康给的demo里的分功能显示,没出现视频,然后又copy你这个程序也没显示
3楼 whj919 2014-08-20 11:13发表 [回复]-
-
谢谢楼主的分享,我这里也是实时性满足不了,节省了我不少时间。
2楼 peterpan_cafuc 2014-06-23 11:09发表 [回复]-
-
我目前要做的一个程序,需求正好和楼主一样。
楼主这篇博文很有用,感谢分享!
1楼 titer1 2014-06-18 14:55发表 [回复]-
很不错,关于raw图像的处理