Java海康门禁设备 对接人脸下发API

海康门禁机设备API接口对接

引言:
我本人在对接海康门禁机设备的时候遇到了两个

  1. 问题1:人脸下发失败的问题,是根据官方的Demo,遇到的问题,可以参考一下

在这里插入图片描述

这个问题我排查了很久,最终发现是海康给的Demo里面的Json包是有问题的,json数据经过断点排查,发现请求下发的参数里面并无人脸信息

  1. 问题2:人员下发时候的照片是有规格要求的,图片大小200k以内,图片的裁剪比例要求,可以使用技术规避,人员照片规格要求(比如说清晰度,复杂背景,脸部位置问题,只能人员重新上传)

1. 人脸下发API解决

1.把原生Json包替换会hutool工具类的Json包
2.写一个工具类解决图片大小问题,图片裁剪比例问题

亲测可以用

 /**
     * 功能:按照二进制方式下发人脸图片
     * @param userID  用户注册ID
     * @param employeeNo 人员工号
     * @throws JSONException
     * @throws InterruptedException
     */
    public static void addFaceByBinary(int userID, String employeeNo) throws JSONException, InterruptedException, IOException {
        HCNetSDK.BYTE_ARRAY ptrByteArray = new HCNetSDK.BYTE_ARRAY(1024); // 数组
        String strInBuffer = "PUT /ISAPI/Intelligent/FDLib/FDSetUp?format=json";
        System.arraycopy(strInBuffer.getBytes(), 0, ptrByteArray.byValue, 0, strInBuffer.length()); // 字符串拷贝到数组中
        ptrByteArray.write();

        int lHandler = hCNetSDK.NET_DVR_StartRemoteConfig(userID, HCNetSDK.NET_DVR_FACE_DATA_RECORD, ptrByteArray.getPointer(), strInBuffer.length(), null, null);
        if (lHandler < 0) {
            System.out.println("Addface NET_DVR_StartRemoteConfig 失败,错误码为" + hCNetSDK.NET_DVR_GetLastError());
            return;
        } else {
            System.out.println("Addface NET_DVR_StartRemoteConfig 成功!");

            HCNetSDK.NET_DVR_JSON_DATA_CFG struAddFaceDataCfg = new HCNetSDK.NET_DVR_JSON_DATA_CFG();
            struAddFaceDataCfg.read();

            cn.hutool.json.JSONObject jsonObject = new cn.hutool.json.JSONObject();
            jsonObject.set("faceLibType", "blackFD");
            jsonObject.set("FDID", "1");
            jsonObject.set("FPID", employeeNo); // 人脸下发关联的工号

            String strJsonData = jsonObject.toString();
            System.arraycopy(strJsonData.getBytes(), 0, ptrByteArray.byValue, 0, strJsonData.length()); // 字符串拷贝到数组中
            ptrByteArray.write();
            struAddFaceDataCfg.dwSize = struAddFaceDataCfg.size();
            struAddFaceDataCfg.lpJsonData = ptrByteArray.getPointer();
            struAddFaceDataCfg.dwJsonDataSize = strJsonData.length();

            /*****************************************
             * 从本地文件里面读取JPEG图片二进制数据
             *****************************************/
            FileInputStream picfile = null;
            int picdataLength = 0;
            byte[] picBytes = null;
            try {
                picfile = new FileInputStream(new File(".//pic//333.jpg"));
                picdataLength = picfile.available();
                picBytes = new byte[picdataLength];
                picfile.read(picBytes);
                picfile.close();
            } catch (IOException e) {
                e.printStackTrace();
                return;
            }

            if (picBytes == null || picBytes.length <= 0) {
                System.out.println("input file dataSize < 0");
                return;
            }
            File p1 = new File(".//pic//333.jpg");
            byte[] imageBytes = FileUtil.readBytes(p1);

            byte[] finBytes = ImageUtil.resizeImage(imageBytes, 600, 800);
            // 压缩图片到200KB
            byte[] compressedPicBytes = ImageUtil.compressPicForScale(finBytes, 200);
            HCNetSDK.BYTE_ARRAY ptrpicByte = new HCNetSDK.BYTE_ARRAY(compressedPicBytes.length);
            System.arraycopy(compressedPicBytes, 0, ptrpicByte.byValue, 0, compressedPicBytes.length);
            ptrpicByte.write();
            struAddFaceDataCfg.dwPicDataSize = compressedPicBytes.length;
            struAddFaceDataCfg.lpPicData = ptrpicByte.getPointer();
            struAddFaceDataCfg.write();

            HCNetSDK.BYTE_ARRAY ptrOutuff = new HCNetSDK.BYTE_ARRAY(1024);
            IntByReference pInt = new IntByReference(0);

            while (true) {
                int dwState = hCNetSDK.NET_DVR_SendWithRecvRemoteConfig(lHandler, struAddFaceDataCfg.getPointer(), struAddFaceDataCfg.dwSize, ptrOutuff.getPointer(), 1024, pInt);
                if (dwState == -1) {
                    System.out.println("NET_DVR_SendWithRecvRemoteConfig接口调用失败,错误码:" + hCNetSDK.NET_DVR_GetLastError());
                    break;
                }
                // 读取返回的json并解析
                ptrOutuff.read();
                String strResult = new String(ptrOutuff.byValue).trim();
                System.out.println("dwState:" + dwState + ",strResult:" + strResult);

                cn.hutool.json.JSONObject jsonResult = new cn.hutool.json.JSONObject(strResult);
                int statusCode = jsonResult.getInt("statusCode");
                if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_NEED_WAIT) {
                    System.out.println("配置等待");
                    Thread.sleep(10);
                    continue;
                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_FAILED) {
                    System.out.println("下发人脸失败, json retun:" + jsonResult.toString());
                    break;
                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_EXCEPTION) {
                    System.out.println("下发人脸异常, json retun:" + jsonResult.toString());
                    break;
                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_SUCCESS) {
                    if (statusCode != 1) {
                        System.out.println("下发人脸成功,但是有异常情况:" + jsonResult.toString());
                    } else {
                        System.out.println("下发人脸成功, json retun:" + jsonResult.toString());
                    }
                    break;
                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_FINISH) {
                    System.out.println("下发人脸完成");
                    break;
                }
            }
            if (!hCNetSDK.NET_DVR_StopRemoteConfig(lHandler)) {
                System.out.println("NET_DVR_StopRemoteConfig接口调用失败,错误码:" + hCNetSDK.NET_DVR_GetLastError());
            } else {
                System.out.println("NET_DVR_StopRemoteConfig接口成功");
            }
        }
    }
