python基于海康设备SDK的二次开发(三)

(最近重新修改了下SDK,因为在两个车间各安装了一台设备) 

再次使用下这张图

       今天是海康设备SDK二次开发的第三天,也是最后一次,因为这次将进入功能开发程序阶段,前面两次已经做好了全部的前期工作 。

首先从导入包开始

提供的demo里面是这样的:

# coding=utf-8
import os
import platform
import time
import tkinter
from tkinter import *
from HCNetSDK import *

       因为后期涉及到数据提取出来后要将数据进行清洗和修改,然后导入到sql中去,所以我进行了修改,添加了pandas和pymysql两个包,然后使用sqlalchemy进行数据库连接,修改如下:

# coding=utf-8
import os
import platform
import time
import tkinter
from tkinter import *
from HCNetSDK import *
import pandas
from pymysql import *
from sqlalchemy import create_engine

数据库连接设置一个全局连接:

engine = create_engine("mysql+pymysql://halo:root@localhost:3306/t_pcmespd?charset=utf8")  # 定义pd数据导入sql的方式,开启mysql数据库

前面的一些函数定义不需要改动,使用给出的demo就可以了

# 系统环境标识
WINDOWS_FLAG = True

# 报警信息列表,报一次在回调中加1次记录
alarm_info = []

# 获取当前系统环境
def GetPlatform():
    sysstr = platform.system()
    print('' + sysstr)
    if sysstr != "Windows":
        global WINDOWS_FLAG
        WINDOWS_FLAG = False

# 设置SDK初始化依赖库路径
def SetSDKInitCfg():
    # 设置HCNetSDKCom组件库和SSL库加载路径
    # print(os.getcwd())    
    if WINDOWS_FLAG:
        strPath = os.getcwd().encode('gbk')
        sdk_ComPath = NET_DVR_LOCAL_SDK_PATH()
        sdk_ComPath.sPath = strPath
        sdk.NET_DVR_SetSDKInitCfg(2, byref(sdk_ComPath))
        sdk.NET_DVR_SetSDKInitCfg(3, create_string_buffer(strPath + b'\libcrypto-1_1-x64.dll'))
        sdk.NET_DVR_SetSDKInitCfg(4, create_string_buffer(strPath + b'\libssl-1_1-x64.dll'))
    else:
        strPath = os.getcwd().encode('utf-8')
        sdk_ComPath = NET_DVR_LOCAL_SDK_PATH()
        sdk_ComPath.sPath = strPath
        sdk.NET_DVR_SetSDKInitCfg(2, byref(sdk_ComPath))
        sdk.NET_DVR_SetSDKInitCfg(3, create_string_buffer(strPath + b'/libcrypto.so.1.1'))
        sdk.NET_DVR_SetSDKInitCfg(4, create_string_buffer(strPath + b'/libssl.so.1.1'))

