通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别

前言

作为实习生接的第一个需求,虽然很简单,但是还是要记录一下在这个过程中遇到的问题和解决办法。

开发流程

  1. 打开海康威视官网找到开发文档,并下载对应的设备网络SDK ,在设备网络SDK的压缩包里面也有对应的开发文档的chm版,查看比较方便,同样在其中我们可以找到Java的demo,注意将dll支持库复制到demo的lib目录下之后就可以尝试运行了。
  2. 设备检测车辆时进行车牌识别、图片抓拍,并且上传识别抓拍结果。识别和抓拍是设备实现的,由设备主动上传,SDK被动接收。这也就是说,我们只需要在后端new一个SDK对象,与设备建立连接之后选择好布防方式,设备那一端就会把信息上传给SDK,由SDK来处理信息。布防通俗理解就是打开识别功能的意思,这里布防有两种方式,

    1)报警布防方式,是指SDK主动连接设备,建立报警上传通道,设备发生报警之后发送给SDK。需要先注册登录设备。
    2)报警监听方式,是指触发事件时设备主动连接SDK并且上传报警信息,SDK在设定的端口上监听和接收。需要先在设备端配置报警主机的IP和端口,和SDK监听的IP、端口需要一致。

  3. 我这里选择报警布防方式,由于海康威视的SDK是根据C++编写的,里面的JavaSDK也是根据C++翻译来的,所有比较反直觉,不过没事,我会讲清楚遇到的问题。demo的代码我就不贴出来了,文档都有,我重点讲一下遇到的问题。

问题和解决方案

dll库加载不到的问题

如果直接运行demo的话,不出意外应该没什么问题,除非你没用自己的设备和ip然后登录失败,并且库也是能加载到的。

但是我们做二次开发总会需要把这些东西整合到项目中,可能是单体项目,可能是微服务项目,大部分时候我们需要把lib放到项目一个固定的文件夹,比如WEB-INF下的lib目录,比如我的项目就是,这个目录下本来就放了很多依赖,已经add as library了。

private static boolean createSDKInstance() {
        if (hCNetSDK == null) {
            synchronized (HCNetSDK.class) {
                String strDllPath = "";
                try {
                    if (osSelect.isWindows())
                        //win系统加载库路径
                        strDllPath = System.getProperty("user.dir") + "\\lib\\HCNetSDK.dll";
                    else if (osSelect.isLinux())
                        //Linux系统加载库路径
                        strDllPath = System.getProperty("user.dir") + "/lib/libhcnetsdk.so";
                    hCNetSDK = (HCNetSDK) Native.loadLibrary(strDllPath, HCNetSDK.class);
                    System.out.println(strDllPath);
                } catch (Exception ex) {
                    System.out.println("loadLibrary: " + strDllPath + " Error: " + ex.getMessage());
                    return false;
                }
            }
        }
        return true;
    }

Native.loadLibrary()这个方法,前一个参数是要加载的dll的位置,后一个是要加载的类,在demo里面第一个参数填的是绝对路径,我在整合到项目里面的时候发现这里总是报错,后来调试发现获取到的路径是tomcat部署目录的路径,而在项目根目录新建lib文件夹他没有识别到。后来尝试写成绝对路径,写成绝对路径还是不行,报错变成了很奇怪的一条信息,显示找不到xxx(dll的绝对路径)在xxx(WEB-INF下的lib的目录),但是实际上我已经将dll放到了WEB-INF下的lib目录,为什么找不到呢?

后来搜索发现Native.loadLibrary()这个方法第一个参数只需要填dll支持的名称就可以了,于是改为

