手部异常多分类算法 SDK · 客户对接手册

RK3568 NPU 加速版(v3.0.0) · 加密授权激活 · Android / Java 集成

算法:hand-anomaly-multiclass 硬件:RK3568(arm64-v8a · NPU) 推理:RKNN(INT8) 激活:公网 HTTPS 加密授权 交付:单文件 AAR

一、概述与交付物

本算法用于晨检 / 工牌核验场景下的手部异常检测:检测戒指、指甲油、伤口、创可贴、手镯手链等佩戴物, 并判读手掌 / 手背的放置是否合规。模型为 RK3568 专用 INT8 统一模型,由 RKNN NPU 推理。

项目说明
算法包 IDhand-anomaly-multiclass · v3.0.0(10 类)
运行硬件RK3568 主板(Android,arm64-v8a),NPU 驱动 已内置
输入摄像头一帧 JPEG/PNG 字节(建议 ≤ 1280×720)
输出目标列表,每项 {label, score, bbox[x,y,w,h]}(bbox 为原图像素)

您拿到的文件

文件用途
handanomaly-sdk-rknn-3.0.0.aarSDK 本体(单文件,唯一必须引入的产物)
HandAnomalyClient.java完整 Java 接入示例
本手册对接说明
SDK 已内置激活地址、设备指纹采集、算法密文包、NPU 驱动与平台公钥。 您只需调用两个方法:activate() 与 recognizeImageBytes()。

二、两步接入

1
激活(仅首次):设备联网调一次 sdk.activate("ACT-XXXX-XXXX-XXXX")。成功后授权缓存在本机,之后启动自动复用,断网也能识别。
2
识别(每次):把摄像头一帧传 sdk.recognizeImageBytes(bytes),返回检测目标列表。

三、工程配置(一次性,3 处)

3.1 引入 AAR(app/build.gradle)

android {
    compileSdk 34
    defaultConfig {
        minSdk 24                          // ≥ 23(Android Keystore 要求)
        ndk { abiFilters 'arm64-v8a' }     // RK3568 只需 arm64
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }
}
dependencies {
    // ★ 唯一依赖,无需再声明其它库
    implementation files('libs/handanomaly-sdk-rknn-3.0.0.aar')
}

3.2 权限

<uses-permission android:name="android.permission.INTERNET" />

3.3 混淆

AAR 自带混淆规则,开启 minifyEnabled 无需额外配置。

四、激活(公网,仅首次)

4.1 四种激活方式(任选其一,与我方运营确认即可)

方式调用适用
① 激活码activate("ACT-XXXX-XXXX-XXXX")我方提供 16 位激活码(最常用)
② 云端激活activateByDevice()我方已预登记设备,一键免码激活
③ 申请激活apply(...) → applyStatus(no)提交申请,我方审核后自动激活
④ 快速激活generateQuickCode() → activateByQuickCode("1234")设备出 4 位码报我方,10 分钟内有效

4.2 Java 代码

import com.company.handanomaly.sdk.HandAnomalySdk;

// 无参构造:激活地址 / 指纹 / 密文包 / 公钥已全部内置,只传 Context
HandAnomalySdk sdk = new HandAnomalySdk(context.getApplicationContext());

// 仅首次;之后启动自动复用本机授权
if (!sdk.isActivated()) {
    sdk.activate("ACT-XXXX-XXXX-XXXX");   // ① 激活码
    // sdk.activateByDevice();            // ② 云端激活
}
联网要求:首次激活需设备能访问我方授权服务(HTTPS,地址已内置)。 激活成功后识别不再依赖网络。若贵司需私有化部署(内网 / 专网激活地址),联系我方替换即可。

五、识别(传摄像头画面)

// bytes:摄像头一帧(JPEG/PNG 字节)
List<Map<String,Object>> results = sdk.recognizeImageBytes(bytes);

for (Map<String,Object> r : results) {
    String label = (String) r.get("label");                 // 类别名,如 "wound"
    float  score = ((Number) r.get("score")).floatValue();  // 置信度 0~1
    float[] bbox  = (float[]) r.get("bbox");                // [x, y, 宽, 高](原图像素)
}