最重要的一点,也是本次功能开发的重点模块来了,给出的demo中有好几个:

    if lCommand == 0x4000:
        print('移动侦测')
        Alarm_struct = cast(pAlarmInfo,
                            LPNET_DVR_ALARMINFO_V30).contents  # 当lCommand是COMM_ALARM时将pAlarmInfo强制转换为NET_DVR_ALARMINFO类型的指针再取值
        single_alrm['dwAlarmType'] = hex(Alarm_struct.dwAlarmType)
        single_alrm['byAlarmOutputNumber'] = Alarm_struct.byAlarmOutputNumber[0]
        single_alrm['byChannel'] = Alarm_struct.byChannel[0]

    if lCommand == 0x5002:
        print('门禁触发报警')
        Alarm_struct = cast(pAlarmInfo,
                            LPNET_DVR_ACS_ALARM_INFO).contents  # 当lCommand是0x5002时将pAlarmInfo强制转换为NET_DVR_ACS_ALARM_INFO类型的指针再取值
        single_alrm['dwSize'] = Alarm_struct.dwSize
        single_alrm['dwMajor'] = hex(Alarm_struct.dwMajor)
        single_alrm['dwMinor'] = hex(Alarm_struct.dwMinor)
        single_alrm['dwPicDataLen'] = Alarm_struct.dwPicDataLen
        localtime = time.asctime(time.localtime(time.time()))
        single_alrm['localtime'] = localtime
        single_alrm['AcsEventInfo'] = Alarm_struct.byAcsEventInfoExtend
        # 抓拍图片
        PicDataLen = Alarm_struct.dwPicDataLen
        if PicDataLen != 0:
            buff1 = string_at(Alarm_struct.pPicData, PicDataLen)
            with open('../../pic/Acs_Capturetest.jpg', 'wb') as fp:
                fp.write(buff1)
    if lCommand == 0x5200:
        print('身份证刷卡事件上传')
        Alarm_struct = cast(pAlarmInfo,LPNET_DVR_ID_CARD_INFO_ALARM).contents
        single_alrm['dwSize'] = Alarm_struct.dwSize
        single_alrm['dwMajor'] = hex(Alarm_struct.dwMajor)
        single_alrm['dwMinor'] = hex(Alarm_struct.dwMinor)
        localtime = time.asctime(time.localtime(time.time()))
        single_alrm['localtime'] = localtime
        #抓拍图片
        DataLen = Alarm_struct.dwCapturePicDataLen
        if DataLen != 0:
            buff1 = string_at(Alarm_struct.pCapturePicData, DataLen)
            with open('../../pic/IDInfo_Capturetest.jpg', 'wb') as fp1:
                fp1.write(buff1)
        #身份证图片
        CardPicLen = Alarm_struct.dwPicDataLen
        if DataLen != 0:
            buff2 = string_at(Alarm_struct.pPicData, CardPicLen)
            with open('../../pic/IDInfo_IDPicTest.jpg', 'wb') as fp2:
                fp2.write(buff2)

    # ISAPI协议报警信息
    if lCommand == 0x6009:
        print('ISAPI协议报警信息上传')
        Alarm_struct = cast(pAlarmInfo, LPNET_DVR_ALARM_ISAPI_INFO).contents
        single_alrm['byDataType'] = Alarm_struct.byDataType
        single_alrm['byPicturesNumber'] = Alarm_struct.byPicturesNumber

        # 报警信息XML或者JSON数据
        DataLen = Alarm_struct.dwAlarmDataLen
        if DataLen != 0:
            buffInfo = string_at(Alarm_struct.pAlarmData, DataLen)
            with open('../../pic/IsapiInfo.txt', 'wb') as fpInfo:
                fpInfo.write(buffInfo)

        # 报警信息图片数据
        nSize = 0
        pNum = Alarm_struct.byPicturesNumber
        if pNum > 0:
            print(pNum)
            STRUCT = NET_DVR_ALARM_ISAPI_PICDATA * pNum
            PicStruct = cast(Alarm_struct.pPicPackData, POINTER(STRUCT)).contents
            for nPicIndex in range(pNum):
                nSize = PicStruct[nPicIndex].dwPicLen
                print(nSize)
                if nSize != 0:
                    buffInfo = string_at(PicStruct[nPicIndex].pPicData, nSize)
                    strName = str(PicStruct[nPicIndex].szFilename)
                    single_alrm['PicName'] = strName
                    sFileName = ('../../pic/ISAPI_Pic[%d].jpg' % nPicIndex)
                    with open(sFileName, 'wb') as fpPic:
                        fpPic.write(buffInfo)

    alarm_info.append(single_alrm)
    print(alarm_info[-1])

    tt.insert(tkinter.END, alarm_info[-1])
    tt.insert(tkinter.END, '\r\n---------------\r\n')
    return True

这次开发的功能只用到了其中的第二个

当lCommand == 0x5002这个判断信号触发数据传递。

