本文参考:https://blog.csdn.net/c20081052/article/details/95082377 笔者将此文章中遗漏或未遇见的问题归纳总结,并分享自己在运行过程中遇到的问题,与君共勉。
Win10系统 (64位)
Python3.7 (若是有用Python2.x版本的童鞋,尽量升级Python版本。在实验过程中,有其他童鞋由于Python版本问题,无法读取Python库)
Opencv3_4_2 、Visual Studio 2015(尽量使用同一版本)
海康硬件IDS-2DC7S420MW-A
海康SDK:CH-HCNetSDKV6.1.6.45_build20210302_win64
建议在D盘或者E盘新建文件夹 ,名字为:App_install 。
下载地址:https://open.hikvision.com/download/5cda567cf47ae80dd41a54b3?type=10
选择自己对应的系统版本,笔者选的是设备网络SDK_Win64。
将其解压,主要会用到里面的头文件与库文件。将其汉语名称头文件改为include、库文件改为lib。
笔者安装的是Opencv3_4_2。
在官网上下载3.4.2版本,双击即可解压。建议放到App_install文件夹,解压后将其bin路径添加到系统环境变量path下。
Swigwin是用来封装库的。
下载链接:http://www.swig.org/index.php
笔者选择的是3.0.12这个版本(本人之前选择的是最新版本,但是由于不明确的错误问题,还是按引用文章的版本安装),将其安装并解压到App_install目录下。
将此文件名路径添加到系统环境变量path中。
下载地址:https://www.boost.org/users/history/
笔者选择的是 boost_1_70_0.zip (因为本文主要是将win10环境下的), 将其解压到待会工程需要用的路径下即可;此处还是先解压到App_install文件夹下,待会会将解压后的文件夹拷贝到后面要用的路径下。
下载地址:https://github.com/renatoGarcia/opencv-swig 将其下载并解压到App_install文件夹下。
需要用到其目录下lib文件夹中的文件opencv和opencv.i接口文件。
至此,前期准备工作搞定。App_install文件夹下的文件如下图:
复制以下三个文件(注意不要更改文件名),保存到同一文件夹下。笔者均将文件都放在新建文件夹 HicVision_python_SDK (建议名字一样)
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 1
using namespace cv;
using namespace std;
//--------------------------------------------
int iPicNum = 0;//Set channel NO.
LONG nPort = -1;
HWND hWnd = NULL;
CRITICAL_SECTION g_cs_frameList;
list<Mat> 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<Mat>::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(若此文件不明白如何写的,可以多复制一份下文的opencv.i文件,将下面代码内容与文件名替换,点击保存即可)
/* Example of wrapping a C function that takes a C double array as input using
* numpy typemaps for SWIG. */
%module HKIPcamera
%include <opencv/mat.i>
%cv_mat__instantiate_defaults
%header %{
/* Includes the header in the wrapper code */
#include "HKIPcamera.h"
%}
%include "HKIPcamera.h"
将第二步相关下载中的opencv-swig-master\lib下的opencv文件夹和opencv.i 这两个文件复制到 HicVision_python_SDK文件夹下。
将解压的boost_1_70_0文件夹也一并拷贝到这个目录下。
将App_install\opencv3_4_2\build\include中opencv2文件夹复制到HicVision_python_SDK文件夹下。(注:此处与之前博主不同,是因为笔者在生成.py与.cxx文件时报错,将此文件复制后,运行成功)
然后打开cmd,切到HicVision_python_SDK 这个文件夹下。
举例:本人HicVision_python_SDK 文件夹在D盘下。win+r,输入cmd,回车;输入d:,转到D盘,输入cd+空格+文件名 转到文件夹下。
然后输入指令
E:\Win32-MFC-Projects\HicVision_python_SDK>swig -IE:/App_install/opencv3_4_2/opencv/build/include -python -c++ HKIPcamera.i
指定你opencv安装的头文件路径,会生成上图所示的HKIPcamera_wrap.cxx 和 HKIPcamera.py 两个文件(蓝色方框文件)。
该文件在App_install \ CH-HCNetSDKV6.0.2.35_build20190411_Win64 \ include 目录下:
第五行,extern “C” __declspec(dllexport)的"C"和____之间需要增加空格,否则会导致编译报错。如下:
新建win32控制台应用 工程,选择"DLL",“空项目”;取消选择"安全开发生命周期(SDL)检测"。若为Visual Studio2019版,请自行在属性页中更改。
应用程序设置页参考如下:
在资源方案管理器页将如下图所示的文件导入,即将上文提到的生成的文件拷贝到项目中(笔者起名为HKIPcamera项目名,建议一致)
编译平台是release x64下的,因此将配置该平台环境的属性页,点击 视图->属性页
其中 VC++目录->包含目录中添加如下头文件路径:(请根据实际安装位置补全其全路径名称,笔者省去了有些安装路径名)
C:\Python3.7\include
C:\Python3.7\Lib\site-packages\numpy\core\include(以下类似)
HicVision_python_SDK\boost_1_70_0
CH-HCNetSDKV6.0.2.35_build20190411_Win64\include
opencv3_4_2\opencv\build\include\opencv2
opencv3_4_2\opencv\build\include\opencv
opencv3_4_2\opencv\build\include
VC++目录->库目录中添加如下库的路径:(自行补全实际安装路径名)
C:\Python3.7\libs
HicVision_python_SDK\boost_1_70_0\libs
CH-HCNetSDKV6.0.2.35_build20190411_Win64\lib
CH-HCNetSDKV6.0.2.35_build20190411_Win64\lib\HCNetSDKCom
opencv3_4_2\opencv\build\x64\vc14\lib
预处理器->预处理器定义中内容如下:
WIN32
NDEBUG
_CONSULE
_CRT_SECURE_NO_WARNINGS
链接器->输入->附加依赖项中添加:
opencv_world342.lib (release下是这个,debug下需要改为opencv_world342d.lib)
HCNetSDK.lib
GdiPlus.lib
HCAlarm.lib
HCCore.lib
HCGeneralCfgMgr.lib
HCPreview.lib
PlayCtrl.lib
在通用属性->常规->字符集中选择使用多字节字符集
在C/C+±>代码生成->运行库选的是多线程DLL(/MD)
Python3.7中 include文件夹下:object.h 注释掉第56行
完成以上步骤后,右键工程项目名选择生成,之后会在工程x64文件夹下的Release文件夹下生成.dll和.lib文件如下(红色框):
若生成成功 将注释掉的行数 恢复原样(不恢复貌似也没问题)。
在生成 HKIPcamera.dll文件与HKIPcamera.lib文件之后,复制两份 HKIPcamera.dll 文件,
其中一份重命名为 _HKIPcamera.pyd (注意文件名前面 _ ) 到 HicVision_python_SDK目录下,并将海康SDK中的 HCNetSDKCom 文件夹拷贝过来
以及将上文中用swig生成的HKIPcamera.py 也复制到HicVision_python_SDK文件夹下。
将 _HKIPcamera.pyd文件,包含目录路径,添加到系统环境变量Path中,并将 _HKIPcamera.pyd所在文件夹目录,也添加到系统环境变量目录中。如下:
生成时遇到未定义问题,可以先查看本文引用文章,后面关于此问题解法。若仍无法解决,可能是C++版本问题,下载DirectX修复工具,修复Visual Studio后,再进行生成操作。
DirectX下载地址:https://blog.csdn.net/vbcom/article/details/6962388
下载后解压,点击
允许其更改电脑;出来界面后,点击工具-> 选项->扩展->开始扩展
扩展完成后,进入首页,点击检测并修复,若无问题,退出。
若有其他问题,请查看DirectX官网解决方法。
最后编写了个test.py也放在上图目录下,主要用来检测是否编译成功:
import HKIPcamera
import time
import numpy as np
import matplotlib.pyplot as plt
import cv2
ip = str('10.167.93.111') # 摄像头IP地址,要和本机IP在同一局域网
name = str('admin') # 管理员用户名
pw = str('abcd1234') # 管理员密码
HKIPcamera.init(ip, name, pw)
HKIPcamera.getfram()
#for i in range(100):
while(True):
t = time.time()
fram = HKIPcamera.getframe()
t2 = time.time()
cv2.imshow('123', np.array(fram))
cv2.waitKey(1)
print(t2-t)
time.sleep(0.1)
HKIPcamera.release()
time.sleep(5)
HKIPcamera.init(ip, name, pw)
究其原因,是找不到.dll文件,故将所有链接的.dll文件移到.pyd同文件夹下。
首先,将此文件夹下文件全部复制到.pyd文件夹下,其中.dll文件会重复,跳过或者覆盖均可。
其次,将海康威视文件夹中lib文件夹下所有文件复制到.pyd文件夹下。
进行完上述操作后,多数人运行test均成功,但笔者依旧报错dll找不到指定模板。
不能放弃呀。
笔者又编写测试test1代码,目的是查看_HKIPcamera.pyd是否正常
import _HKIPcamera
print(dir(_HKIPcamera))
print(help(_HKIPcamera))
不失所望,它依旧运行不出来。
下载depends(后文有网盘链接可自行下载),运行其应用程序,将_HKIPcamera.pyd拖到其界面,系统自动分析,分析过后出现找不到文件的情况。
寻找其主要原因。笔者这边主要是找不到三个.dll文件:分别是python37.dll,opencv_WORLD342.dll,VCRUNTIME140_1.dll。在我的电脑中,搜索这三个文件,将其复制到.pyd同目录文件中。
若是你缺少与笔者不同的.dll文件,按照与笔者相同的方法即可。
然后重启电脑,打开test1。它就成功了~~
本文中用到的文件:
Swigwin-3.0.12:链接:https://pan.baidu.com/s/1VK_Pb7VcbwVxwwJzKDWuhA 提取码:g3mo
Opencv-swig-master:链接:https://pan.baidu.com/s/1qAa2P4040AROx_a16XZ63Q 提取码:vnw0
boost_1_70_0:链接:https://pan.baidu.com/s/17i4cutVICiiFRy-UEqiCyw 提取码:jgb2
海康威视SDK软件包:链接:https://pan.baidu.com/s/1vMV1bk4EfDrEzJLTweCRzg 提取码:xhwc
Visual Studio2015(64):链接:https://pan.baidu.com/s/1FvxGZWW19I7rIgBuo1itSQ 提取码:noby
DirectX_Repair:链接:https://pan.baidu.com/s/1iNnb6YzJGqCUKxOTCJP_-g 提取码:qruk
depends(汉化版):链接:https://pan.baidu.com/s/1xOAfAQIj-QrR5bYD9bYGhw 提取码:s0r0
Python-3.7.0:链接:https://pan.baidu.com/s/13QdAw4zeV4D4WJfKAOJFUQ 提取码:iyfl
再次声明:本文参考此文https://blog.csdn.net/c20081052/article/details/95082377,并在此基础上查漏补缺。