之前已经写了个简单的,但是觉得可能有些人第一次使用会遇到大麻烦,所以写完整一点。
首先要明白 我们用JAVA代码去操控硬件是有两条路线走的,
第一条:联网方式,根据硬件厂家提供的SDK进行初始化、输入账号、密码进行连接。
第二条:用设备直接连接,如USB,这个就需要用到串口COMM编程了。
刚好两个我都在公司的项目上遇到过,所以就稍微懂了一点,但是仅仅是入门使用而已。
好了,接下来我们就开始回到题目了
**
引入海康的SDK中有个HCNetSDK.java,里面定义了很多很多东西,包括人脸对别。
那么我们需要人脸对比就写一个类去实现它里面定义的人脸比对的接口(它没明说是人脸比对,是通过报警回调函数中的黑名单报警这个接口去实现人脸比对的),
简单来说就是写个类去实现HCNetSDK.FMSGCallBack 然后根据条件函数 case HCNetSDK.COMM_SNAP_MATCH_ALARM(人脸对别的黑名单): 去操作我们需要的步骤。
然后除此之外,你引用人家的类 少不了进行类的初始化操作、账号和密码的设定,IP地址的绑定等这些步骤
1.去海康官网下载最新的SDK 官网地址:https://www.hikvision.com/cn/
2.下载好了之后创建maven项目,
按照SDK里面的文档要求把下图文件夹和文件引入(在SDK库文件夹里),
7个dll文件和一个KCNetSDK文件夹(我这里创建了一个HCNetSDK的文件夹装下这些)
3.接下来把他的接口类引入 如下
打开接口类 看33行 这里有个引入dll文件的代码
我这里是用的文件引入工具类(这个类后面有给出),你们自己换成目录
resources\HCNetSDK\HCNetSDK的绝对路径!!!!
其实这里引入的就是我们引入的7个dll文件中的HCNetSDK.dll这个文件,这里绝对路径引入的时候不要.dll后缀名。
文件也引入了 接下来就是我们自己创建java类去调用它的接口类了
创建两个类 一个是报警回调函数的实现类(用来实现调用海康人脸比对)
一个是主类 里面包含 初始化海康接口类、调用第一个函数实现人脸对比等等
/**
* 报警回调函数中接收和处理数据
*/
@Controller
public class FMSGCallBackController implements HCNetSDK.FMSGCallBack {
//报警信息回调函数
public void invoke(int lCommand, HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen, Pointer pUser) {
try {
String sAlarmType = new String();
String[] newRow = new String[3];
//报警时间
Date today = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
String[] sIP = new String[2];
sAlarmType = new String("lCommand=") + lCommand;
//lCommand是传的报警类型
switch (lCommand) {
case HCNetSDK.COMM_SNAP_MATCH_ALARM: //人脸黑名单比对报警
HCNetSDK.NET_VCA_FACESNAP_MATCH_ALARM strFaceSnapMatch = new HCNetSDK.NET_VCA_FACESNAP_MATCH_ALARM();
strFaceSnapMatch.write();
Pointer pFaceSnapMatch = strFaceSnapMatch.getPointer();
pFaceSnapMatch.write(0, pAlarmInfo.getByteArray(0, strFaceSnapMatch.size()), 0, strFaceSnapMatch.size());
strFaceSnapMatch.read();
sAlarmType = sAlarmType + ":人脸黑名单比对报警,相识度:" + strFaceSnapMatch.fSimilarity + ",黑名单姓名:" +
new String(strFaceSnapMatch.struBlackListInfo.struBlackListInfo.struAttribute.byName, "GBK").trim() + ",黑名单证件信息:" +
new String(strFaceSnapMatch.struBlackListInfo.struBlackListInfo.struAttribute.byCertificateNumber).trim();
//人脸相似度
float fSimilarity = strFaceSnapMatch.fSimilarity;
//********************************从这里开始 这里是我们自己操作的内容 里面的QueryInsertAlarmInformationService 换成你自己定义要干嘛的service就行
//员工姓名
String employeeName = new String(strFaceSnapMatch.struBlackListInfo.struBlackListInfo.struAttribute.byName, "GBK").trim();
//报警时间
String alarmTime = dateFormat.format(today);
//如果识别的人名不为空则进行数据库操作
if(null !=employeeName && !"".equals(employeeName)){
//根据姓名进行数据库匹配
QueryInsertAlarmInformationService queryInsertAlarmInformation = new QueryInsertAlarmInformationService();
//查询出用户USERID
String userID = queryInsertAlarmInformation.QueryUserIdByDepartAndName(employeeName);
//将数据保存到数据库
if(null!=userID && !"".equals(userID)){
queryInsertAlarmInformation.InsertAttAllEvent(userID,alarmTime);
}
}
//****************************自己操作的部分结束
newRow[0] = dateFormat.format(today);
//报警类型
newRow[1] = sAlarmType;
//报警设备IP地址
sIP = new String(pAlarmer.sDeviceIP).split("\0", 2);
newRow[2] = sIP[0];
System.out.println("人脸比对结果: "+employeeName+" "+alarmTime);
//System.out.println("这是人脸比对报警信息:" + "报警时间:" + dateFormat.format(today) + "\r\n" + "报警类型:" + sAlarmType + "\r\n" + "报警设备IP:" + sIP[0]);
break;
default:
newRow[0] = dateFormat.format(today);
//报警类型
newRow[1] = sAlarmType;
//报警设备IP地址
sIP = new String(pAlarmer.sDeviceIP).split("\0", 2);
newRow[2] = sIP[0];
//System.out.println("这是人脸比对报警信息:"+"报警时间:"+dateFormat.format(today)+"\r\n"+"报警类型:"+sAlarmType+"\r\n"+"报警设备IP:"+sIP);
break;
}
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(FaceCompareAlarmInfoController.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
QueryInsertAlarmInformationService 类 这个换成你自己定义的service
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
/**
* 对数据库逻辑的处理
*/
public class QueryInsertAlarmInformationService {
public static Connection conn = null;
public static PreparedStatement ps = null;
public static ResultSet rs = null;
/**
* 向AttAllEvent中插入数据
*
* @param UserID
* @param EventTime
*/
public void InsertAttAllEvent(String UserID, String EventTime) {
String eventType = "刷卡";
Integer doorType = 0;
try {
//连接数据库
conn = DataBaseConnectionUtil.getConnection();
String sql = "insert into AttAllEvent (UserID,EventTime,EventType,DoorType) values(?,?,?,?)";
ps = conn.prepareStatement(sql);
ps.setString(1, UserID);
ps.setString(2, EventTime);
ps.setString(3, eventType);
ps.setInt(4, doorType);
// 执行sql语句
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 关闭数据库连接对象
DataBaseConnectionUtil.close2(ps, conn);
}
}
/**
* 查询出所有部门的员工姓名和部门拼接
*/
public Map QueryDepartNameAndEmployeeName() {
Map departName = new HashMap<>();
try {
conn = DataBaseConnectionUtil.getConnection();
String sql = "SELECT Department+Name as DName ,UserID FROM AttUser;";
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
while (rs.next()) {
String dName = rs.getString("DName");
String userID = rs.getString("UserID");
departName.put(rs.getString("DName"), rs.getString("UserID"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 关闭数据库连接对象
DataBaseConnectionUtil.close(rs, ps, conn);
}
return departName;
}
/**
* 查询出用户id
* @param departUserName
* @return
*/
public String QueryUserIdByDepartAndName( String departUserName) {
Map map = QueryDepartNameAndEmployeeName();
for(Map.Entry entry : map.entrySet()){
String mapKey = entry.getKey();
String mapValue = entry.getValue();
//判断用户名和部门名是否匹配设备上传过来的
if (departUserName.equals(mapKey)){
return mapValue;
}
}
return "";
}
}
DataBaseConnectionUtil 数据库连接类 我们直接用的是JDBC连接数据库操作的 如果采用springboot或者其他框架整合了mybatis数据库框架的话可以节省这一步
import java.sql.*;
/**
* 数据库连接工具类
*/
public class DataBaseConnectionUtil {
// 连接驱动 这里连接的是sqlserver mysql的请更换
private static final String DRIVERCLASSNAME= "com.microsoft.sqlserver.jdbc.SQLServerDriver";
// 连接路径
private static final String URL = "jdbc:sqlserver://localhost:1433;DatabaseName=XXX";
// 数据库用户名
private static final String USERNAME = "sa";
// 数据库密码
private static final String PASSWORD = "123456";
//静态代码块
static {
try {
// 加载驱动
Class.forName(DRIVERCLASSNAME);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/*
* 获取数据库连接
*/
public static Connection getConnection() {
Connection conn = null;
try{
conn= DriverManager.getConnection(URL, USERNAME, PASSWORD);
}catch(SQLException e){
e.printStackTrace();
}
return conn;
}
/*
* 关闭数据库连接,释放资源
*/
public static void close(ResultSet rs, PreparedStatement ps, Connection conn) {
if(rs!=null){
try{
rs.close();
rs=null;
}catch(SQLException e){
e.printStackTrace();
}
}
if(ps!=null){
try{
ps.close();
ps=null;
}catch(SQLException e){
e.printStackTrace();
}
}
if(conn!=null){
try{
conn.close();
conn=null;
}catch(SQLException e){
e.printStackTrace();
}
}
}
/*
* 关闭数据库连接,释放资源
*/
public static void close2( PreparedStatement ps, Connection conn) {
if(ps!=null){
try{
ps.close();
ps=null;
}catch(SQLException e){
e.printStackTrace();
}
}
if(conn!=null){
try{
conn.close();
conn=null;
}catch(SQLException e){
e.printStackTrace();
}
}
}
}
**
@Controller
public class FaceCompareAlarmInfoController {
HCNetSDK hCNetSDK = HCNetSDK.INSTANCE;
//设备信息
HCNetSDK.NET_DVR_DEVICEINFO_V30 m_strDeviceInfo;
//已登录设备的IP地址
String m_sDeviceIP;
//用户句柄
NativeLong lUserID;
//报警布防句柄
NativeLong lAlarmHandle;
//报警监听句柄
NativeLong lListenHandle;
//报警回调函数实现
FMSGCallBackController fMSFCallBack;
public FaceCompareAlarmInfoController() {
this.initInformation();
}
/**
* 初始化信息
*/
public void initInformation() {
//初始化的参数
lUserID = new NativeLong(-1);
lAlarmHandle = new NativeLong(-1);
lListenHandle = new NativeLong(-1);
fMSFCallBack = null;
//注册
Boolean login = this.Login();
if (login){
//注册成功就进行布防
this.SetupAlarmChan();
while (true) ;
}
}
/**
* 用户注册
*
* @return
*/
public Boolean Login() {
//初始化
HCNetSDK hCNetSDK = HCNetSDK.INSTANCE;
boolean initSuc = hCNetSDK.NET_DVR_Init();
if (initSuc != true) {
System.out.println("初始化失败"+ " 失败原因是:" + hCNetSDK.NET_DVR_GetLastError());
} else {
System.out.println("接口初始化成功");
}
m_sDeviceIP = HCNetDeviceConUtil.m_sDeviceIP;
m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30();
int iPort = HCNetDeviceConUtil.PORT;
lUserID = hCNetSDK.NET_DVR_Login_V30(m_sDeviceIP,
(short) iPort, HCNetDeviceConUtil.USERNAME, HCNetDeviceConUtil.PASSWORD, m_strDeviceInfo);
long userID = lUserID.longValue();
if (userID == -1) {
System.out.println("注册失败" + " 失败原因是:" + hCNetSDK.NET_DVR_GetLastError());
return false;
} else {
System.out.println("注册成功");
return true;
}
}
/**
* 报警布防
*/
public void SetupAlarmChan() {
if (fMSFCallBack == null) {
fMSFCallBack = new FMSGCallBackController();
Pointer pUser = null;
if (!hCNetSDK.NET_DVR_SetDVRMessageCallBack_V30(fMSFCallBack, pUser)) {
System.out.println("设置回调函数失败!"+ " 失败原因是:" + hCNetSDK.NET_DVR_GetLastError());
}
}
HCNetSDK.NET_DVR_SETUPALARM_PARAM m_strAlarmInfo = new HCNetSDK.NET_DVR_SETUPALARM_PARAM();
m_strAlarmInfo.dwSize = m_strAlarmInfo.size();
m_strAlarmInfo.byLevel = 1;
m_strAlarmInfo.byAlarmInfoType = 1;
m_strAlarmInfo.write();
lAlarmHandle = hCNetSDK.NET_DVR_SetupAlarmChan_V41(lUserID, m_strAlarmInfo);
if (lAlarmHandle.intValue() == -1) {
System.out.println("布放失败" + " 失败原因是:" + hCNetSDK.NET_DVR_GetLastError());
} else {
System.out.println("布防成功");
}
}
}
HCNetDeviceConUtil 账号和密码工具类
import java.io.UnsupportedEncodingException;
/**
* 海康设备账号和密码
*/
public class HCNetDeviceConUtil {
// 登录IP
public static final String m_sDeviceIP = "登录IP"; //(登录IP 例如 192.168.0.1,它可以用来组网,可以在海康后台组建由这个ip控制的某几个海康摄像头)
// 登录名
public static final String USERNAME = "账号"; //(例如 admin)
// 密码
public static final String PASSWORD = "密码"; //(例如 123456)
//设备端口号
public static final Integer PORT = 8000;
//加载海康HCNetSDK.dll文件的路径
public static final String loadLibrary=HCNetSDKPath.DLL_PATH;
public static class HCNetSDKPath {
public static String DLL_PATH;
/*下面这个是加载dll文件的 ,也就是上面的第3步(做了第3步可以不要这个static里面的内容,但是用这个把第3步换成工具类加载更加的方便后续的维护,所以我们把第3步的加载路径换成:
HCNetSDK INSTANCE = (HCNetSDK) Native.loadLibrary(HCNetDeviceConUtil.loadLibrary,
HCNetSDK.class);
*/
static {
String path = (HCNetSDKPath.class.getResource("/HCNetSDK/HCNetSDK.dll").getPath()).replaceAll("%20", " ").substring(1).replace("/",
"\\");
try {
DLL_PATH = java.net.URLDecoder.decode(path, "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
}
源码下载:(下面下载的这个代码和我上面的不一样,但是也是一个完整的人脸比对demo,思路是一样的)
链接:https://pan.baidu.com/s/1QenBYOZO8HGXIgaoTtmvAw
提取码:fkjj