package util;

import net.coobird.thumbnailator.Thumbnails;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

/**
 * @Author rjx
 * @Date 2024/7/05
 */
//@Slf4j
//@UtilityClass
public class ImageUtil {

    /**
     * 根据指定大小压缩图片
     *
     * @param imageBytes  源图片字节数组
     * @param desFileSize 指定图片大小,单位kb
     * @return 压缩质量后的图片字节数组
     */
    public static byte[] compressPicForScale(byte[] imageBytes, long desFileSize) {
        if (imageBytes == null || imageBytes.length <= 0 || imageBytes.length < desFileSize * 1024) {
            return imageBytes;
        }
        long srcSize = imageBytes.length;
        double accuracy = getAccuracy(srcSize / 1024);
        try {
            while (imageBytes.length > desFileSize * 1024) {
                ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageBytes.length);
                Thumbnails.of(inputStream)
                        .scale(accuracy)
                        .outputQuality(accuracy)
                        .toOutputStream(outputStream);
                imageBytes = outputStream.toByteArray();
            }
            System.out.println("图片原大小="+ (srcSize / 1024)+"kb | 压缩后大小={}kb" +( imageBytes.length / 1024) );
        } catch (Exception e) {
            System.out.println("【图片压缩】msg=图片压缩失败!"+e);
        }
        return imageBytes;
    }

    /**
     * 自动调节精度(经验数值)
     *
     * @param size 源图片大小
     * @return 图片压缩质量比
     */
    private static double getAccuracy(long size) {
        double accuracy;
        if (size < 900) {
            accuracy = 0.85;
        } else if (size < 2047) {
            accuracy = 0.6;
        } else if (size < 3275) {
            accuracy = 0.44;
        } else {
            accuracy = 0.4;
        }
        return accuracy;
    }




    private static BufferedImage toBufferedImage(Image img) {
        if (img instanceof BufferedImage) {
            return (BufferedImage) img;
        }

        // Create a buffered image with transparency
        BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_RGB);

        // Draw the image on to the buffered image
        Graphics2D bGr = bimage.createGraphics();
        bGr.drawImage(img, 0, 0, null);
        bGr.dispose();

        return bimage;
    }


    /**
     * 调整图片大小为指定宽度和高度
     *
     * @param imageBytes  源图片字节数组
     * @param width       目标宽度
     * @param height      目标高度
     * @return 调整大小后的图片字节数组
     */
    public static byte[] resizeImage(byte[] imageBytes, int width, int height) {
        try {
            ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            Thumbnails.of(inputStream)
                    .size(width, height)
                    .outputFormat("jpg")
                    .toOutputStream(outputStream);
            return outputStream.toByteArray();
        } catch (Exception e) {
//            log.error("【图片调整大小】msg=图片调整大小失败!", e);
            return imageBytes; // 返回原始图片字节数组以防失败
        }
    }

}

