From 9b0106b52b3fc6823ab9bf87052e56030939c3b3 Mon Sep 17 00:00:00 2001 From: guanyuankai Date: Fri, 31 Oct 2025 14:05:06 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...†åˆ« Android SDK é›†æˆæŒ‡å— (V1.0) => Readme.md} | 0 README.md | 246 +++++++++++++++++- 2 files changed, 245 insertions(+), 1 deletion(-) rename Distribution/{人脸识别 Android SDK é›†æˆæŒ‡å— (V1.0) => Readme.md} (100%) diff --git a/Distribution/人脸识别 Android SDK é›†æˆæŒ‡å— (V1.0) b/Distribution/Readme.md similarity index 100% rename from Distribution/人脸识别 Android SDK é›†æˆæŒ‡å— (V1.0) rename to Distribution/Readme.md diff --git a/README.md b/README.md index b5a538c..4400513 100644 --- a/README.md +++ b/README.md @@ -1 +1,245 @@ -# FaceSDK_Project \ No newline at end of file +人脸识别 Android SDK é›†æˆæŒ‡å— (V1.0) +本文档为人脸识别 C++ 核心库 (libface_sdk_jni.so) æä¾›äº†è¯¦å°½çš„ Android é›†æˆæ­¥éª¤å’Œ API 使用说明。 + +1. 概述 +本 SDK æä¾›äº†åœ¨ Android 设备上本地è¿è¡Œçš„高性能人脸识别功能。SDK 核心基于 C++ 实现,1:1 转译自 Python 端的 7 模型推ç†ç®¡çº¿ï¼Œç¡®ä¿äº†ç‰¹å¾å‘é‡çš„完全兼容。 + +SDK æä¾›çš„ä¸»è¦ Java API 接å£åŒ…括: + +ç‰¹å¾æå–: extractFeature(Bitmap bitmap) + +ç‰¹å¾æ¯”较: compare(float[] feat1, float[] feat2) + +关键特性 +C++ 核心: 所有计算å‡åœ¨ C++ 层完æˆï¼Œæ€§èƒ½é«˜ï¼Œå†…å­˜å¯æŽ§ã€‚ + +7 模型管线: 完整å¤çŽ°äº† Python 端的 7 æ¨¡åž‹ç®¡çº¿ï¼ˆæ—‹è½¬ã€æ£€æµ‹ã€å§¿æ€ã€å…³é”®ç‚¹ã€å¯¹é½ã€è¯†åˆ«ï¼‰ï¼Œä¿è¯äº†é«˜è¯†åˆ«ç²¾åº¦ã€‚ + +è´¨é‡è¿‡æ»¤: 内置姿æ€è§’(Yaw/Pitch)过滤,自动拒ç»ä½Žè´¨é‡äººè„¸ã€‚ + +手动æ†ç»‘: SDK 手动æ†ç»‘了所有必è¦çš„ä¾èµ–库 (ONNX Runtime, OpenCV, C++ STL),确ä¿äº†åœ¨ä¸åŒè®¾å¤‡ä¸Šçš„一致性,é¿å…了因 Gradle ä¾èµ–版本ä¸åŒ¹é…导致的崩溃。 + +2. SDK 包内容 +分å‘çš„ SDK 包å«ä¸‰ä¸ªéƒ¨åˆ†ï¼š + +1. Java æŽ¥å£ +SDK_Wrapper/ +└── com/ + └── facesdk/ + └── wrapper/ + └── FaceSDKWrapper.java (SDK 公开的 Java API) +2. Native 库 (C++) +SDK_Libs/ +└── arm64-v8a/ + ├── libface_sdk_jni.so (✅ 您的核心 SDK 库) + ├── libonnxruntime.so (ä¾èµ–: ONNX 1.23.2 完整版) + ├── libopencv_java4.so (ä¾èµ–: OpenCV 4.12.0) + └── libc++_shared.so (ä¾èµ–: C++ 标准库) +注æ„: 本 SDK ç›®å‰ä»…æ”¯æŒ arm64-v8a 架构。这覆盖了市é¢ä¸Š 99% 以上的现代 Android 设备。 + +3. AI 模型 +SDK_Models/ +├── faceboxesv2-640x640.onnx +├── face_landmarker_pts5_net1.onnx +├── face_landmarker_pts5_net2.onnx +├── face_recognizer.onnx +├── fsanet-conv.onnx +├── fsanet-var.onnx +└── model_gray_mobilenetv2_rotcls.onnx +3. é›†æˆæŒ‡å— +请按照以下步骤将 SDK 集æˆåˆ°æ‚¨çš„ Android Studio 项目中。 + +步骤 1: å¤åˆ¶ Java æŽ¥å£ +在 Android Studio çš„ "Project" 视图中,导航到 app/src/main/java/。 + +å°† FaceSDKWrapper.java 文件å¤åˆ¶åˆ°æ‚¨é¡¹ç›®çš„ Java æºç ç›®å½•中(例如,com.yourcompany.yourapp.sdk/)。 + +é‡è¦: 打开 FaceSDKWrapper.java 文件,将其顶部的 package com.facesdk.wrapper; 声明修改为您自己的包å,例如 package com.yourcompany.yourapp.sdk;。 + +步骤 2: å¤åˆ¶ Native 库 (.so) +在 Android Studio çš„ "Project" 视图中,导航到 app/src/main/。 + +å³é”®ç‚¹å‡» main -> New -> Directory。 + +创建 jniLibs 文件夹。 + +å³é”®ç‚¹å‡» jniLibs -> New -> Directory。 + +创建 arm64-v8a 文件夹。 + +å°† SDK_Libs/arm64-v8a/ 目录下的所有 4 个 .so 文件å¤åˆ¶åˆ°æ‚¨åˆšåˆ›å»ºçš„ app/src/main/jniLibs/arm64-v8a/ 目录中。 + +步骤 3: å¤åˆ¶ AI 模型 (.onnx) +在 Android Studio çš„ "Project" 视图中,导航到 app/src/main/。 + +å³é”®ç‚¹å‡» main -> New -> Directory。 + +创建 assets 文件夹。 + +å°† SDK_Models/ 目录下的所有 7 个 .onnx 文件å¤åˆ¶åˆ°æ‚¨åˆšåˆ›å»ºçš„ app/src/main/assets/ 目录中。 + +步骤 4: é…ç½® build.gradle.kts (或 build.gradle) +这是最关键的一步。我们需è¦å‘Šè¯‰ Gradle 在打包 App æ—¶åŒ…å«æˆ‘们的手动库。 + +打开您的 app/build.gradle.kts (或 build.gradle) 文件。 + +移除 (或ä¸è¦æ·»åŠ ) onnxruntime å’Œ opencv çš„ implementation ä¾èµ–ã€‚æˆ‘ä»¬å·²ç»æ‰‹åЍæä¾›äº†å®ƒä»¬ã€‚ + +在 android { ... } 代ç å—中,添加 sourceSets å’Œ ndk é…置: + +如果是 build.gradle.kts (Kotlin 脚本): + +Kotlin +``` +android { + // ... (namespace, compileSdk, ç­‰) + + defaultConfig { + // ... (applicationId, minSdk, targetSdk, ç­‰) + } + + // (ä¿æŒè¿™ä¸ª sourceSets å—ä¸å˜ï¼Œå³ä½¿å®ƒçœ‹èµ·æ¥æ˜¯ç©ºçš„) + sourceSets { + getByName("main") { + // 明确告知 Gradle 我们的 jniLibs 目录在哪里 + jniLibs.srcDirs("src/main/jniLibs") + } + } + + // 强制 Gradle åªæ‰“包和使用 arm64-v8a 架构的库 + // è¿™å¯ä»¥é˜²æ­¢åœ¨ x86 模拟器上å‘生库ä¸åŒ¹é…的崩溃 + ndk { + abiFilters.add("arm64-v8a") + } + + // ... (buildTypes, compileOptions, ç­‰) +} +``` +如果是 build.gradle (Groovy 脚本): + +Groovy +``` +android { + // ... (namespace, compileSdk, ç­‰) + + defaultConfig { + // ... (applicationId, minSdk, targetSdk, ç­‰) + } + + sourceSets { + main { + // 明确告知 Gradle 我们的 jniLibs 目录在哪里 + jniLibs.srcDirs = ['src/main/jniLibs'] + } + } + + // 强制 Gradle åªæ‰“包和使用 arm64-v8a 架构的库 + ndk { + abiFilters 'arm64-v8a' + } + + // ... (buildTypes, compileOptions, ç­‰) +} +``` +点击 "Sync Now" åŒæ­¥æ‚¨çš„项目。 + +至此,集æˆå·²å…¨éƒ¨å®Œæˆï¼ + +4. API ä½¿ç”¨æŒ‡å— (Java) +FaceSDKWrapper.java ä¼šè‡ªåŠ¨å¤„ç†æ¨¡åž‹å¤åˆ¶å’Œ C++ 库加载。 + +1. åˆå§‹åŒ– SDK +您必须在åŽå°çº¿ç¨‹ä¸­åˆå§‹åŒ– SDK,因为它包å«è€—时的模型å¤åˆ¶æ“作(仅é™é¦–次å¯åŠ¨ï¼‰ã€‚ + +Java +``` +import com.facesdk.wrapper.FaceSDKWrapper; // ç¡®ä¿å¯¼å…¥æ‚¨ä¿®æ”¹äº†åŒ…å的类 + +public class MyApplication extends Application { + + private FaceSDKWrapper sdkWrapper; + private volatile boolean isSdkInitialized = false; + + @Override + public void onCreate() { + super.onCreate(); + + // 在åŽå°çº¿ç¨‹åˆå§‹åŒ– SDK + new Thread(() -> { + sdkWrapper = new FaceSDKWrapper(); + boolean success = sdkWrapper.init(getApplicationContext()); + if (success) { + isSdkInitialized = true; + Log.i("MyApplication", "人脸识别 SDK åˆå§‹åŒ–æˆåŠŸï¼"); + } else { + Log.e("MyApplication", "人脸识别 SDK åˆå§‹åŒ–失败ï¼"); + } + }).start(); + } + + // æä¾›ä¸€ä¸ªå…¨å±€èŽ·å– SDK 实例的方法 + public FaceSDKWrapper getSdkWrapper() { + return (isSdkInitialized) ? sdkWrapper : null; + } +} +``` +(您也å¯ä»¥ä¸åœ¨ Application 中åˆå§‹åŒ–,而是在 Activity 中,如我们的测试项目所示) + +2. æå–ç‰¹å¾ (必须在åŽå°çº¿ç¨‹) +ç‰¹å¾æå–æ˜¯ä¸€ä¸ªCPU 密集型æ“作(è¿è¡Œ 7 个模型)。严ç¦åœ¨ UI 主线程上调用它,å¦åˆ™ä¼šå¯¼è‡´ App 冻结。 + +Java +``` +// (在您的 Activity 或 ViewModel 中) +// å‡è®¾æ‚¨å·²ä»Ž Application 中获å–了 sdkWrapper 实例 + +public void runExtraction(Bitmap faceBitmap) { + if (sdkWrapper == null) { + Log.e("MyActivity", "SDK 尚未åˆå§‹åŒ–。"); + return; + } + + // 必须在åŽå°çº¿ç¨‹ä¸­è¿è¡Œ + new Thread(() -> { + // 1. 调用 C++ 核心库 + final float[] features = sdkWrapper.extractFeature(faceBitmap); + + // 2. 在 UI 线程上处ç†ç»“æžœ + runOnUiThread(() -> { + if (features != null) { + Log.i("MyActivity", "ç‰¹å¾æå–æˆåŠŸï¼ç»´åº¦: " + features.length); + // TODO: 使用特å¾å‘é‡ (例如,与数æ®åº“比对) + } else { + Log.w("MyActivity", "ç‰¹å¾æå–失败 (æœªæ£€æµ‹åˆ°åˆæ ¼äººè„¸æˆ–出错)"); + // TODO: æç¤ºç”¨æˆ· + } + }); + }).start(); +} +``` +3. æ¯”è¾ƒç‰¹å¾ +这是一个éžå¸¸å¿«é€Ÿçš„æ“ä½œï¼Œå¯ä»¥åœ¨ä»»ä½•线程上调用。 + +Java +``` +float[] featureA = ... // (æ¥è‡ª extractFeature) +float[] featureB = ... // (æ¥è‡ªæ•°æ®åº“) + +float similarity = sdkWrapper.compare(featureA, featureB); + +// 相似度是一个 -1.0 到 1.0 之间的浮点数 (余弦相似度) +Log.i("MyActivity", "人脸相似度: " + similarity); +``` +4. 释放 SDK +在您的主 Activity (或 Application) 退出时,调用 release() æ¥é‡Šæ”¾ C++ å ç”¨çš„内存。 + +Java +``` +// (在您的 MainActivity 中) +@Override +protected void onDestroy() { + super.onDestroy(); + if (sdkWrapper != null) { + sdkWrapper.release(); + } +}``` \ No newline at end of file