windows下python调用海康威视网络摄像头sdk

本文参考以下博文加自己的实践,发现有些步骤是不必要的,例如不需要为opencv等第三方库指定路径
运行环境:
准备工作
1、海康SDK下载
2、下载安装vcpkg
3、安装Swig
4、下载OpenCV-swig接口文件
实现方案
1. 使用swig编译生成python和c++数据交换需要的.py和.cxx文件
HKIPcamera.i
HKIPcamera.h
HKIPcamera.cpp
2. 修改海康SDK下的plaympeg4.h文件
3、用VS2019编译生成动态链接库文件
将该库给别人使用
本文参考以下博文加自己的实践,发现有些步骤是不必要的,例如不需要为opencv等第三方库指定路径
https://blog.csdn.net/c20081052/article/details/95082377
https://www.ryannn.com/archives/hikvision/comment-page-2#comments
https://blog.csdn.net/GottaYiWanLiu/article/details/106187962

运行环境:
Win10系统,64位,Anaconda3

python 3.7.9(基于anaconda环境)

vcpkg(boost,opencv3)

Visual Studio 2019

硬件:DS-2CD3T56DWD-I5

相机SDK: 设备网络SDK_V6.1.4.42(for Windows x64)

准备工作
1、海康SDK下载
下载地址:https://www.hikvision.com/cn/download_61.html

选择自己对应的系统平台版本,我这边选的是设备网络SDK_Win64 :CH-HCNetSDKV6.1.4.42_build20200527_win64

该文件夹下主要是头文件和库文件。

2、下载安装vcpkg
vcpkg如何安装请参考别的博客。安装完以后,命令行cd至vcpkg根目录,然后命令行输入

./vcpkg install boost:x64-windows
./vcpkg install opencv3:x64-windows
1
2
即可安装boost和opencv3。

3、安装Swig
Swig是用来封装库的,下载链接:http://www.swig.org/download.html

我安装的版本是swigwin-4.0.2:http://prdownloads.sourceforge.net/swig/swigwin-4.0.2.zip

然后将安装目录添加至环境变量path

4、下载OpenCV-swig接口文件
下载地址:https://github.com/renatoGarcia/opencv-swig

我们主要会用到其目录下lib文件夹中的文件opencv文件夹和opencv.i接口文件


实现方案
1. 使用swig编译生成python和c++数据交换需要的.py和.cxx文件
新建一个文件夹,例如HicVision_python_SDK文件夹。将下载的opencv-swig\lib下的opencv.i和opencv文件夹放入新建的HicVision_python_SDK文件夹中。

复制以下三个文件,到新建的HicVision_python_SDK文件夹中。注意代码中的字符串不要出现中文即可避免编码问题。

HKIPcamera.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"
1
2
3
4
5
6
7
8
9
10
11
HKIPcamera.h
#include <opencv2/opencv.hpp>
using namespace cv;
 
void init(char* ip, char* usr, char* password);
Mat getframe();
void release();
1
2
3
4
5
6
HKIPcamera.cpp
#include <opencv\cv.h>
#include <opencv\highgui.h>
#include <opencv2\opencv.hpp>
#include <iostream>
#include <time.h>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <windows.h>
#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 << "Call NET_DVR_RealPlay_V30 successful!" << 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();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240


这样HicVision_python_SDK文件夹下就拥有上图红框的所有文件了。然后使用cmd或者powershell,cd到这个路径,执行

swig -ID:\vcpkg\installed\x64-windows\include -python -c++ HKIPcamera.i
1
注意将其中的D:\vcpkg修改为自己的vcpkg安装目录。

执行之后将在该目录生成HKIPcamera.py和HKIPcamera_wrap.cxx。


2. 修改海康SDK下的plaympeg4.h文件
这里直接参考https://blog.csdn.net/c20081052/article/details/95082377所描述即可:


3、用VS2019编译生成动态链接库文件
首先创建空C++项目,并且项目命名为HKIPcamera


然后将之前文件夹下的三个文件放入项目中:

修改上面的编译选项为Release和x64

右键项目属性,切换选项卡为Release和x64,修改配置类型为动态库(.dll)

项目下添加3rdparty文件夹,在里面添加海康威视sdk的头文件和库文件:


取消安全周期检查:


VC++目录->包含目录中添加如下头文件路径(修改python目录到你自己的):
注意使用了vcpkg之后,就不需要添加使用vcpkg安装的opencv等库的头文件和.lib了。

3rdparty\include
D:\ProgramData\Anaconda3\envs\dust37\Lib\site-packages\numpy\core\include
D:\ProgramData\Anaconda3\envs\dust37\include
1
2
3


VC++目录->库目录中添加如下库的路径:(修改python目录到你自己的)

D:\ProgramData\Anaconda3\envs\dust37\libs
3rdparty\lib
3rdparty\lib\HCNetSDKCom
1
2
3


预处理器->预处理器定义中内容如下:

WIN32
NDEBUG
_CONSULE
_CRT_SECURE_NO_WARNINGS
1
2
3
4


链接器->输入->附加依赖项中添加:
HCNetSDK.lib
GdiPlus.lib
HCAlarm.lib
HCCore.lib
HCGeneralCfgMgr.lib
HCPreview.lib
PlayCtrl.lib

注意使用了vcpkg之后,就不需要添加使用vcpkg安装的opencv等库的头文件和.lib了。
完成以上步骤后,右键工程项目名选择生成,之后会在工程x64文件夹下的Release文件夹下生成.dll和.lib文件如下(红色)


复制一份 HKIPcamera.dll 文件并重命名为 _HKIPcamera.pyd到该目录下,并将海康SDK中的3rdparty\lib下的库文件都复制到该目录),以及将上文中用swig生成的HKIPcamera.py 也复制过来(如上图蓝色)
最后编写了个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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
在anaconda的prompt控制台下运行该test.py,会看到python调用SDK的实时画面,其延迟性同网页预览版差不多。但比rtsp流读取的效果好很多~

至此成功!

将该库给别人使用
经过测试,该库给别人使用的唯一条件是目标计算机使用的python版本需要与编译时的python版本完全一致,而不需要在指定目录下安装opencv等库。

因此放上我个人编译的版本。注意需要使用Python 3.7.9运行。运行时修改test.py中的8-10行为你自己的ip,name和pd

ip = str('10.167.93.111')  # 摄像头IP地址,要和本机IP在同一局域网
name = str('admin')       # 管理员用户名
pw = str('abcd1234')        # 管理员密码
1
2
3
然后使用

python test.py
1
即可运行。
————————————————
版权声明:本文为CSDN博主「张小小恩」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ylzf2008/article/details/109247587

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值