在这里插入图片描述

对接海康门禁添加人脸需要使用海康门禁SDK,以下是Java调用海康门禁SDK实现对门禁设备添加人脸的示例代码: ```java import com.sun.jna.Native; import com.sun.jna.Pointer; import com.sun.jna.ptr.ByteByReference; import com.sun.jna.ptr.IntByReference; public class HikvisionFaceController { public interface HikvisionLibrary extends com.sun.jna.Library { HikvisionLibrary INSTANCE = (HikvisionLibrary) Native.loadLibrary("HCNetSDK", HikvisionLibrary.class); int NET_DVR_Init(); int NET_DVR_Login_V40(); int NET_DVR_Logout_V30(); int NET_DVR_GetLastError(); int NET_DVR_SetDVRConfig(); int NET_DVR_GetDVRConfig(); int NET_DVR_SendRemoteConfig(); int NET_DVR_StopRemoteConfig(); } public static void main(String[] args) { // 初始化SDK HikvisionLibrary.INSTANCE.NET_DVR_Init(); // 登录门禁 IntByReference lUserID = new IntByReference(); HikvisionLibrary.NET_DVR_DEVICEINFO_V40 struDeviceInfo = new HikvisionLibrary.NET_DVR_DEVICEINFO_V40(); lUserID.setValue(HikvisionLibrary.INSTANCE.NET_DVR_Login_V40("192.168.1.64", (short) 8000, "admin", "password", struDeviceInfo)); // 添加人脸 HikvisionLibrary.NET_DVR_XML_CONFIG_INPUT struInput = new HikvisionLibrary.NET_DVR_XML_CONFIG_INPUT(); struInput.dwSize = struInput.size(); String str = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<FaceAppendData>" + "<name>test</name>" + "<gender>1</gender>" + "<bornTime>19900101</bornTime>" + "<certificateType>111</certificateType>" + "<certificateNumber>123456789012345678</certificateNumber>" + "<certificatePicUrl>http://192.168.1.64/certificate.jpg</certificatePicUrl>" + "<facePicUrl>http://192.168.1.64/face.jpg</facePicUrl>" + "</FaceAppendData>"; byte[] byInput = str.getBytes(); struInput.lpRequestUrl = "POST /ISAPI/Intelligent/FDLib/FDSearch/AddFaceDataInFDLib?format=json".getBytes(); struInput.dwRequestUrlLen = struInput.lpRequestUrl.length; struInput.lpInBuffer = byInput; struInput.dwInBufferSize = byInput.length; struInput.write(); Pointer lpInBuffer = struInput.getPointer(); HikvisionLibrary.NET_DVR_XML_CONFIG_OUTPUT struOutput = new HikvisionLibrary.NET_DVR_XML_CONFIG_OUTPUT(); struOutput.dwSize = struOutput.size(); struOutput.lpOutBuffer = new byte[1024]; struOutput.dwOutBufferSize = struOutput.lpOutBuffer.length; struOutput.write(); Pointer lpOutBuffer = struOutput.getPointer(); boolean result = HikvisionLibrary.INSTANCE.NET_DVR_SendRemoteConfig(lUserID.getValue(), 255, HikvisionLibrary.NET_DVR_SET_FACEAPPEND_DATA, lpInBuffer, struInput.size(), lpOutBuffer, struOutput.size()); if (!result) { System.out.println("添加人脸失败,错误码:" + HikvisionLibrary.INSTANCE.NET_DVR_GetLastError()); } // 注销登录 HikvisionLibrary.INSTANCE.NET_DVR_Logout_V30(lUserID.getValue()); } } ``` 需要注意的是,代码中的IP地址、端口、用户名、密码等信息需要替换为实际的门禁设备信息。同时,需要将海康门禁SDK的库文件 HCNetSDK.dll 放置在Java工程的运行路径下。人脸信息需要按照门禁设备接口要求的XML格式进行组装,并通过海康门禁SDK的接口发送到门禁设备
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值