# FaceRecognitionDemo **Repository Path**: MrJimmy/FaceRecognitionDemo ## Basic Information - **Project Name**: FaceRecognitionDemo - **Description**: 定制的 Android 系统硬件特定功能调用的演示项目 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 4 - **Forks**: 5 - **Created**: 2021-10-13 - **Last Updated**: 2025-09-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## FaceRecognitionDemo - 人脸识别硬件 sdk demo ### demo 提供的功能: - 相机预览 - usb 扫码相机预览 - 体温检测 - 读卡 - 232 串口调试 - 韦根调试 - 读身份证 - HID 扫码枪 - 控制 LED 灯光和继电器开关 - 跳转系统的桌面 - U 盘更新 - U 盘文件选择 - 旷世人脸算法简单使用,包括识别和录入流程 - 指纹比对 ### [点击查看更新日志](release.md) ### [Click here to view the English API](README-EN.md) ### Thanks [AndroidUSBCamera](https://github.com/jiangdongguo/AndroidUSBCamera) ### **系统功能** ##### 开机自动启动 参数一 :表示应用包名,对应 Android 平台的 application id 参数二:表示需要定时监控应用是否在前台的时间,单位秒 ,不能小于 15 参数三:是否开机自启动,true/false ```java ESSystem.instance().getsystemManager().startHonitorAppRK( pkgName: "xxx.xx.xx", seconds: 30, islauncher: true); ``` ##### 状态栏导航栏 参数一 : 是否启用禁用 true 启用,false 不启用 参数二 : 是否禁用状态栏 true 禁用,false 不禁用 参数三 : 是否禁用导航栏 true 禁用,false 不禁用 ```java ESSystem.instance().getSystemManager().disableStatusBarRK(true, true, true); ``` ##### 静默安装 参数一 :apk 文件路径 ```java ESSystem.instance().getSystemManager().installApk(file.getAbsolutePath()); ``` ##### 重启 参数一 : 重启原因 ```java ESFaceUtils.reboot(reason) ``` ### 网络管理 ##### 获取网络连接信息 ```java FaceSdkApplication.instance().getSystemHelper().getNetwork().getEthernetNetworkConfig() ``` ##### 设置以太网 ip ```java FaceSdkApplication.instance().getSystemHelper().getNetwork().setEthernetStaticIp(ip, mask, gateway, dns1, dns2) ``` ##### 设置以太网 Dhcp ```java FaceSdkApplication.instance().getSystemHelper().getNetwork().setEthernetStaticDhcp() ``` ##### 设置 wifi ip ```java FaceSdkApplication.instance().getSystemHelper().getNetwork().setWifiStaticIp(ssid, ip, mask, gateway, dns1, dns2) ``` ##### 设置 wifi dhcp ```java FaceSdkApplication.instance().getSystemHelper().getNetwork().setWifiDhcp(ssid) ``` ### **相机** ##### 绑定相机到 LifecycleOwner 参数一 :lifecycleOwner [LifecycleOwner] 参数二 : textureView 相机预览对象 参数三 : openCameraParams 相机打开参数 参数四 :iCameraCallback 相机状态回调 @return [ICamera] ```kotlin mCamera = CameraHelper.bindCommonCameraToLifecycle(getViewLifecycleOwner(), mViewBinding.textureView, new ICameraCallback() { @Override public void onCameraOpenSuccess() { Log.i(TAG, "相机打开成功"); } @Override public void onCameraError() { Log.i(TAG, "相机打开异常,需要重启"); // todo 这种情况下,一般需要重启,因为 sdk 回调这个方法前,已经进行过 5 次 重新打开了,都没有打开成功才回调的 // ESFaceUtils.reboot("相机打开异常"); } @Override public void onCameraPreview(@Nullable byte[] bytes) { } }, CameraSizeHelper.getInstance().getVLOpenParams()); ``` ##### 无需预览 如果不需要预览可以使用 bindCommonCamera2ToLifecycle , textureView 相机预览对象可以为空 ```java mCamera = CameraHelper.bindCommonCamera2ToLifecycle(getViewLifecycleOwner(), mViewBinding.tvOne, new ICameraCallback() { @Override public void onCameraOpenSuccess() { Log.i(TAG, "相机打开成功"); } @Override public void onCameraError() { Log.i(TAG, "相机打开异常,需要重启"); // todo 这种情况下,一般需要重启,因为 sdk 回调这个方法前,已经进行过 5 次重新打开了,都没有打开成功才回调的 // ESFaceUtils.reboot("相机打开异常"); } @Override public void onCameraPreview(@Nullable byte[] bytes) { } }, p); ``` ### 开门和灯光控制 ##### 获取灯光及继电器操作实例 ``` GpioHelper gpioHelper = GpioHelper.getInstance(); ``` ##### 操作继电器开门 ``` gpioHelper.openDoor(); ``` ##### 操作继电器关门 ```java gpioHelper.closeDoor(); ``` ##### 亮起绿色灯并开门 ```java gpioHelper.setPassStatus(true); ``` ##### 亮起红外灯 ``` gpioHelper.setPassStatus(false); ``` ##### 打开白色补光灯 ```java gpioHelper.setWhiteLedStatus(true); ``` ##### 关闭其他灯光并触发关门信号 参数一 :是否开启白色灯光 ``` gpioHelper.ledDismiss(false); ``` ### **刷卡** ##### 简单读卡号 ```java SerialPortManager.instance().getCardRead(getActivity()).startRead(new IReadCardCallback() { @Override public void onReadResult(@NonNull ReadCardResult readCardResult) { SoundPoolHelper.getInstance().playDi(); requireActivity().runOnUiThread(() -> mViewBinding.tvCard.setText("卡号:" + readCardResult.getCardNumber())); Log.e(TAG, "卡号:" + readCardResult.getCardNumber()); } @Override public void onReadFailure(int i, @NonNull String s) { Log.e(TAG, "onReadFailure code:" + i + "msg:" + s); } }); ``` ### 刷身份证 ##### 获取身份证操作类实例 ```java private final IDCardManager mIDCardManager = new IDCardManager(); ``` ##### 读身份证 ``` mIDCardManager.getIDCardRead(requireActivity()).startReadIDCard(new IReadIDCardCallback() { @Override public void onReadResult(@Nullable IDCardInfo idCardInfo) { SoundPoolHelper.getInstance().playDi(); requireActivity().runOnUiThread(() -> { String idCardStr = "姓名: " + idCardInfo.getUsername() + "\n" + "性别: " + idCardInfo.getGender() + "\n" + "名族: " + idCardInfo.getEthnic() + "\n" + "地址: " + idCardInfo.getAddress() + "\n" + "生日: " + idCardInfo.getBirthday() + "\n" + "有效期: " + idCardInfo.getIdValidStart() + " - " + idCardInfo.getIdValid() + "\n" + "发证机关: " + idCardInfo.getIdDepartment() + "\n" + "证件号: " + idCardInfo.getIdNumber(); }); } @Override public void onReadFailure(int i, @NonNull String s) { Log.e(TAG, "onReadFailure code: " + i + " msg: " + s); } @Override public void onInitSuccess(@NonNull String samId) { Log.e(TAG, "onInitSuccess samId: " + samId); } }); ``` ### 高通 NFC 刷卡刷身份证 ##### 开始读普通 IC 卡 ```java NFCReadHelper.INSTANCE.startReadICCard(result -> { SoundPoolHelper.getInstance().playDi(); mViewBinding.tvText.setText("卡号:" + result.getCardNumber()); }); ``` ##### 停止读卡 ``` NFCReadHelper.INSTANCE.stopReadICCard(); ``` ##### 开始读身份证 ```java NFCReadHelper.INSTANCE.startReadIDCard(idCardInfo -> { SoundPoolHelper.getInstance().playDi(); runOnUiThread(() -> { String idCardStr = "姓名: " + idCardInfo.getUsername() + "\n" + "性别: " + idCardInfo.getGender() + "\n" + "名族: " + idCardInfo.getEthnic() + "\n" + "地址: " + idCardInfo.getAddress() + "\n" + "生日: " + idCardInfo.getBirthday() + "\n" + "有效期: " + idCardInfo.getIdValidStart() + " - " + idCardInfo.getIdValid() + "\n" + "发证机关: " + idCardInfo.getIdDepartment() + "\n" + "证件号: " + idCardInfo.getIdNumber(); Log.i("TAG", "id card 身份证读取成功 " + mReadCount); }); }); ``` ##### 停止读身份证 ``` NFCReadHelper.INSTANCE.stopReadIDCard(); ``` ### 扫码 ##### 获取扫码操作实例 ``` private final HIDManager mHidManager = new HIDManager(); ``` ##### 开启扫码 ``` mHidManager.init(new IHIDResultListener() { @Override public void onCompleteData(@NonNull String value) { Log.e(TAG, ""HID 数据:" + count + "\n" + value); } @Override public void onInitFailure(int code, @NonNull String msg) { // 目前只有 code 1,初始化失败 Log.e(TAG, "onInitFailure: code: " + code + " msg: " + msg); } @Override public void onLog(int code, @NonNull String msg) { Log.e(TAG, "onLog ----- : code: " + code + " msg: " + msg); } }); ``` ### 串口通信 ##### 获取串口 Builder() 对象 ``` MySerial.Builder serialBuilder = new MySerial.Builder(); ``` ##### 设置串口地址 ``` serialBuilder.setSerialPath(path); ``` ##### 设置波特率 ``` serialBuilder.setBaudRate(baudRate); ``` ##### 设置接收消息回调 ``` serialBuilder.setCallback(new ISerialDataCallback() { @Override public void onSimpleData(@Nullable byte[] bytes, int offset, int length) { if (bytes == null) { return; } StringBuilder str = new StringBuilder(); String[] hexStr = SerialPortUtilsKt.bytesArrayToHexStr(bytes, offset, length).split(" "); for (String s : hexStr) { if (!s.isEmpty()) { str.append(s); } } requireActivity().runOnUiThread(() -> { Log.i(TAG, "数据开始 ------ " + str); mViewBinding.tvReceive.append(str + "\n"); Log.i(TAG, "数据结束 ------"); }); } }); ``` ##### 串口操作实例 ``` private MySerial mSerial = serialBuilder.build(); ``` ##### 打开串口 ``` mSerial.openPort(); ``` ##### 关闭串口 ``` mSerial.closePort(); ``` ##### 发送消息 ``` mSerial.writePort(data); ``` ### 韦根 ##### 监听韦根输入数据 ``` ESWeigandManager.instance().getCardRead().startRead(new IReadCardCallback() { @Override public void onReadFailure(int code, @NonNull String msg) { mViewBinding.tvReceive.append("韦根输入错误:" + code + " msg:" + msg); } @Override public void onReadResult(@NonNull ReadCardResult result) { String cardNumber = result.getCardNumber(); mViewBinding.tvReceive.append("韦根输入:" + cardNumber + " 类型:" + result.getType()); } }); ``` ##### 韦根 26 输出 ``` boolean result = ESWeigandManager.instance().getWiegandWrite().writeString(value, IWiegand.WIEGAND_TYPE_26); ``` ##### 韦根 34 输出 ``` boolean result = ESWeigandManager.instance().getWiegandWrite().writeString(value, IWiegand.WIEGAND_TYPE_34); ``` ### 指纹 ##### 获取指纹操作实例 ``` private Fingerprint mFingerprint = Fingerprint.instance(); ``` ##### 初始化指纹模块 ``` mFingerprint.init(); ``` ##### 释放指纹模块 ``` mFingerprint.release(); ``` ##### 开始录入指纹 ``` mFingerprint.startEntry(true, new OnFingerprintEntryListener() { @Override public void onExtractSuccess(@NonNull byte[] fingerprint) { // key 为录入指纹唯一标识 mFingerprint.addFingerprintTemplate(key, fingerprint); updateState("录入成功"); } @Override public void onUpdateState(int action, @NonNull String msg, int result) { if (action != Fingerprint.ACTION_GEN_CHAR || result != 0) { updateState("录入:" + msg); } Log.i("FingerprintFragment", "Entry onUpdateState: " + action + " msg: " + msg + " result: " + result); } @Override public void onFingerprintImage(@NonNull byte[] image) { Log.i("FingerprintFragment", "onFingerprintImage: "); } }); ``` ##### 停止录入 ``` mFingerprint.stopEntry(); ``` ##### 开始比对 ``` mFingerprint.startMatch(new OnFingerprintMatchListener() { @Override public void onUpdateState(int action, @NonNull String msg, int result) { updateState("比对:" + msg); Log.i("FingerprintFragment", "Match onUpdateState: " + action + " msg: " + msg + " result: " + result); } @Override public void onMatchComplete(@NonNull List result) { FingerprintMatchResult fingerprint = result.get(0); int score = fingerprint.getScore(); if (score > 50) { updateState("比对成功:" + fingerprint.getFingerprintKey() + " 相似度:" + score); } else { updateState("比对失败:" + fingerprint.getFingerprintKey() + " 相似度:" + score); } } }); ``` ##### 停止比对 ``` mFingerprint.stopMatch(); ``` ### 酒测 ##### 获取酒测操作实例 ``` Alcohol alcohol = Alcohol.instance(); ``` ##### 酒精检测操作回调 ``` private IAlcoholCallBack alcoholCallBack = new IAlcoholCallBack() { @Override public void onReadResult(@NonNull AlcoholResult result) { int type = result.getType(); switch (type) { case 2: { // 准备倒计时 break; } case 3: { // 开始检测吹气,请吹气 showLog("酒测 : 开始检测吹气"); break; } case 4: { // 吹气中 showLog("酒测 : 吹气中"); break; } case 5: { // 吹气中断错误 showLog("酒测 : 吹气中断错误"); break; } case 6: { // 吹气结束 showLog("酒测 : 吹气结束"); break; } case 7: { // 吹气结果 showLog("酒测 : 收到酒测结果: " + result.getResult()); break; } case 8: { // 关闭测试 break; } case 48: { // 获取清零值 break; } case 160: { // 设置吹气时长回复 showLog("酒测:修改吹气时长"); break; } } } }; ``` ##### 初始化酒精模块 ``` alcohol.init(alcoholCallBack); ``` ##### 释放资源 ``` alcohol.release(); ``` ##### 开始检测 ``` alcohol.stopDetection(); ``` ##### 停止检测 ``` alcohol.stopDetection(); ``` ##### 设置吹气时长(建议3s) ``` alcohol.changTestTime(3); ``` ### Modbus 通信 ##### 获取 Modbus 通讯实例 ``` private ModbusMasterWrapper modbusRtuMaster = new ModbusMasterWrapper(); ``` ##### 初始化通信 ``` ModbusSerialPortParam param = new ModbusSerialPortParam(); modbusRtuMaster.init(param, new OnRequestBack() { @Override public void onSuccess(String s) { Log.i(TAG, "modbus rtu init onSuccess: " + s); } @Override public void onFailed(String s) { Log.i(TAG, "modbus rtu init onFailed: " + s); } }); ``` ##### 结束通信 ``` modbusRtuMaster.destory(); ``` ##### 写保存寄存器 16 ``` short[] shortArray = {Short.parseShort("ff",16),Short.parseShort("0B",16),Short.parseShort("0C",16),Short.parseShort("0D",16)}; modbusRtuMaster.writeRegisters(new OnRequestBack() { @Override public void onSuccess(String s) { } @Override public void onFailed(String s) { } },1,1,shortArray); ``` ##### 读线圈 ``` modbusRtuMaster.readCoil(new OnRequestBack() { @Override public void onSuccess(boolean[] booleen) { Log.d(TAG, "readCoil onSuccess " + Arrays.toString(booleen)); } @Override public void onFailed(String msg) { Log.e(TAG, "readCoil onFailed " + msg); } }, 1, 200, 1); ``` ##### 读离散输入 ``` modbusRtuMaster.readDiscreteInput(new OnRequestBack() { @Override public void onSuccess(boolean[] booleen) { Log.d(TAG, "readDiscreteInput onSuccess " + Arrays.toString(booleen)); } @Override public void onFailed(String msg) { Log.e(TAG, "readDiscreteInput onFailed " + msg); } }, 1, 200, 1); ``` ##### 读输入寄存器 ```java modbusRtuMaster.readInputRegisters(new OnRequestBack() { @Override public void onSuccess(short[] data) { Log.d(TAG, "readInputRegisters onSuccess " + Arrays.toString(data)); } @Override public void onFailed(String msg) { Log.e(TAG, "readInputRegisters onFailed " + msg); } }, 1, 2, 8); ``` ##### 写线圈 ```java getModbusMaster().writeCoil(new OnRequestBack() { @Override public void onSuccess(String s) { Log.e(TAG, "writeCoil onSuccess " + s); } @Override public void onFailed(String msg) { Log.e(TAG, "writeCoil onFailed " + msg); } }, 1, 1, true); ``` ##### 写寄存器 ```java getModbusMaster().writeRegister(new OnRequestBack() { @Override public void onSuccess(String s) { Log.e(TAG, "writeRegister onSuccess " + s); } @Override public void onFailed(String msg) { Log.e(TAG, "writeRegister onFailed " + msg); } }, 1, 1, 234); ``` ### 双屏异显 ##### 启动服务,连接副屏 ``` PresentationServiceManager.INSTANCE.startService(() -> { Log.i(TAG,"副屏连接成功"); return Unit.INSTANCE; }); ``` ##### 断开屏幕 ```java PresentationServiceManager.INSTANCE.dismiss(); ``` ##### 停止服务 ``` PresentationServiceManager.INSTANCE.stopService(); ``` ##### 刷新副屏内容 screenView : 副屏显示 View ``` PresentationServiceManager.INSTANCE.drawView(screenView); ``` ### U盘更新 ##### U 盘挂载监听 ``` private ExternalMountHelper.OnUDiskMountStateListener listener = new ExternalMountHelper.OnUDiskMountStateListener() { @Override public void mounted(String path) { } @Override public void eject(String path) { } }; UDiskFileSelectorApplication.getExternalMount().addMountStateListener(listener); ``` ##### 获取 U 盘根路径 ```java HashSet mRootPath = UDiskFileSelectorApplication.getExternalMount().getMountRootPaths(); ``` ##### 安装 apk 文件 ``` ESSystem.instance().getSystemManager().installApk(file.getAbsolutePath()); ``` ### U 盘文件 ##### u 盘文件选择 ``` private ISelectorResultCallback mCallback = new ISelectorResultCallback() { @Override public boolean canDismiss() { return true; } @Override public void onExceedCountLimit(int limit) { Toast.makeText(requireContext(), "一次只能选择 " + limit + " 个文件", Toast.LENGTH_SHORT).show(); } @Override public void onNoPreviousLevel() { Toast.makeText(requireContext(), "没有上一级目录了", Toast.LENGTH_SHORT).show(); } @Override public boolean onOpenUsb() { return false; } @Override public void onResult(@NonNull List file) { for (File file1 : file) { if (file1 != null) { Log.i("FileSelectorFragment", "onResult: " + file1.getAbsolutePath()); } } } }; // 标题为选择图片 // 正则文件过滤规则,这里的规则为 "[^\\.].*\\.(jpg|png|jpeg)$" // 可以选的数量 new UDiskFileSelectorFragment.Builder(mCallback).setTitle("选择图片") .setFileRegex(UDiskFileSelectorFragment.REGEX_IMAGE_FILE) .setCount(9) .create() .show(getChildFragmentManager(), ""); ```