所以在数据提取这部分要在demo的基础上添加这部分的程序

    if lCommand == 0x5002:
        print('门禁触发报警')
        Alarm_struct = cast(pAlarmInfo,
                            LPNET_DVR_ACS_ALARM_INFO).contents  # 当lCommand是0x5002时将pAlarmInfo强制转换为NET_DVR_ACS_ALARM_INFO类型的指针再取值
        single_alrm['dwSize'] = Alarm_struct.dwSize
        single_alrm['dwMajor'] = hex(Alarm_struct.dwMajor)
        single_alrm['dwMinor'] = hex(Alarm_struct.dwMinor)
        single_alrm['dwPicDataLen'] = Alarm_struct.dwPicDataLen
        localtime = time.asctime(time.localtime(time.time()))
        single_alrm['localtime'] = localtime
        single_alrm['AcsEventInfo'] = Alarm_struct.byAcsEventInfoExtend
        # 抓拍图片
        PicDataLen = Alarm_struct.dwPicDataLen
        if PicDataLen != 0:
            buff1 = string_at(Alarm_struct.pPicData, PicDataLen)
            with open('../../pic/Acs_Capturetest.jpg', 'wb') as fp:
                fp.write(buff1)

上面是demo中的内容,在localtime这里我做了修改,给出的格式是ISO格式,导入到sql时无法正确显示,所以直接更换传自带的时间格式,添加内容如下:

if Alarm_struct.byAcsEventInfoExtend == 1:

        这里要着重讲解下,因为该设备的数据均是直接传递到内存中,在提取数据的时候要通过指针的方式来读取,demo中给出了一种读取指针数据的方式

 但是,如果下面这一步效仿demo来,只返回一个内存地址,这个地方卡着痛苦了好几天,通过和海康的技术咨询,给出的是结构体错误,又反复的校验结构体,没发现什么问题,最后在海康开发手册里给出的C++demo种找到了灵感。

然后通过查找资料,将这部分改成python如下:

 Alarm_struct_ACS = NET_DVR_ACS_EVENT_INFO_EXTEND()                               #定义事件详情
            ctypes.memset(ctypes.byref(Alarm_struct_ACS),0,ctypes.sizeof(Alarm_struct_ACS))  #利用ctypes.memset方法设置Alarm_struct_ACS初始内存空间值为0
            ctypes.memmove(ctypes.byref(Alarm_struct_ACS),Alarm_struct.pAcsEventInfoExtend,ctypes.sizeof(Alarm_struct))#利用ctypes.memmove方法将Alarm_struct中内存地址为pAcsEventInfoExtend的值赋给Alarm_struct_ACS

       然后就成功获取到了所需要字段的值,至此本次项目最难的部分就给解决了,后面的就是按照需求一步一步的弄成自己想要的式样,整体写下来,海康给的SDK基本算是完整的,减少了大量的开发工作,只是其中也需要自己把开发手册和开发指南这两个资料看透看明白才能顺利的完成项目开发。

        后面还加了个小步骤,因为需要设备实时接收到信息,所以TK开发的界面需要最小化至右下角,所以后面TK那部分我做了下小修改,如下:

 menu = (MenuItem('显示', show_window, default=True), Menu.SEPARATOR, MenuItem('退出', quit_window))
    image = Image.open("XXX.jpg")
    icon = pystray.Icon("icon", image, "图标名称", menu)
    win = tkinter.Tk()
    # # 固定窗口大小
    # win.resizable(0, 0)
    # win.overrideredirect(True)

    sw = win.winfo_screenwidth()
    # 得到屏幕宽度
    sh = win.winfo_screenheight()
    # 得到屏幕高度

    # 窗口宽高
    ww = 512
    wh = 384
    x = (sw - ww) / 2
    y = (sh - wh) / 2
    win.geometry("%dx%d+%d+%d" % (ww, wh, x, y))
    win.protocol('WM_DELETE_WINDOW', on_exit)
    win.title('XXX')
    win.iconbitmap("kd.ico")
    threading.Thread(target=icon.run, daemon=True).start()
    # # 创建退出按键
    # b = Button(win, text='退出', command=win.quit)
    # b.pack()
    # 创建显示报警信息的文本框
    tt = tkinter.Text(win, width=ww, height=wh, bg='white')
    tt.pack()