if (hcNetSDK == null) {
            synchronized (HCNetSDK.class) {
                String strDllPath = "";
                try {
                
                    // 加载库
                    hcNetSDK = (HCNetSDK) Native.loadLibrary("HCNetSDK", HCNetSDK.class);
                } catch (Exception ex) {
                    logger.info("loadLibrary: " + strDllPath + " Error: " + ex.getMessage());
                    return false;
                }


            }

现在就可以加载到了,分析原因可能是Native.loadLibrary()这个方法会到项目指定的lib目录下去找对应的dll,如果项目没有指定lib目录,那就需要指定绝对路径,如果指定了,那么就只需要名称就可以了。可能我的理解有问题,大家有更好的理解欢迎指出。

老旧版本sdk不兼容的问题

如果你使用的是新下载的sdk,那么下边这个问题应该不会遇到

在demo给出的HCNetSdk.java中,可以看到所有的类都继承了一个Structure,这是因为Java中没有结构体,而我们前面提到他这个sdk是由c++翻译来的,所以他自定义了一个结构体,但是有一个问题,老版本的sdk中,这个Structure里面有一个getFiledName()方法需要自己实现,我们得自定义一个BaseStructure,写好这个方法之后再把sdk中所有集成Structure的地方换成我们这个自定义的BaseStructure,代码如下

public class BaseStructure extends Structure
{
	@Override
	protected List<String> getFieldOrder()
	{
		return getFiledName(this);
	}

	public static List<String> getFiledName(Object o)
	{
		Field[] fields = o.getClass().getDeclaredFields();
		String[] fieldNames = new String[fields.length];
		for (int i = 0; i < fields.length; i++)
		{
			fieldNames[i] = fields[i].getName();
		}
		return Arrays.asList(fieldNames);
	}
}

但是在新版的sdk中,这个方法已经不需要我们重写了。

我的项目中之前使用过老版的sdk编写过一些老模块,所以我碰到了上边这个问题。另外就是我在更换老版sdk时发现,在老版sdk中很多方法使用了nativelong这个类型作为返回值或者变量类型,而在新版sdk中,这些都变成了int,所以如果你使用的sdk有新老版本冲突的问题,可以尝试把nativelong类型都换成int。

关键实现流程

创建sdk实例;

if (hCNetSDK == null) {
            if (!createSDKInstance()) {
                System.out.println("Load SDK fail");
                return;
            }
        }

初始化并加载日志

        /**初始化*/
        hCNetSDK.NET_DVR_Init();
        /**加载日志*/
        hCNetSDK.NET_DVR_SetLogToFile(3, "./sdklog1", false);
        

编写并设置回调函数(回调函数就是处理车牌信息的函数,COMM_ITS_PLATE_RESULT这个类型的lCommand就是我们需要的车牌信息的情况,可以在里面编写自己的逻辑),车牌照片有不同的类型,可以根据需要自己保存照片,文档里面有写不同编号对应不同场景图

public class FMSGCallBack implements HCNetSDK.FMSGCallBack_V31 {
    //报警信息回调函数
    public boolean invoke(int lCommand, HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen, Pointer pUser) {

        LOGGER.info("报警事件类型: lCommand:" + Integer.toHexString(lCommand));
        String MonitoringSiteID;
        switch (lCommand) {
            case 0x3058:
                LOGGER.info("报警事件类型: 0x3058 车辆黑白名单数据需要同步报警上传");
                break;

            case HCNetSDK.COMM_UPLOAD_PLATE_RESULT:
                LOGGER.info("报警事件类型: COMM_UPLOAD_PLATE_RESULT");
                break;

            case HCNetSDK.COMM_ITS_PLATE_RESULT:  // 交通抓拍结果(新报警信息)
                HCNetSDK.NET_ITS_PLATE_RESULT strItsPlateResult = new HCNetSDK.NET_ITS_PLATE_RESULT();
                //可以在这里处理自己的逻辑
                break;

            default:
                LOGGER.info("报警类型:" + Integer.toHexString(lCommand));
                break;
        }
        return true;
    }

}
if (fMSFCallBack_V31 == null) {
            fMSFCallBack_V31 = new FMSGCallBack_V31();
            Pointer pUser = null;
            if (!hCNetSDK.NET_DVR_SetDVRMessageCallBack_V31(fMSFCallBack_V31, pUser)) {
                System.out.println("设置回调函数失败!");
                return;
            } else {
                System.out.println("设置回调函数成功!");
            }
        }

设置结果分离参数

/** 设备上传的报警信息是COMM_VCA_ALARM(0x4993)类型,
         在SDK初始化之后增加调用NET_DVR_SetSDKLocalCfg(enumType为NET_DVR_LOCAL_CFG_TYPE_GENERAL)设置通用参数NET_DVR_LOCAL_GENERAL_CFG的byAlarmJsonPictureSeparate为1,
         将Json数据和图片数据分离上传,这样设置之后,报警布防回调函数里面接收到的报警信息类型为COMM_ISAPI_ALARM(0x6009),
         报警信息结构体为NET_DVR_ALARM_ISAPI_INFO(与设备无关,SDK封装的数据结构),更便于解析。*/

        HCNetSDK.NET_DVR_LOCAL_GENERAL_CFG struNET_DVR_LOCAL_GENERAL_CFG = new HCNetSDK.NET_DVR_LOCAL_GENERAL_CFG();
        struNET_DVR_LOCAL_GENERAL_CFG.byAlarmJsonPictureSeparate = 1;   //设置JSON透传报警数据和图片分离
        struNET_DVR_LOCAL_GENERAL_CFG.write();
        Pointer pStrNET_DVR_LOCAL_GENERAL_CFG = struNET_DVR_LOCAL_GENERAL_CFG.getPointer();
        hCNetSDK.NET_DVR_SetSDKLocalCfg(17, pStrNET_DVR_LOCAL_GENERAL_CFG);

接着登录设备并布防即可

lUserID=Alarm.loginDevice( "10.9.137.17", (short) 8000, "admin", "hik12345");  //登录设备

lAlarmHandle=Alarm.setAlarmChan(lUserID);//报警布防,和报警监听二选一即可

有一点需要注意,他这个车牌识别无法直接识别静止的图片,比如说我们当时采用放个平板(平板上放个车牌照片)的方式测试,摄像头就没有抓拍,移动了好几次才识别出来,大家测试的时候可以注意。虽然它此时没有抓拍车牌,但还是有一些报警信息,

报警事件类型: 0x3058 车辆黑白名单数据需要同步报警上传

这个信息隔一段时间就会出现,问了客服说这个信息不用解析,大家也可以将这个信息作为自己摄像头是否正常布防的调试信息,如果有这个类型的报警说明已经布防成功了。

内含SDK、开发文档 及Demo示例(C++、C#、Java设备网络SDK是基于设备私有网络通信协议开发的,为后端设备(嵌入式网络硬盘录像机、视频服务器)、前端设备网络摄像机、网络球机、IP模块)等产品服务的配套模块,用于远程访问和控制设备软件的二次开发。 适用于但不仅限于以下产品型号: 1.编解码设备 DVR:DS-9100、DS-8100、DS-8000-S、DS-8800、DS-7800、DS-7300、DS-7200、DS-7100、DS-7000等系列,包括-ST、-SH、-SE、-SN、-RT、-RH、-XT等; NVR:DS-96000、DS-9600、DS-9500、DS-8600、DS-7900、DS-7800、DS-7700、DS-7600、DS-7100等系列,包括-I、-F、-K、-E、-H、-ST、-XT、-SN、-SE、-SNH、-SHT、-S、-SH、-RT等; XVR:DS-9000HQH-SH、DS-8100HQH(/HGH)-SH、DS-8000HQH-SH、DS-7300HQH(/HGH)-SH、DS-7200HQH(/HGH)-SH、DS-8800HQH(/HGH)(/HUH)-SH(/Fx)、DS-7900HQH(/HGH)(/HUH)-SH(/Fx)、DS-7800HQH(/HGH)(/HUH)-SH(/Ex/Fx)、DS-7100HGH-E1(/F1)等; HDVR(混合型DVR):DS-9000、DS-8000-ST、DS-7600H-ST/-S系列等; 编码器:DS-6700、DS-6600、DS-6500(-JX)、DS-6100、DS-6401HFH系列视频服务器、DS-6000系列编/解码器等; 解码器:DS-6300D(-JX)、DS-6400HD(-JX/-T)、DS-6500D(-T)等 2. 网络摄像机, 网络球机 网络摄像机:标清、高清、红外、热成像、鱼眼等,如DS-2CD7xx、DS-2CD71xx、DS-2CD72xx、DS-2CD8xx、DS-2CD81xx、DS-2CD82xx、DS-2CD84xx、DS-2CD83xx、DS-2CD11xx、DS-2CD12xx、DS-2CD13xx、DS-2CD20xx、DS-2CD21xx、DS-2CD22xx、DS-2CD23xx、DS-2CD24xx、DS-2CD25xx、DS-2CD26xx、DS-2CD27xx、DS-2CD28xx、DS-2CD29xx、DS-2CD2Axx、DS-2CD2Cxx、DS-2CD2Dxx、DS-2CD2Txx、DS-2CD2Qxx、DS-2CD30xx、DS-2CD31xx、DS-2CD32xx、DS-2CD33xx、DS-2CD34xx、DS-2CD39xx、DS-2CD3Txx、DS-2CD3Qxx、DS-2CD40xx、DS-2CD41xx、DS-2CD42xx、DS-2CD4Axx、DS-2CD62xx、DS-2CD63xx、DS-2CD65xx等 网络球机:标清、高清、红外等,如DS-2DF86xx、DS-2DF85xx、DS-2DF82xx、DS-2DF72xx、DS-2DF71xx、DS-2DE71xx、DS-2DE73xx、DS-2DE72xx、DS-2DM72xx、DS-2DM71xx、DS-2DF1-7xx、DS-2DF66xx、DS-2DF62xx、DS-2DF1-6xx、DS-2DE51xx、DS-2DE52xx、DS-2DE53xx、DS-2DM52xx、DS-2DF52xx、DS-2DC52xx、DS-2DC51xx、DS-2DF1-5xx、DS-2DE45xx、DS-2DE42xx、DS-2DE41xx、DS-2DF1-4xx、DS-2DM1-7xx、DS-2DM1-6xx、DS-2DM1-5xx等 一体化网络摄像机:DS-2ZCN3007、DS-2ZCN3006、DS-2DZ216MF、DS-2DZ2116、DS-2ZCN2006、DS-2ZCN2007、DS-2ZMN2007、DS-2ZMN2006等 3. 智能交通产品 出入口抓拍机:(i)DS-2CD95xx、(i)DS-2CD93xx、(i)DS-2CD92xx、(i)DS-2CD91xx、DS-2CD9xx、DS-TCGxxx、EVU-xxxx等 车位相机:DS-TCPxxx等 出入口控制机:DS-TMExxx等 诱导管理器:DS-TPMxxx等 4. 智能设备 行为分析、ATM防护、自动跟踪、客流量统计、人脸识别、智能交通事件、VQD视频质量诊断等 5. 其他IP设备 CVR、报警主机、门禁、可视对讲、LCD拼接屏、IP模块等
### 海康威视网络摄像头 SDK 的 Python 集成方法 #### 背景介绍 海康威视作为全球领先的安防设备制造商,其提供的 SDK 主要面向 C/C++ 开发者。然而,在实际应用中,许多开发者更倾向于使用 Python 这一高效的语言进行开发[^1]。尽管官方并未提供针对 Python 的原生支持,但通过第三方工具和封装技术,仍然可以实现 Python 对海康威视 SDK 的调用。 --- #### 方法概述 以下是几种常见的 Python 集成海康威视 SDK 的方式: 1. **SWIG 封装** SWIG 是一种强大的工具,能够将 C/C++ 库转换为其他编程语言可用的形式,其中包括 Python。通过 SWIG 封装海康威视的 C++ SDK,可以在 Python 中直接调用相关函数[^3]。 - 安装依赖项并配置环境: ```bash sudo apt-get install swig python-dev libhkipcamera.so ``` - 创建 `interface.i` 文件用于描述 C++ 接口,并执行以下命令生成 Python 绑定文件: ```bash swig -python -c++ interface.i gcc -fPIC -I/usr/include/python3.x -c HKIPcamera_wrap.cxx -o HKIPcamera_wrap.o g++ -shared HKIPcamera_wrap.o -o _HKIPcamera.so ``` - 示例代码展示如何初始化摄像头并与之交互: ```python import HKIPcamera # 加载由 SWIG 生成的模块 import cv2 import numpy as np ip = '192.168.1.64' # 摄像头 IP 地址 username = 'admin' # 用户名 password = 'password' # 密码 HKIPcamera.init(ip, username, password) # 初始化连接 while True: frame = HKIPcamera.getframe() # 获取帧数据 if frame is not None: img = np.array(frame) # 转换为 NumPy 数组 cv2.imshow('Camera Stream', img) # 显示图像 if cv2.waitKey(1) & 0xFF == ord('q'): break cv2.destroyAllWindows() HKIPcamera.release() # 释放资源 ``` 2. **Ctypes 方式** 如果不希望引入额外的工具链,可以直接利用 Python 自带的 `ctypes` 模块加载动态链接库 (DLL 或 .so),并通过它调用底层 API 函数[^2]。 - 基础示例演示如何加载共享库以及访问其中的方法: ```python from ctypes import cdll, c_char_p, POINTER, Structure class NET_DVR_DEVICEINFO_V30(Structure): pass # 替代结构体定义 dll_path = './libHCNetSDK.so' hcnet_sdk = cdll.LoadLibrary(dll_path) user_id = hcnet_sdk.NET_DVR_LoginV30(c_char_p(b'192.168.1.64'), 8000, c_char_p(b'admin'), c_char_p(b'password'), POINTER(NET_DVR_DEVICEINFO_V30)()) if user_id < 0: print("Login failed.") else: print("Login successful with ID:", user_id) # 实现更多功能... hcnet_sdk.NET_DVR_Logout(user_id) ``` 3. **借助现有开源项目** 社区中有不少开发者分享了自己的解决方案,比如 GitHub 上的一些仓库就提供了完整的案例供参考。这些项目的优点在于它们通常已经解决了大部分兼容性和性能优化方面的问题,适合快速上手。 --- #### 注意事项 - 确保本地已正确安装海康威视 SDK 并完成必要的路径设置[^4]。 - 不同版本间的接口可能存在差异,请仔细阅读对应版本的手册说明。 - 若遇到权限错误或其他异常情况,则需检查防火墙状态或者调整服务端授权策略。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值