基于海康SDK实现Python调用海康威视网络摄像头

基于海康SDK实现Python调用海康威视网络摄像头

  • 1. 原料准备
  • 2. 环境配置
    • 2.1. opencv环境配置
    • 2.2. Swig环境变量配置
  • 3. 编译和运行
    • 3.1. Step1
    • 3.2. Step2
    • 3.3. Step3
    • 3.4. Step4
    • 3.5. Step5

本文参考博客,写得很好:

  • Python调用海康威视网络相机之——python调用海康威视C++的SDK
  • Python调用海康威视网络相机C++的SDK

写本文的目的,也是快速复盘,所以没有很详细

保存视频流到本地可参考下一篇:基于海康SDK实现Python保存海康威视网络摄像头拍摄的视频

1. 原料准备

  • Windows11
  • Visual Studio 2015 或 Visual Studio 2013
  • Anaconda3 或 Miniconda3(配置基于conda的Python 3.7.xx 的虚拟环境)
    • Miniconda3下载链接:https://docs.conda.io/projects/miniconda/en/latest/
  • opencv-3.4.16-vc14_vc15_for_Windows
    • opencv下载链接:https://opencv.org/releases/
  • swigwin-3.0.12
    • Swig_Windows版本下载地址:https://sourceforge.net/projects/swig/files/swigwin/
  • OpenCV-swig接口文件
    • 下载地址:https://github.com/renatoGarcia/opencv-swig
  • boost_1_70_0
    • Boost下载地址:https://www.boost.org/users/history/
  • 海康威视网络摄像头
  • 海康SDK版本:CH-HCNetSDKV6.1.9.48_build20230410_win64
    • 海康SDK下载地址:https://open.hikvision.com/download/5cda567cf47ae80dd41a54b3?type=10

2. 环境配置

  • Visual Studio 2015 或 Visual Studio 2013 安装:略
  • Anaconda3 或 Miniconda3配置Python虚拟环境:略

2.1. opencv环境配置

  • opencv安装配置:可参考:Windows下 OpenCV 的下载安装教程(详细)
  • 可能需要注意的,关于visual studio和vc版本之间的对应关系:关于visual studio和vc版本之间的对应关系(更新至2020.07)

    vc14 对应 VS2015

    vc15 对应 VS2017

    但实际上用VS2013好像也可以

  • 我这里安装的是opencv-3.4.16-vc14_vc15_for_Windows,参考上面的文章,我的用户变量和系统变量的路径配置为:D:\DeveloperTools\OpenCV\opencv\build\x64\vc14\bin

2.2. Swig环境变量配置

  • 可参考:SWIG:SWIG的简介、安装、使用方法之详细攻略
  • 我这里安装的是swigwin-3.0.12,我的系统变量的路径配置为:D:\DeveloperTools\SWIG\swigwin-3.0.12

3. 编译和运行

  • 为方便,不用安装和配置环境变量的文件全都放到了D:\CYT\Desktop\HKSDK\文件夹下

