海康相機-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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章