python实现海康sdk二次开发,移动侦测事件(一)

------------------------------------------------------------------------------------------------------------------------------------------------------------

こうしん 2020-12.7

一般来说,发现移动侦测后,都需要进行抓图,

请参见

python 海康威视ipc抓图

-------------------------------------------------------------------------------------------------------------------------------------------------------------

------------------------------------------------------------------------------------------------------------------------------------------------------------

こうしん 2021/3/15

之前一直使用的是单独的摄像机,没有发现移动侦测的回调bug,在此更正,

@CFUNCTYPE(c_int, c_long, MSesGCallback.NET_DVR_ALARMER, c_char_p, c_ulong, c_void_p)

中,第四个参数需要使用

POINTER(c_char)

python 海康威视ipc抓图

-------------------------------------------------------------------------------------------------------------------------------------------------------------

在上篇博文里,我们完成了海康摄像头的配置、sdk的下载,在本篇文章,我们开始着手开发海康sdk

对于实现海康摄像头自带的移动侦测事件,大概的流程为

  1. 引入海康sdk
  2. 初始化海康sdk和设置连接时间
  3. 登录
  4. 设置报警回调函数
  5. 部防
  6. 撤防
  7. 退去

该流程,也是符合海康的官方sdk流程的

1 sdk引入

我们为了开发python版本的海康摄像头的相关功能,需要使用C++版本提供的sdk,假设在上篇博客中,下载的sdk路径为:D:\Backup\solo\hkoython\dll

采用如下代码读入海康sdk

from ctypes import *class HkAdapter:dll_path = r"D:\Backup\solo\hkoython\dll"def load_hkdll(self):# 载入HCCore.dllhccode = WinDLL(__class__.dll_path + "\\HCCore.dll")# 载入HCNetSDK.dllhcnetsdk = cdll.LoadLibrary(__class__.dll_path + "\\HCNetSDK.dll")return hcnetsdk

在代码段中,我们采用winDLL的形式,读入了两个dll文件,而目录下,有很多dll文件,我们是用不到的,我们只需要按照海康sdk读取我们需要的两个核心文件即可。

这里要注意,dll_path文件夹里的子文件夹  文件的名称都是不可以更改的,因为我们没有显式引入,但是hknetsdk.dll是会去调用其他dll的,因此我们保持原样放好即可。

我们这里将hcnetsdk变量返回,以后调用c++函数,采用hknetsdk.functionname()的形式即可

2.初始化

我们采用hknetsdk.functionname()的方式,调用初始化函数即可

def init(hksdk):if not hksdk.NET_DVR_Init():print("初始失败")return Falseif not hksdk.NET_DVR_SetConnectTime():print("设置连接时间失败")return Falseprint("初始化成功")return True

在该init方法中,我们调用了海康dll提供的两个函数。都使用缺省参数。

NET_DVR_Init(): 初始化
NET_DVR_SetConnectTime():设置连接时间,缺省为DWORD dwWaitTime = 3000, DWORD dwTryTimes = 3

可以发现,采用ctypes调用这种没有参数函数相当简单

3.登录

3.1 ctypes结构体与数据类型对应

C++版的登录函数为

        NET_DVR_USER_LOGIN_INFO loginInfo = { 0 };NET_DVR_DEVICEINFO_V40 deviceInfo = { 0 };//登录方式设置为同步loginInfo.bUseAsynLogin = 0;const char *deviceAddress, *userName, *passWord;WORD wPort = 8000;LONG userID;deviceAddress = "192.168.8.112";userName = "admin";passWord = "hk123456";strcpy_s(loginInfo.sDeviceAddress, deviceAddress);strcpy_s(loginInfo.sUserName, userName);strcpy_s(loginInfo.sPassword, passWord);loginInfo.wPort = wPort;userID = NET_DVR_Login_V40(&loginInfo, &deviceInfo);

可以看到,需要为登录函数NET_DVR_Login_V40传递两个参数,参数类型为两个结构体类型的地址,在ctypes中,使用Structure的子类,来定义结构体,固定写法为