3.1. Step1

  1. 在D:\CYT\Desktop\HKSDK\文件夹下创建HicVision_python_SDK文件夹
  2. 创建3个文本文件,并修改名称和文件后缀为HKIPcamera.h、HKIPcamera.cpp、HKIPcamera.i
  3. 上面3个文件的内容如下:
    • HKIPcamera.h
    #include using namespace cv;void init(char* ip, char* usr, char* password);Mat getframe();void release();
    • HKIPcamera.cpp
    #include #include #include #include #include #include #include #include #include #include "HCNetSDK.h"#include "plaympeg4.h"#define USECOLOR 1using namespace cv;using namespace std;//--------------------------------------------int iPicNum = 0;//Set channel NO.LONG nPort = -1;HWND hWnd = NULL;CRITICAL_SECTION g_cs_frameList;list g_frameList;LONG lUserID;NET_DVR_DEVICEINFO_V30 struDeviceInfo;HANDLE hThread;LONG lRealPlayHandle = -1;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];	 			outYuv[idx + col * 3] = Y;			outYuv[idx + col * 3 + 1] = U;			outYuv[idx + col * 3 + 2] = V;		}	}}//解码回调 视频为YUV数据(YV12),音频为PCM数据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		//int start = clock();		static IplImage* pImgYCrCb = cvCreateImage(cvSize(pFrameInfo->nWidth, pFrameInfo->nHeight), 8, 3);//得到图像的Y分量  		yv12toYUV(pImgYCrCb->imageData, pBuf, pFrameInfo->nWidth, pFrameInfo->nHeight, pImgYCrCb->widthStep);//得到全部RGB图像		static IplImage* pImg = cvCreateImage(cvSize(pFrameInfo->nWidth, pFrameInfo->nHeight), 8, 3);		cvCvtColor(pImgYCrCb, pImg, CV_YCrCb2RGB);		//int end = clock();#else		static IplImage* pImg = cvCreateImage(cvSize(pFrameInfo->nWidth, pFrameInfo->nHeight), 8, 1);		memcpy(pImg->imageData, pBuf, pFrameInfo->nWidth*pFrameInfo->nHeight);#endif		EnterCriticalSection(&g_cs_frameList);		//g_frameList.push_back(pImg);		g_frameList.push_back(cv::cvarrToMat(pImg));		LeaveCriticalSection(&g_cs_frameList);    } }///实时流回调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;			}		}		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;	}}bool OpenCamera(char* ip, char* usr, char* password){	lUserID = NET_DVR_Login_V30(ip, 8000, usr, password, &struDeviceInfo);	if (lUserID == 0)	{		cout << "Log in success!" << endl;		return TRUE;	}	else	{		printf("Login error, %d\n", NET_DVR_GetLastError());		NET_DVR_Cleanup();		return FALSE;	}}DWORD WINAPI ReadCamera(LPVOID IpParameter){	//---------------------------------------	//设置异常消息回调函数	NET_DVR_SetExceptionCallBack_V30(0, NULL, g_ExceptionCallBack, NULL);	//cvNamedWindow("Mywindow", 0);	//cvNamedWindow("IPCamera", 0);	 	//HWND  h = (HWND)cvGetWindowHandle("Mywindow");	//h = cvNamedWindow("IPCamera");	//---------------------------------------	//启动预览并设置回调数据流 	NET_DVR_CLIENTINFO ClientInfo;	ClientInfo.lChannel = 1;        //Channel number 设备通道号	ClientInfo.hPlayWnd = NULL;     //窗口为空,设备SDK不解码只取流	ClientInfo.lLinkMode = 1;       //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 -1;	}	else		cout << "码流回调成功!" << endl;	Sleep(-1);	if (!NET_DVR_StopRealPlay(lRealPlayHandle))	{		printf("NET_DVR_StopRealPlay error! Error number: %d\n", NET_DVR_GetLastError());		return 0;	}	NET_DVR_Logout(lUserID);	NET_DVR_Cleanup();	return 0;}void init(char* ip, char* usr, char* password) {	//HANDLE hThread;	//LPDWORD threadID;	//---------------------------------------	// 初始化	NET_DVR_Init();	//设置连接时间与重连时间	NET_DVR_SetConnectTime(2000, 1);	NET_DVR_SetReconnect(10000, true);	OpenCamera(ip, usr, password);	InitializeCriticalSection(&g_cs_frameList);	hThread = ::CreateThread(NULL, 0, ReadCamera, NULL, 0, 0);}Mat getframe() {	Mat frame1;	EnterCriticalSection(&g_cs_frameList);	while (!g_frameList.size()) {		LeaveCriticalSection(&g_cs_frameList);		EnterCriticalSection(&g_cs_frameList);	}	list::iterator it;	it = g_frameList.end();	it--;	Mat dbgframe = (*(it));	(*g_frameList.begin()).copyTo(frame1);	frame1 = dbgframe;	g_frameList.pop_front();	//imshow("camera", frame1);	//waitKey(1);	g_frameList.clear();   // 丢掉旧的帧	LeaveCriticalSection(&g_cs_frameList);	return(frame1);}void release() {	::CloseHandle(hThread);	NET_DVR_StopRealPlay(lRealPlayHandle);	//关闭预览	NET_DVR_Logout(lUserID);	//注销用户	NET_DVR_Cleanup();}
    • HKIPcamera.i
    /*  Example of wrapping a C function that takes a C double array as input using *  numpy typemaps for SWIG. */%module HKIPcamera%include %cv_mat__instantiate_defaults%header %{    /*  Includes the header in the wrapper code */    #include "HKIPcamera.h"%} %include "HKIPcamera.h"

3.2. Step2

  1. 将之前下载的opencv-swig-master中的lib\目录下的opencv\文件夹和opencv.i 复制到自己创建的HicVision_python_SDK\文件夹下。
  2. 将解压的boost_1_70_0文件夹也一并复制到HicVision_python_SDK\文件夹下。
  3. 将安装后的Opencv路径下的.\opencv\build\include\opencv2\文件夹也复制到HicVision_python_SDK\文件夹下。
  4. 打开CMD终端,移动到HicVision_python_SDK\文件夹,执行如下命令:
    swig -IE:你的opencv安装路径 -python -c++ HKIPcamera.i# 根据自己opencv安装路径来写,例如我的命令如下:swig -IE:D:/DeveloperTools/OpenCV/opencv/build/include -python -c++ HKIPcamera.i
  5. 执行完命令后,会生成HKIPcamera_wrap.cxx 和 HKIPcamera.py 两个文件。
  6. 这里使用的海康SDK版本为:CH-HCNetSDKV6.1.9.48_build20230410_win64,如果是此本版以前的版本,可能会需要修改SDK中的plaympeg4.h文件,可参考文章最开头给出的参考文章。

3.3. Step3

  • 由于对VisualStudio这个软件用的少,所以下面步骤详细点,这里用的是VisualStudio2015
  1. 创建项目

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

  2. 添加头文件和源文件,添加的文件就在之前创建的HicVision_python_SDK\文件夹下

    在这里插入图片描述

在这里插入图片描述

  • 源文件同样这样添加,添加后的样子

    在这里插入图片描述

  1. 参数设置

    在这里插入图片描述

    在这里插入图片描述

  • 在VC++目录->包含目录中添加如下头文件路径:(请根据自己的实际安装位置填写)
    # 我的路径如下:D:\DeveloperTools\Miniconda3\envs\HKSDK\includeD:\DeveloperTools\Miniconda3\envs\HKSDK\Lib\site-packages\numpy\core\includeD:\CYT\Desktop\HKSDK\HicVision_python_SDK\boost_1_70_0D:\CYT\Desktop\HKSDK\CH-HCNetSDKV6.1.9.48_build20230410_win64\includeD:\DeveloperTools\OpenCV\opencv\build\include\opencv2D:\DeveloperTools\OpenCV\opencv\build\include\opencvD:\DeveloperTools\OpenCV\opencv\build\include
  • 在VC++目录->库目录中添加如下头文件路径:(请根据自己的实际安装位置填写)
    # 我的路径如下:D:\DeveloperTools\Miniconda3\envs\HKSDK\libsD:\CYT\Desktop\HKSDK\HicVision_python_SDK\boost_1_70_0\libsD:\CYT\Desktop\HKSDK\CH-HCNetSDKV6.1.9.48_build20230410_win64\libD:\CYT\Desktop\HKSDK\CH-HCNetSDKV6.1.9.48_build20230410_win64\lib\HCNetSDKComD:\DeveloperTools\OpenCV\opencv\build\x64\vc14\lib
  • 在C/C++->预处理器->预处理器定义中添加如下内容:
    WIN32NDEBUG_CONSULE_CRT_SECURE_NO_WARNINGS
  • 在链接器->输入->附加依赖项添加如下内容:
    opencv_world3416.lib   # 这里一定要根据自己的opencv版本来写HCNetSDK.libGdiPlus.libHCAlarm.libHCCore.libHCGeneralCfgMgr.libHCPreview.libPlayCtrl.lib

在这里插入图片描述

  • 在常规->字符集中选择使用多字节字符集
  • 在C/C++->代码生成中选择多线程DLL(/MD)
  1. 在自己的python3.7中的 include\文件夹下
    • 我这里的python3.7虚拟环境路径为:D:\DeveloperTools\Miniconda3\envs\HKSDK\include\
    • 将object.h 中的第56行注释掉(以自己实际的行数为准)

      在这里插入图片描述

  • 将pyconfig.h中的第317~319行注释掉(以自己实际的行数为准)

    在这里插入图片描述

3.4. Step4

  1. 完成以上步骤后,右键工程项目名选择生成

    在这里插入图片描述

    在这里插入图片描述

    • 之后会在工程的x64\Release\文件夹下生成.dll和.lib文件

      在这里插入图片描述

  2. 现在,可以将之前python3.7中的 include\文件夹下的object.h 和pyconfig.h中注释掉的行数恢复原样(不恢复貌似也没问题)

  3. 将.\HKIPcamera\x64\Release\下生成的HKIPcamera.dll文件复制一份,并将文件名称和后缀名修改为_HKIPcamera.pyd

  4. 将海康SDK中的 .\CH-HCNetSDKV6.1.9.48_build20230410_win64\lib\ 文件夹下的所有文件和文件夹拷贝到.\HKIPcamera\x64\Release\文件夹下

  5. 将之前在.\HicVision_python_SDK下生成的HKIPcamera.py文件也拷贝到.\HKIPcamera\x64\Release\文件夹下

    • 最终文件组成如下(未显示完):

      在这里插入图片描述

  6. 将_HKIPcamera.pyd文件,包含目录路径,添加到系统环境变量Path中,并将_HKIPcamera.pyd所在文件夹目录,也添加到系统环境变量目录中

    在这里插入图片描述

3.5. Step5

  1. 测试,导包测试,主要是看是否能够导入HKIPcamera包,没有报错,就是成功了
    import HKIPcamera
    import time
    import numpy as np
    import matplotlib.pyplot as plt
    import cv2
    
  2. 将上面.\HKIPcamera\x64\Release\中的文件和文件夹全部复制一份到.\CH-HCNetSDKV6.1.9.48_build20230410_win64\Demo\5_Python_Demo\1-预览取流解码Demo\lib\win\目录下
  3. 运行海康SDK中的CH-HCNetSDKV6.1.9.48_build20230410_win64_20230905143859.zip\CH-HCNetSDKV6.1.9.48_build20230410_win64\Demo示例\5- Python开发示例\1-预览取流解码Demo\test_main.py,测试可行

    在这里插入图片描述

到底了🤪

本文来自网络,不代表协通编程立场,如若转载,请注明出处:https://net2asp.com/8b300d8cd2.html