这样实现了点击界面关闭按钮不会直接退出,而是退至后台托盘。

好了,看到这里给个关注,加个好友可以获得完整代码!

下个开发项目见。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
### 回答1: 海康相机SDK海康威视公司推出的一款相机软件开发工具包,它可以帮助开发者实现对海康相机的控制与数据处理。而使用Qt编写的二次开发程序可以在跨平台、界面友好、开发效率高等方面表现出色。因此,将海康相机SDK二次开发Qt的方法可以有效提高开发效率和使用体验。 在二次开发Qt程序之前,首先需要安装海康相机SDK和Qt开发环境。然后,通过SDK给出的样例程序,了解相机控制和数据处理的基本操作。接下来,结合Qt的开发框架,建立相应界面和事件响应,并利用海康相机SDK提供的函数,实现相机的开启、关闭、捕获图片等操作。同时,也要考虑到Qt与SDK之间的数据转换和参数传递的问题。 在开发过程中,需要注意一些细节问题,如相机连接状态的检测、相机参数的设置、图像处理算法的优化等。同时,也可以结合其他相关的开源库,如OpenCV等,进一步丰富程序的功能。 总之,海康相机SDK二次开发Qt是一个非常有前景和实际意义的开发方向。通过此类程序的开发,可以提高海康相机的应用范围和应用效果,满足不同用户的实际需求。 ### 回答2: 海康相机SDK是一款网络摄像机开发工具包,可以提供高质量的视频流和图像采集,集成该SDK到QT开发环境中可以实现基于网络摄像机的图像处理和视频监测应用的开发。 在使用海康相机SDK进行QT二次开发的过程中,需要首先了解SDK操作和QT编程的基本知识。在使用SDK时,需要通过SDK提供的API进行网络摄像机的控制、图像采集和视频流显示等操作。在此基础上,可以使用QT编程实现各种功能和应用,例如图像增强、文本识别、动态拍照和视频监测等。 在进行二次开发时,还需要注意SDK的版本选择和兼容性问题。另外,需要考虑软硬件平台的匹配问题,例如CPU架构、操作系统和网络接口等。在具体实现中,可以使用QT提供的多种工具和组件,例如QT designer、QT creator和QT widgets等,以提高开发效率和代码质量。 总之,通过海康相机SDK的二次开发和QT编程的结合,可以实现基于网络摄像机的各种应用和功能,为用户提供更加便捷、高效的视频监测和图像处理体验。 ### 回答3: 海康相机sdk是一个旨在为开发者提供海康威视相机设备的二次开发接口的软件开发工具包。对于开发者来说,使用海康相机sdk进行二次开发是非常重要的,这是因为该工具包提供了丰富的API,可以使开发者更加高效地定制相机设备的软件功能。 在海康相机sdk二次开发中,Qt是一种流行的跨平台开发框架,可以集成到C++中,使用Qt编写对于初学者来说也比较容易上手。我们可以使用Qt Creator IDE来编写程序,该IDE支持快速的窗口设计和多线程开发。同时,Qt还提供了很好的图形用户界面(GUI)支持,这对于开发相机设备用户友好的UI界面非常重要。 在使用海康相机sdk进行二次开发时,我们需要遵守相应的开发流程,首先需要进行硬件设备连接和查询,然后创建相应的海康相机对象,并且设置相机参数、注册回调函数等。之后,我们可以使用Qt编写界面并添加关于设备的一些功能,例如录像、拍照和保存数据等。 总之,使用海康相机sdk进行二次开发是一个涉及不同技术的综合性开发过程,例如设备硬件、图像处理、网络和GUI开发,同时也需要注意程序的健壮性和安全性等方面的考虑。虽然这个过程可能会面临一些挑战,但是在付出努力后,我们可以获得一个高效且功能强大的相机设备软件,满足我们的需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

oppo_123456

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值