// 要 JSON:String json = sdk.recognizeToJson(bytes);

// 与 CameraX 配合:ImageAnalysis 回调里把帧编码为 JPEG 后交给 SDK 即可
// 释放:sdk.release();  (Activity/Application 退出时调用,下次识别自动重建)

六、结果语义(10 类,重要)

模型同时输出整手框与异常框两类目标,请区分处理:

ID代码含义类型
0palm手掌(手心)整手框(放置判定)
1back手背整手框(放置判定)
2ring戒指异常框
3nail_polish指甲油异常框
4long_nail长指甲异常框
5wound伤口异常框
6glove手套异常框
7bandaid创可贴/绷带异常框
8watch手表异常框
9bracelet手镯/手链异常框

推荐判定逻辑

boolean hasHand = false;
List<String> anomalies = new ArrayList<>();
for (Map<String,Object> r : results) {
    String label = (String) r.get("label");
    if ("palm".equals(label) || "back".equals(label)) {
        hasHand = true;                       // 整手框:手已正确放置
    } else {
        anomalies.add(label);                 // 异常框:佩戴物/伤患
    }
}
// 无整手框 → 未检测到手 / 放置不合规;anomalies 非空 → 存在需提示的异常
bbox 已还原到原图像素,可直接画框。score ≥ 0.25 的目标才会返回(阈值内置,无需配置)。

七、授权说明

算法包以密文形式内置在 SDK 中,SDK 内不含任何解密密钥。密钥只在激活成功时由授权平台用本机密钥加密下发:

Android 设备 SDK(零内置密钥) 公网 HTTPS 授权服务 授权平台 License 管理 设备安全芯片 私钥不可导出 ①激活+设备公钥 ②验签 ③加密下发解密密钥 ④本机解密 ⑤内存中运行 算法密文包 内置 SDK(无密钥)

八、错误排查

现象原因 / 处理
SecurityError: 未激活首次使用未调 activate();或授权过期/被吊销。重新激活。
UnsatisfiedLinkError: handrknnAPK 未打入 native 库。确认引入的是本 AAR 且 abiFilters 含 arm64-v8a。
NPU 初始化失败勿自行替换 SDK 内置的 NPU 驱动;确认运行设备为 RK3568。
激活连接失败 / 超时设备无法访问授权服务。检查设备网络、DNS、防火墙出站(HTTPS 443)。
激活码无效激活码已绑定其他设备或已过期。联系我方重新发放。
结果始终为空画面无手或置信度低;或传入非 JPEG/PNG 字节。先用附录示例验证。

九、FAQ

Q:每次运行都要激活吗?
A:不需要。仅首次;之后自动复用本机授权,断网可用。

Q:支持哪些设备?
A:RK3568 主板(Android,arm64)。其它平台(Flutter / Python / 其它芯片)另有交付形态,联系我方。

Q:可以多线程并发识别吗?
A:不建议。请依次调用(可放同一后台线程/队列)。

Q:一帧传多大图?
A:建议 ≤ 1280×720,SDK 内部自动缩放。

附录 · Java 完整示例

完整可编译示例见随包文件 HandAnomalyClient.java,要点如下:

public class HandAnomalyClient {
    private final HandAnomalySdk sdk;
    public HandAnomalyClient(android.content.Context ctx) {
        sdk = new HandAnomalySdk(ctx.getApplicationContext());
    }
    public void ensureActivated(String activationCode) {
        if (!sdk.isActivated()) sdk.activate(activationCode);
    }
    public void inspect(byte[] jpegBytes) {
        List<Map<String,Object>> results = sdk.recognizeImageBytes(jpegBytes);
        boolean hasHand = false;
        List<String> anomalies = new ArrayList<>();
        for (Map<String,Object> r : results) {
            String label = (String) r.get("label");
            if ("palm".equals(label) || "back".equals(label)) hasHand = true;
            else anomalies.add(label);
        }
        // 业务逻辑:hasHand / anomalies
    }
}