海康相机-SDK二次开发(NVR)-多相机IPCamera连接采集-opencv图像格式转换

主要功能:

海康SDK开发,通过连接NVR,实现连接NVR的2个相机同时采集(多线程),并进行opencv图像格式转换。

关键技术点:

1、回调函数

2、YV12->oepncv图像格式转换

3、多线程连接多IPcamera,同时采集

---------------------------分割线-------------------------------------------------------

1、回调函数

定义:回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

回调函数是继承自C语言的。

在C++中,应只在与C代码建立接口或与已有的回调接口打交道时,才使用回调函数。除了上述情况,在C++中应使用虚拟方法或仿函数(functor),而不是回调函数。

理解:即回调函数的目的是解耦,

 

Callback
下面以一段不完整的C语言代码来呈现上图的意思:
#include<stdio.h>
#include<softwareLib.h> // 包含Library Function所在读得Software library库的头文件
int Callback() // Callback Function
{
// TODO
return 0;
}
int main() // Main program
{
// TODO
Library(Callback);
// TODO
return 0;
}

      乍一看,回调似乎只是函数间的调用,和普通函数调用没啥区别,但仔细一看,可以发现两者之间的一个关键的不同:在回调中,主程序把回调函数像参数一样传入库函数。这样一来,只要我们改变传进库函数的参数,就可以实现不同的功能,这样有没有觉得很灵活?并且丝毫不需要修改库函数的实现,这就是解耦。

      再仔细看看,主函数和回调函数是在同一层的,而库函数在另外一层,想一想,如果库函数对我们不可见,我们修改不了库函数的实现,也就是说不能通过修改库函数让库函数调用普通函数那样实现,那我们就只能通过传入不同的回调函数了,这也就是在日常工作中常见的情况。

更详细的讲解请参考:

 https://www.cnblogs.com/jiangzhaowei/p/9129105.html

https://baike.baidu.com/item/%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0/7545973?fr=aladdin

实例:

//回调函数实例
void __stdcall show(void(*CallLBackFun)(const string&, InputArray), const string& winname, InputArray m)
{
	namedWindow(winname,0);
	CallLBackFun(winname, m);
	waitKey(1);
}

void  CALLBACK DecCBFun(long nPort,char *pBuf,long nSize,FRAME_INFO *pFrameInfo,void *nUser,void *nReserved2)
{
	char buff[10];
	sprintf_s(buff, "%d", nPort+11);
	if (pFrameInfo->nType == T_YV12)
	{
		//  YUV--> Mat格式转换
		Mat g_BGRImage;
		g_BGRImage.create(pFrameInfo->nHeight, pFrameInfo->nWidth, CV_8UC3);
		Mat YUVImage(pFrameInfo->nHeight + pFrameInfo->nHeight / 2, pFrameInfo->nWidth, CV_8UC1, (unsigned char*)pBuf);
		cvtColor(YUVImage, g_BGRImage, COLOR_YUV2BGR_YV12);
		//把opencv的imshow作为回调函数使用
           //imshow("dst", g_BGRImage);
		show(imshow,buff, g_BGRImage);	
	}
}

2、YV12->oepncv图像格式转换

void  CALLBACK DecCBFun(long nPort,char *pBuf,long nSize,FRAME_INFO *pFrameInfo,void *nUser,void *nReserved2)
{
	if (pFrameInfo->nType == T_YV12)
	{
		//  YUV--> Mat格式转换
		Mat g_BGRImage;
		g_BGRImage.create(pFrameInfo->nHeight, pFrameInfo->nWidth, CV_8UC3);
		Mat YUVImage(pFrameInfo->nHeight + pFrameInfo->nHeight / 2, pFrameInfo->nWidth, CV_8UC1, (unsigned char*)pBuf);
		cvtColor(YUVImage, g_BGRImage, COLOR_YUV2BGR_YV12);
           imshow("dst", g_BGRImage);
           cvWaitKey(1);	
	}
}

3、多线程连接多IPcamera,同时采集

C语言多线程介绍:

c语言库 process.h 中的函数, 用来创建一个线程 :_beginthreadex

unsigned long _beginthreadex(
    void *security,    // 安全属性, 为NULL时表示默认安全性
    unsigned stack_size,    // 线程的堆栈大小, 一般默认为0
    unsigned(_stdcall *start_address)(void *),    // 所要启动的线程函数
    void *argilist, // 线程函数的参数, 是一个void*类型, 传递多个参数时用结构体
    unsigned initflag, //新线程的初始状态,0表示立即执行,CREATE_SUSPENDED
表示创建之后挂起
    unsigned *threaddr    // 用来接收线程ID
);
返回值 : // 成功返回新线程句柄, 失败返回0
-------------分割线----------------------
#include <stdio.h>
#include <windows.h>
#include <process.h>
unsigned int __stdcall threadDemo(LPVOID) // void *
{
    printf("我被执行啦!\n");
    return 0;
}
int main()
{
    HANDLE handle;    
    handle = (HANDLE)_beginthreadex(NULL, 0, ThreadDemo, NULL, 0, NULL);   
    return 0;
}

参考:https://blog.csdn.net/p312011150/article/details/81538247

实例:

#include <process.h>
typedef struct MyStruct
{
	LONG lUserId;
	LONG channel;
}MyStruct, *LPMyStruct;
----------------------------
unsigned int __stdcall play(void* user)
{
	LPMyStruct stru = (LPMyStruct)user;
	//启动预览并设置回调数据流
	LONG lRealPlayHandle;
	//HWND hWnd = GetConsoleWindowAPI();     //获取窗口句柄
	NET_DVR_PREVIEWINFO struPlayInfo = { 0 };
	struPlayInfo.hPlayWnd = NULL;         //需要SDK解码时句柄设为有效值,仅取流不解码时可设为空
	struPlayInfo.lChannel = stru->channel + 32;       //预览通道号
	struPlayInfo.dwStreamType = 0;       //0-主码流,1-子码流,2-码流3,3-码流4,以此类推
	struPlayInfo.dwLinkMode = 0;       //0- TCP方式,1- UDP方式,2- 多播方式,3- RTP方式,4-RTP/RTSP,5-RSTP/HTTP
	struPlayInfo.bBlocked = 1;       //0- 非阻塞取流,1- 阻塞取流
	lRealPlayHandle = NET_DVR_RealPlay_V40(stru->lUserId, &struPlayInfo, fRealDataCallBack, NULL);
	if (lRealPlayHandle < 0)
	{
		printf("NET_DVR_RealPlay_V40 error\n");
		printf("error :%d", NET_DVR_GetLastError());
		NET_DVR_Logout(stru->lUserId);
		NET_DVR_Cleanup();
		return 0;
	}
	Sleep(10000);
	//关闭预览
	NET_DVR_StopRealPlay(lRealPlayHandle);
	return 0;
}
-------------------------
//多线程
	MyStruct structdata, structdata2;
	structdata.lUserId = lUserID;
	structdata.channel = 7;
	HANDLE handle, handle2;
	handle = (HANDLE)_beginthreadex(NULL, 0, play, (void*)(&structdata), 0, NULL);
	structdata2.lUserId = lUserID;
	structdata2.channel = 3;
	handle2 = (HANDLE)_beginthreadex(NULL, 0, play, (void*)(&structdata2), 0, NULL);

	Sleep(20000);

-----------------------分割线----------------------------------------

源程序:

不能添加附件,大家去下载链接下载吧,资源分1分,没有积分的留言联系我吧

 

 

发布了8 篇原创文章 · 获赞 4 · 访问量 9353
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章