class ClassName(Structure):_fields_ = [# 该标量的名称,形式都是固定的# 每个元素为("结构体属性名",数据类型)的元组形式#,结构体属性名字段必须与c++的必须要完全一致("结构体属性1", 数据类型), ("结构体属性2", 数据类型),...]

结构体属性直接复制C++的即可,而数据类型需要对应到Ctype数据类型。如下图所示。

2.2 数据准备

我们分别按照C++的结构体说明,在一个文件里,定义两个类,分别表示登录所需要的结构体

from ctypes import *class NET_DVR_DEVICEINFO_V30(Structure):_fields_ = [("sSerialNumber", c_byte * 48),  # 序列号("byAlarmInPortNum", c_byte),  # 模拟报警输入个数("byAlarmOutPortNum", c_byte),  # 模拟报警输出个数("byDiskNum", c_byte),  # 硬盘个数("byDVRType", c_byte),  # 设备类型,详见下文列表("byChanNum", c_byte),  ("byStartChan", c_byte),  ("byAudioChanNum", c_byte),  # 设备语音对讲通道数("byIPChanNum", c_byte),        ("byZeroChanNum", c_byte),  # 零通道编码个数("byMainProto", c_byte),  # 主码流传输协议类型:("bySubProto", c_byte),  # 字码流传输协议类型:("bySupport", c_byte),       ("bySupport1", c_byte),("bySupport2", c_byte),("wDevType", c_uint16),  # 设备型号,详见下文列表("bySupport3", c_byte),       ("byMultiStreamProto", c_byte),("byStartDChan", c_byte),  # 起始数字通道号,0表示无数字通道,比如DVR或IPC("byStartDTalkChan", c_byte),  ("byHighDChanNum", c_byte),  # 数字通道个数,高8位        ("bySupport4", c_byte),       ("byLanguageType", c_byte),("byVoiceInChanNum", c_byte),  # 音频输入通道数("byStartVoiceInChanNo", c_byte),  # 音频输入起始通道号,0表示无效("bySupport5", c_byte),("bySupport6", c_byte),("byMirrorChanNum", c_byte),  # 镜像通道个数,录播主机中用于表示导播通道("wStartMirrorChanNo", c_uint16),("bySupport7", c_byte),("byRes2", c_byte )]  # 保留,置为0class NET_DVR_DEVICEINFO_V40(Structure):_fields_ = [# struDeviceV30结构体中包括接口体,我们只需要额外定义一下该子结构体即可("struDeviceV30", NET_DVR_DEVICEINFO_V30),("bySupportLock", c_byte),#设备是否支持锁定功能,bySupportLock为1时,dwSurplusLockTime和byRetryLoginTime有效("byRetryLoginTime", c_byte),("byPasswordLevel", c_byte),("byProxyType", c_byte),("dwSurplusLockTime", c_ulong),("byCharEncodeType", c_byte),("bySupportDev5", c_byte),("bySupport", c_byte),("byLoginMode", c_byte),("dwOEMCode", c_ulong),("iResidualValidity", c_int),("byResidualValidity", c_byte),("bySingleStartDTalkChan", c_byte),("bySingleDTalkChanNums", c_byte),("byPassWordResetLevel", c_byte),("bySupportStreamEncrypt", c_byte),("byMarketType", c_byte),("byRes2", c_byte*253),]class NET_DVR_USER_LOGIN_INFO(Structure):_fields_ = [("sDeviceAddress", c_char * 129),("byUseTransport", c_byte),("wPort", c_uint16),("sUserName", c_char * 64),("sPassword", c_char * 64),("bUseAsynLogin", c_int),("byProxyType", c_byte),("byUseUTCTime", c_byte),("byLoginMode", c_byte),("byHttps", c_byte),("iProxyID", c_long),("byVerifyMode", c_byte),("byRes3", c_byte * 120)]

3.3 login

我们获得了两个结构体,直接对其初始化,复制,调用登录即可。

def login(hksdk, url, usename, password, port=8000):# python的String向ctype里的c_char传递的数据需要进行bytes编码burl = bytes(url, "ascii")busename = bytes(usename, "ascii")bpassword = bytes(password, "ascii")# 初始化两个结构体login_info = NET_DVR_Login_V40.NET_DVR_USER_LOGIN_INFO()device_info = NET_DVR_Login_V40.NET_DVR_DEVICEINFO_V40()# 设置登录信息login_info.wPort = portlogin_info.bUseAsynLogin = 0login_info.sUserName = busenamelogin_info.sPassword = bpasswordlogin_info.sDeviceAddress = burl# 获得引用,byref基本等于c++的&符号param_login = byref(login_info)  # 传递的为指针则使用该种方式param_device = byref(device_info)# 执行NET_DVR_Login_V40函数,获取useriduseid = hksdk.NET_DVR_Login_V40(param_login, param_device)# 登录成功时,useid的值为0、1.....,失败时为-1# 可以调用NET_DVR_GetLastError查看错误码if useid == -1: print("登录失败,错误码为{}".format(hksdk.NET_DVR_GetLastError()))else:print("登录成功,用户id为{}".format(useid))return useid

4 布防
4.1 设置报警回调函数

在海康sdk中,当触发了报警时间后,会自动调用用户设置的回调函数,该函数原型为

BOOL CALLBACK MSesGCallback(LONG lCommand, NET_DVR_ALARMER *pAlarmer, char *pAlarmInfo, DWORD dwBufLen, void* pUser) ;

该回调函数需要的形参除了基本数据类型外,还需要一个结构体,因此我们先定义该结构体

from ctypes import *class NET_DVR_ALARMER(Structure):_fields_ = [("byUserIDValid",c_byte),("bySerialValid", c_byte),("byVersionValid", c_byte),("byDeviceNameValid", c_byte),("byMacAddrValid",c_byte),("byLinkPortValid", c_byte),("byDeviceIPValid", c_byte),("bySocketIPValid", c_byte),("lUserID", c_long),("sSerialNumber", c_byte*48),("sDeviceName", c_char*32),("byMacAddr", c_byte*6),("wLinkPort", c_uint16),("sDeviceIP", c_char*128),("sSocketIP", c_char*128),("byIpProtocol", c_byte),("byRes1", c_byte*2),("bJSONBroken", c_byte),("wSocketPort", c_uint16),("byRes2", c_byte*6)]

我们写一个python方法作为回调函数

# 更正,此处第四个参数应该换成POINTER(c_char)
@CFUNCTYPE(c_int, c_long, MSesGCallback.NET_DVR_ALARMER, POINTER(c_char), c_ulong, c_void_p)
def alarm_callback(lCommand: c_long, pAlarmer: MSesGCallback.NET_DVR_ALARMER,pAlarmInfo: POINTER(c_char), dwBufLen: c_ulong, pUser: c_void_p):print("收到警报信息,类型为 {} \t发送者为 {}".format(lCommand, pAlarmer.lUserID))if lCommand == 0x4000:print("消息类型为 COMM_ALARM_V30", end=" --> ")alarm_info = ALARM.NET_DVR_ALARMINFO_V30()# 更正,换成POINTER(c_char)后,不需要调用decode方法memmove(addressof(alarm_info), pAlarmInfo, sizeof(alarm_info))if alarm_info.dwAlarmType == 3:print("子事件为移动侦测")else:print("子事件 None")else:print("消息类型为None")return 1

ctype可以用装饰器的形式来定义回调函数,明确返回值类型和输入值类型,在上述代码中为

@CFUNCTYPE(返回类型,参数类型1,参数类型2...)

该回调函数首先会判断是不是通用警报信息,如果是,在判断是不是为移动侦测。

在判断移动侦测时,我们使用了一个新的结构体NET_DVR_ALARMINFO_V30,我们将在4.2中,定义该结构体

4.2 启用回调函数,布防

布防函数为

 NET_DVR_SETUPALARM_PARAM setupParam = { 0 };setupParam.dwSize = sizeof(NET_DVR_SETUPALARM_PARAM);setupParam.byLevel = 0; //优先级 0 高 1低LONG handle = NET_DVR_SetupAlarmChan_V41(userID, &setupParam);

可见我们需要定义一个新的结构体NET_DVR_SETUPALARM_PARAM

class NET_DVR_SETUPALARM_PARAM(Structure):_fields_ = [("dwSize", c_ulong),("byLevel", c_byte),  # 布防优先级("byAlarmInfoType", c_byte),("byRetAlarmTypeV40", c_byte),("byRetDevInfoVersion", c_byte),("byRetVQDAlarmType", c_byte),("byFaceAlarmDetection", c_byte),("bySupport", c_byte),("byBrokenNetHttp", c_byte),("wTaskNo", c_uint16),("byDeployType", c_byte),("byRes1", c_byte*2),("byAlarmTypeURL", c_byte),("byCustomCtrl", c_byte),]class NET_DVR_ALARMINFO_V30(Structure):_fields_ =[("dwAlarmType",c_ulong),("dwAlarmInputNumber",c_ulong),("byAlarmOutputNumber",c_byte*96),("byAlarmRelateChannel",c_byte*64),("byChannel",c_byte*64),("byChannel",c_byte*33)]

据此,我们可以完成设置回调函数,启用布防

def deploy(hksdk, userid):  # 布防# 设置回调函数callback_status = hksdk.NET_DVR_SetDVRMessageCallBack_V31(alarm_callback, None)if callback_status == -1:print("设置回调函数失败,错误码为".format(hksdk.NET_DVR_GetLastError()))return -1else:print("设置回调函数成功")# 启用布防setup_alarm = ALARM.NET_DVR_SETUPALARM_PARAM()setup_alarm.dwSize = sizeof(ALARM.NET_DVR_SETUPALARM_PARAM)setup_alarm.byLevel = 0setup_alarm.byAlarmInfoType = 1handle = hksdk.NET_DVR_SetupAlarmChan_V41(userid, setup_alarm)if handle < 0:print("布防失败,错误码为{}".format(hksdk.NET_DVR_GetLastError()))else:print("布防成功")return handle

5 撤防

撤防较为简单,只需要一个由布防得到的handle参数即可

def disdeploy(hksdk, handle):  # 布防disdeploy_result = hksdk.NET_DVR_CloseAlarmChan_V30(handle)if disdeploy_result == -1:print("撤防失败,错误码为{}".format(hksdk.NET_DVR_GetLastError()))else:print("撤防成功")

6 反初始化

将推出登录和反初始化做到一起,也较为简单,一个需要一个int类型参数useid,一个不需要参数

def uinit(hksdk, useid):isOK = hksdk.NET_DVR_Logout(useid)if isOK == -1:print("登出失败错误码为{}".format(hksdk.NET_DVR_GetLastError()))else:print("登出成功")hksdk.NET_DVR_Cleanup()

至此,我们所有的功能函数都写完了

7 run it

写一个main函数,执行上述过程

if __name__ == "__main__":print("-----------初始化与登录---------")hkadapter = HkAdapter()hksdk = hkadapter.load_hkdll()init(hksdk)userid = login(hksdk, "xxx.xxx.xxx.xxx", "xxxxxx", "xxxxxxx")print("----------初始化与登录完成---------")print("-----------布防与撤防---------")print("开始部防。。。")handle = deploy(hksdk, userid)if handle >= 0:print("***************警告信息输出begin******************")# 主线程sleep的时间就是程序布防的时间time.sleep(100)print("****************警告信息输出end*******************")print("开始撤防。。。")disdeploy(hksdk, handle)print("-----------布防与撤防结束---------")uinit(hksdk, userid)

8 After

很粗糙的写了一个小程序,还需要全方位的细致优化,大家有什么好的意见和建议可以留言

参考

Python实现海康威视SDK二次开发(开源库)

ctypes --- Python 的外部函数库

python实现海康sdk二次开发,移动侦测事件(二)相关推荐

  1. Python调用海康SDK进行车牌识别(动态链接库的方法—不通过swig)

    由于公司项目需要,要通过Python取得海康相机识别到的车牌号,由于目前在办公室,无法进行实际测试,所以通过网络触发抓拍的方式来进行. 首先要下载海康官网的SDK示例,最开始从网上查找资料是通过swi ...

  2. python调用海康sdk 数据类型

    c++的 unsigned char指针,python格式为:POINTER(c_char) ok的项目:百度网盘里,HikSDKyv12View fRealDataCallBack_V30 = RE ...

  3. 海康摄像头二次开发python_python实现海康sdk二次开发,移动侦测事件(一)

    1.概述 最近一段时间要从海康摄像头读取数据,作为程序的输入源,c++版本有海康有自己的demo,较为简单,很容易就实现了,但是为我们其他的程序都是基于python的,因此,需要使用Python调用海 ...

  4. java 调用dll_Python调用海康SDK抓取红外图像

    海康SDK提供了C++.C#.Java等示例代码,可以使用这些语言进行二次开发.对于做算法开发的人来说,就想快速采集到图像,然后在Matlab或Python里对图像进行分析,使用C++.C#.Java ...

  5. 海康 sdk 视频截取 demo

    说下这个demo 的背景 .....   好了 说完了 直接上重点 .... 这是在网上看到一个 jijl 的朋友的 demo 基础上面开发的,用到了里面的一些东西 .示例 demo 以及  web ...

  6. Linux环境中对海康威视工业相机SDK进行二次开发(QT+CMake+Opencv+海康SDK)

    关于在Windows环境中对海康威视工业相机SDK进行二次开发的话,可以参考这两篇博客. 海康威视工业相机SDK二次开发(VS+Opencv+QT+海康SDK+C++)(一) 海康威视工业相机SDK二 ...

  7. 海康威视摄像机的实时读取篇二(海康SDK开发环境配置)

    利用海康SDK+OpenCV,实现海康摄像机图像实时读取.篇二介绍海康SDK开发环境配置及相关注意事项. 海康SDK开发环境配置 海康SDK开发环境配置具体步骤类似篇一(http://blog.csd ...

  8. Android平台上集成海康SDK(二)

    Android平台上集成海康SDK 以上是我之前写的一篇Android平台上集成海康SDK的文章,其中对于Android平台上集成海康SDK.基于海康SDK进行二次开发基本上进行了详细地介绍. 这篇文 ...

  9. 海康SDK开发实时读取摄像头图像

    1.概述 最近项目需要实时读取网络摄像头,并对图像做处理,参考网络资料和海康SDK开发文档,文档中给了两种方式(1)SDK直接解码显示(2)实时流数据回调,用户自行处理码流数据(开发文档上以软解显示为 ...

  10. Linux Python利用海康相机C++SDK(丝滑取流)

    众所周知,海康的相机SDK里面没有python模块,因此python不能调用,需要做转换,方法如下. 准备的包 OpenCV(用于源码编译,链接库的拷贝) 海康SDK Swig(桥梁,将C++SDk转 ...

最新文章

  1. 图解Java的substring()方法底层干了啥?
  2. 380v pcb 接线端子_连接器、接线端子、插针插孔三者究竟有什么区别?
  3. python 均值滤波_Python的一个骚操作
  4. python跟java-Java与Python两大幸存者谁更胜一筹呢
  5. oracle两列合并成一列_POWER QUERY--一个工作簿内的多张工作表合并汇总
  6. GPE监控多台MySQL_zabbix监控多个服务器
  7. bartender的安全策略不允许指定的用户执行此操作_Linux sudo 被曝提权漏洞,任意用户均能以 root 身份运行命令...
  8. php mysql pdo 多次_一次php脚本执行过程中多次实例化PDO的情景分析
  9. IDEA插件系列(46):PDF Viewer插件——PDF文档查看器
  10. C#/.Net 的托管堆和垃圾回收
  11. Pg Admin4 无法正常启动
  12. python的三种基本结构流程图_程序的三种基本结构是什么
  13. 3Dmax自动加载脚本错误,语法错误:位于bad,需要因子
  14. linux子系统下载错误,Win10系统开启linux子系统报错“0x80070057”怎么办?
  15. python 拼音搜索中文_汉语转拼音工具、新华字典API——两个支持Python的中文资源...
  16. 系统监控必备工具procmon
  17. 微信扫描登录(生成二维码)
  18. P1786 帮贡排序
  19. 解决360断网急诊强力修复后无法上网的问题
  20. phonegap 安装及环境配置(简介)

热门文章

  1. C语言:丹尼斯·里奇的不朽遗产
  2. 明日之后登不上去一直连接服务器,《明日之后》登不上去怎么办 明日之后进不去怎么回事...
  3. Linux核心进程管理命令
  4. 联想e550笔记本怎么样_摄像头是亮点 — Lenovo 联想 ThinkPad E550C 笔记本 简单评测...
  5. CodeSmith(1):使用和语法简介
  6. java 启动resin,Resin 启动时报错!解决方法
  7. HTC G14解锁S-OFF、刷机、获取ROOT权限
  8. Exposure X8 ps人像图片调色滤镜插件
  9. DES算法理解--附《密码编码学与网络安全(第七版)》课后练习题答案
  10. Windows 10 操作系统,更新之后无法打开Windows Mobile 设备中心,要么双击无反应。要么正在启动,过会就关闭了。