项目场景:
通过海康摄像头进行车牌识别。
注意避坑:
(1)将官方文档的【库文件】里的HCNetSDK.dll、HCCore.dllHCNetSDKCom文件夹、libssl-1_1-x64.dll.dll、libcrypto-1_1-x64.dll.dll、hlog.dll、hpr.dll、zlib1.dll、log4cxx.properties等文件均拷贝到java.exe同级目录下(xxx/jdk/bin或者xxx/jdk/jre/bin)。
(2)把官方DEMO中的HCNetSDK.java拷贝至项目当中。
(3)加载HCNetSDK.dll(在HCNetSDK.java添加以下内容)
HCNetSDK INSTANCE = Native.load( "HCNetSDK", HCNetSDK.class);
(4)继承Structure可能会报错,需要添加HIKSDKStructure 重写,然后将HCNetSDK.java中所有继承Structure改成继承HIKSDKStructure即可。
package com.support.sdk.hikvision;
import com.sun.jna.Structure;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
public class HIKSDKStructure extends Structure {
@Override
protected List<String> getFieldOrder(){
List<String> fieldOrderList = new ArrayList<String>();
for (Class<?> cls = getClass();
!cls.equals(HIKSDKStructure.class);
cls = cls.getSuperclass()) {
Field[] fields = cls.getDeclaredFields();
int modifiers;
for (Field field : fields) {
modifiers = field.getModifiers();
if (Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) {
continue;
}
fieldOrderList.add(field.getName());
}
}
return fieldOrderList;
}
}
总体流程
初始化SDK
设置报警回调函数
用户登录
获取设备能力集(是否具备车牌识别能力)
- 配置报警条件(可选)
- 报警布防
报警回调函数里面接收和处理数据(可选)
报警撤防
登出
释放SDK资源
SDK初始化:
提示:lUserID=连接摄像头后返回的句柄数(0成功)。
/**
* 初始化连接摄像头
*/
private void initConn(String deviceIp, Short devicePort, String userName, String pwd) {
// SDK未初始化
boolean initSuc = HCNetSDK.INSTANCE.NET_DVR_Init();
if (!initSuc) {
log.error("SDK初始化失败");
return;
}
//设置连接时间与重连时间
HCNetSDK.INSTANCE.NET_DVR_SetConnectTime(2000, 1);
HCNetSDK.INSTANCE.NET_DVR_SetReconnect(100000, true);
// 设备登录信息
HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();
// 设备信息
HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();
// 设置ip、port、userName、pwd
m_strLoginInfo.sDeviceAddress = new byte[HCNetSDK.NET_DVR_DEV_ADDRESS_MAX_LEN];
System.arraycopy(deviceIp.getBytes(), 0, m_strLoginInfo.sDeviceAddress, 0, deviceIp.length());
m_strLoginInfo.wPort = devicePort;
m_strLoginInfo.sUserName = new byte[HCNetSDK.NET_DVR_LOGIN_USERNAME_MAX_LEN];
System.arraycopy(userName.getBytes(), 0, m_strLoginInfo.sUserName, 0, userName.length());
m_strLoginInfo.sPassword = new byte[HCNetSDK.NET_DVR_LOGIN_PASSWD_MAX_LEN];
System.arraycopy(pwd.getBytes(), 0, m_strLoginInfo.sPassword, 0, pwd.length());
// 是否异步登录:false- 否,true- 是
m_strLoginInfo.bUseAsynLogin = false;
m_strLoginInfo.write();
lUserID = HCNetSDK.INSTANCE.NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo);
if (lUserID == -1) {
System.out.println("登录失败,错误码为" + HCNetSDK.INSTANCE.NET_DVR_GetLastError());
HCNetSDK.INSTANCE.NET_DVR_Cleanup();
return;
} else {
System.out.println("登录成功!");
// read()后,结构体中才有对应的数据
m_strDeviceInfo.read();
}
}
获取设备能力:
提示:通过连接句柄获取设备能力
能力类型 能力值 描述 IPC_FRONT_PARAMETER_V20 0x009 设备前端参数 DEVICE_ABILITY_INFO 0x011 智能交通摄像机和ITS智能终端设备能力 SNAPCAMERA_ABILITY 0x300 智能交通摄像机抓拍能力 ITC_TRIGGER_MODE_ABILITY 0x301 智能交通摄像机(V3.1及以后版本)的触发模式能力
private boolean getCameraAbility() {
HCNetSDK.NET_DVR_STD_ABILITY ability = new HCNetSDK.NET_DVR_STD_ABILITY();
ability.dwOutSize = ability.size();
ability.write();
return HCNetSDK.INSTANCE.NET_DVR_GetDeviceAbility(lUserID, 0x011, null, 0, ability.getPointer(), ability.size());
}
回调事件:
提示::
public boolean CarNumberCallBack(int lCommand, HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen, Pointer pUser) {
log.info("开始回调事件,开始识别车牌=====================");
try {
// 接收对车辆信息对象
CarNumberCapturedArgs carInfo = new CarNumberCapturedArgs();
switch (lCommand) {
//COMM_ITS_PLATE_RESULT 交通抓拍
case 0x3050:
HCNetSDK.NET_ITS_PLATE_RESULT strItsPlateResult = new HCNetSDK.NET_ITS_PLATE_RESULT();
strItsPlateResult.write();
Pointer pItsPlateInfo = strItsPlateResult.getPointer();
pItsPlateInfo.write(0, pAlarmInfo.getByteArray(0, strItsPlateResult.size()), 0, strItsPlateResult.size());
strItsPlateResult.read();
try {
// 获取车牌号
String carNumber = new String(strItsPlateResult.struPlateInfo.sLicense, "GBK");
carInfo.setCarNumber(carNumber);
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
try {
for (int i = 0; i < strItsPlateResult.dwPicNum; i++) {
if (strItsPlateResult.struPicInfo[i].dwDataLen > 0) {
//1.车辆场景图片(大图) 0.车牌图片(小图)
if (strItsPlateResult.struPicInfo[i].byType == 1) {
//将字节写入
ByteBuffer buffers = strItsPlateResult.struPicInfo[i].pBuffer.getByteBuffer(0L, strItsPlateResult.struPicInfo[i].dwDataLen);
byte[] imageBigBytes = new byte[strItsPlateResult.struPicInfo[i].dwDataLen];
buffers.rewind();
buffers.get(imageBigBytes);
carInfo.setFullImage(imageBigBytes);
} else if (strItsPlateResult.struPicInfo[i].byType == 0) {
//将字节写入
ByteBuffer buffers = strItsPlateResult.struPicInfo[i].pBuffer.getByteBuffer(0L, strItsPlateResult.struPicInfo[i].dwDataLen);
byte[] imageSmallBytes = new byte[strItsPlateResult.struPicInfo[i].dwDataLen];
buffers.rewind();
buffers.get(imageSmallBytes);
carInfo.setCarNumberImage(imageSmallBytes);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
break;
default:
break;
}
log.info("识别信息======================" + JSONObject.toJSON(carInfo));
// TODO 将识别后的信息传到业务模块
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
开始识别:
提示:识别车牌。
public void carNumberRecognize() {
// 判断摄像头是否有车牌识别能力
if (!getCameraAbility()) {
log.error(String.format("%s摄像头无车牌识别功能,ip=%s,port=%d", name, ip, port));
return;
}
//启用布防
HCNetSDK.NET_DVR_SETUPALARM_PARAM lpSetupParam = new HCNetSDK.NET_DVR_SETUPALARM_PARAM();
lpSetupParam.dwSize = 0;
//布防优先级:0 = 一等级(高),1 = 二等级(中)
lpSetupParam.byLevel = 1;
//上传报警信息类型: 0 = 老报警信息(NET_DVR_PLATE_RESULT), 1 = 新报警信息(NET_ITS_PLATE_RESULT)
lpSetupParam.byAlarmInfoType = 1;
int lAlarmHandle = HCNetSDK.INSTANCE.NET_DVR_SetupAlarmChan_V41(lUserID, lpSetupParam);
if (lAlarmHandle < 0) {
log.error(String.format("%s启动车牌识别失败,错误代码= %d", name, HCNetSDK.INSTANCE.NET_DVR_GetLastError()));
HCNetSDK.INSTANCE.NET_DVR_Logout(lUserID);
HCNetSDK.INSTANCE.NET_DVR_Cleanup();
return;
}
// 设置报警回调函数
if (!HCNetSDK.INSTANCE.NET_DVR_SetDVRMessageCallBack_V30(this::CarNumberCallBack, null)) {
log.error(String.format("%s设置回调函数失败,错误代码= %d", name, HCNetSDK.INSTANCE.NET_DVR_GetLastError()));
log.error("设置回调函数失败" + HCNetSDK.INSTANCE.NET_DVR_GetLastError());
return;
} else {
log.info("设置回调函数成功");
}
}