| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Ready in ~10 minutes (after AAR download): Drop facerecognitionsdk.aar into libfacesdk/ → Run on a phone Jump: Get the AAR · Run the demo · Setup (your own app) · About SDK · Demo kit
Explore FacePlugin Face Recognition SDK — enroll faces, identify in 1:N, capture with a live coach, and read attributes (liveness, quality, pose, age, gender, and more).
This is an on-premise FacePlugin SDK. All processing stays on the device — no biometric data is sent to FacePlugin cloud.
This repository is the Android demo app — a standalone customer repo. Runtime is libfacesdk/facerecognitionsdk.aar (download from Google Drive). No other FacePlugin repository is required.
You get:
| Feature | Supported |
|---|---|
| Gallery enroll (one face) | ✓ |
| Live Identify 1:N (stop on first match) | ✓ |
| Oval Capture coach + enroll | ✓ |
| Gallery Attribute | ✓ |
| 2D liveness, pose, quality, eyes, mask, glasses | ✓ |
| Age, gender, emotion | ✓ |
| 14-point landmarks | ✓ |
| Template extraction + 1:N similarity | ✓ |
| Offline license | ✓ |
| Platform | Repository |
|---|---|
| Android | FaceRecognition-Android |
| iOS | FaceRecognition-iOS-App |
| Windows | FaceRecognition-Windows |
| Linux / Docker | FaceRecognition-Linux-App |
| Step | What you need |
|---|---|
| 1 | Android Studio + a real device (emulator is not recommended) |
| 2 | facerecognitionsdk.aar in ./libfacesdk/ — see Get the AAR |
| 3 | Demo license is already in the repo (LICENSE_KEY for com.faceplugin.facerecognitionsdk). Request a new key only if you change applicationId — see SDK License |
You can run the sample app as-is. Enroll / Identify / Capture / Attribute unlock when the status bar disappears.
facerecognitionsdk.aar includes native libs for arm64-v8a and armeabi-v7a. The sample app filters to those two ABIs.
| Item | Minimum | Recommended |
|---|---|---|
| Android | API 24 (7.0) | API 29 (10) or newer |
| ABI | arm64-v8a, armeabi-v7a | arm64-v8a (typical phones) |
| RAM | 4 GB | 6 GB or more |
| CPU | 4+ cores | Mid-range SoC from ~2019 or newer |
| Camera | Front camera | 720p or 1080p |
| Device | Physical device | Same; emulator is not for camera / liveness |
libfacesdk/facerecognitionsdk.aar is empty on GitHub because the binary is too large.
FaceRecognitionSDK-Android-App runtime (Google Drive)
git clone https://github.com/Faceplugin-ltd/FaceRecognition-Android.git
cd FaceRecognition-AndroidFaceRecognition-Android/
└── libfacesdk/
├── build.gradle
└── facerecognitionsdk.aar
The warning bar on the home screen is the SDK status (Loading native SDK…). Enroll / Identify / Capture / Attribute stay disabled until it disappears.
| Home | Identify | Capture |
|---|---|---|
| Capture result | Attribute | Attribute (emotion) |
|---|---|---|
| Attribute (quality) | Settings | About |
|---|---|---|
| Home (tiles) | Attribute (liveness) |
|---|---|
Licenses are offline and bound to your app identifier.
The sample app already includes a valid key for com.faceplugin.facerecognitionsdk. You only need a new key if you use a different applicationId.
The code below shows how to use the license:
Please contact us to get the license.
You need libfacesdk/ (the AAR) and com.faceplugin.facerecognitionsdk.FaceRecognitionSDK. You do not need this demo’s Activities.
Optional: also copy app/src/main/java/com/faceplugin/facerecognitionsdk/kit/ — that is the fastest way to use every function. See Demo kit.
settings.gradle:
include ':app'
include ':libfacesdk'app/build.gradle:
android {
defaultConfig {
minSdk 24
ndk {
abiFilters 'arm64-v8a', 'armeabi-v7a'
}
}
packaging {
jniLibs {
useLegacyPackaging = true
}
}
}
dependencies {
implementation project(':libfacesdk')
// only if you copy kit/ CameraPreview + CameraFrameUtils:
def camerax = '1.4.2'
implementation "androidx.camera:camera-core:$camerax"
implementation "androidx.camera:camera-camera2:$camerax"
implementation "androidx.camera:camera-lifecycle:$camerax"
implementation "androidx.camera:camera-view:$camerax"
}<uses-feature android:name="android.hardware.camera" android:required="true" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />The license is bound to your applicationId. Request a key for that id, not the demo’s.
Then follow About SDK. Call init and all process methods off the UI thread. First init unpacks the on-device models (a few seconds).
Public class: com.faceplugin.facerecognitionsdk.FaceRecognitionSDK (Java; call it from Kotlin the same way).
All work stays on the device. 0 = SDK_SUCCESS.
| Your product needs | Call this |
|---|---|
| Start the engine once | setActivation → init |
| Find a face on a photo / still | faceDetection |
| Liveness, pose, age, gender, emotion, mask, eyes, glasses, quality | same faceDetection with FaceDetectionParam.allAttributes() |
| Save a person | templateExtraction → store byte[] in your DB |
| 1:1 two photos | two templates → similarityCalculation |
| 1:N a photo against your DB | loop similarityCalculation (or kit bestMatch) |
| Live camera box + 1:N | VideoWorker (start → syncDatabase → addFrame) |
| Live 2D liveness / eyes | extra faceDetection with DETECT_LIVENESS / DETECT_EYES (VideoWorker does not fill these) |
| Active liveness (smile / blink / turn) | VideoWorkerConfig.activeLiveness |
| Stop | stopVideoWorker then deinit when the process ends |
Do not copy MainActivity / CameraActivity unless you want the demo UI. The AAR is the product.
import android.graphics.Bitmap
import com.faceplugin.facerecognitionsdk.FaceBox
import com.faceplugin.facerecognitionsdk.FaceDetectionParam
import com.faceplugin.facerecognitionsdk.FaceRecognitionSDK| Method | What it does |
|---|---|
| getMachineCode(context) | FPMC1.… string (send to FacePlugin if asked) |
| setActivation(context, "FP1.…") | Offline license for your applicationId |
| isActivated() / lastLicenseError() | Check / last license error text |
| init(context) | Unpack models + open engine (once, background) |
| faceDetection(bitmap, param) | Faces as List<FaceBox> |
| detect(bitmap, crop, flags) | Same engine, raw JSON |
| templateExtraction(bitmap, face) | Recognizer template (byte[]) |
| cropFace(bitmap, face) | Thumbnail / enroll crop |
| similarityCalculation(a, b) | 1:1 score (similarity is the same) |
| extractFeature(bitmap) | Template as JSON (crop first yourself) |
| match(image1, image2, crop) | 1:1 two images → JSON |
| quality(bitmap, crop) | Quality JSON (blur / noise / …) |
| yuv2Bitmap(nv21, w, h, mode) | Camera NV21 → upright Bitmap (7 front, 6 back) |
| setLandmarkMode / getLandmarkMode | 14 / 68 / 468 |
| startVideoWorker(config) | Live tracking + 1:N (+ optional active liveness) |
| syncVideoWorkerDatabase(features, threshold) | Push enrolled templates into VideoWorker |
| addVideoWorkerFrame(bitmap) | Feed one live frame (Rgb / Bgra variants exist) |
| setVideoWorkerEventHandler | JSON events: tracking / match |
| stopVideoWorker() | Stop live worker |
| estimatorStatusJSON() | Loaded estimators (debug) |
| deinit() | Close engine |
Thread {
FaceRecognitionSDK.getMachineCode(context) // optional
var ret = FaceRecognitionSDK.setActivation(context, "FP1.…")
if (ret == FaceRecognitionSDK.SDK_SUCCESS) {
ret = FaceRecognitionSDK.init(context)
}
// ret == 0 → enable camera / gallery
}.start()Or copy the kit and call FaceRecognitionClient.get(context).activate(key) { code -> … } (already off the UI thread, skips a second init).
Default FaceDetectionParam() = box + pose + 14 landmarks.
val faces: List<FaceBox> = FaceRecognitionSDK.faceDetection(bitmap, FaceDetectionParam())
if (faces.size != 1) return // 0 = none, 2+ = ask for a single-face photo
val face = faces[0]Everything on one still (liveness, quality, age, gender, emotion, mask, eyes, glasses):
val param = FaceDetectionParam.allAttributes()
param.check_liveness_level = 0 // 0 = High Accuracy, 1 = Light
val faces = FaceRecognitionSDK.faceDetection(bitmap, param)Turn individual checks on FaceDetectionParam:
| Field | Engine flag |
|---|---|
| check_pose | DETECT_POSE |
| check_landmarks | DETECT_LANDMARKS |
| estimate_age_gender | DETECT_AGE + DETECT_GENDER |
| check_emotion | DETECT_EMOTION |
| check_mask / check_face_occlusion | DETECT_MASK |
| check_quality | DETECT_QUALITY + DETECT_FACE_QUALITY |
| check_eye_closeness | DETECT_EYES |
| check_liveness | DETECT_LIVENESS (+ DETECT_LIVENESS_ACCURATE when level is 0) |
| check_glasses | DETECT_GLASSES |
Or JSON: FaceRecognitionSDK.detect(bitmap, false, FaceRecognitionSDK.DETECT_ALL).
After faceDetection, there is no second call — read the box.
| Field | Meaning |
|---|---|
| x1, y1, x2, y2 | Box in image pixels |
| liveness | 2D score (demo threshold 0.7) |
| livenessLabel | "Real" / "Spoof" when present |
| face_quality / qualityLabel | Capture quality |
| face_luminance | Brightness |
| yaw, roll, pitch | Head pose (degrees) |
| age | Estimated age |
| gender | 0 = male, 1 = female |
| genderLabel, emotionLabel, maskLabel | Text when present |
| eyesLeftLabel, eyesRightLabel | Open / Closed |
| left_eye_closed, right_eye_closed | Scores |
| extraAttributes | Extra strings (Glasses, Sunglasses, Lighting, …) |
| landmarks_68, landmarkCount | Landmark xy pairs (image pixels) |
if (face.liveness < 0.7f) {
// spoof — do not identify / enroll
}FaceRecognitionSDK.setLandmarkMode(FaceRecognitionSDK.LANDMARK_MODE_14) // or _68 / _468
val faces = FaceRecognitionSDK.faceDetection(bitmap, FaceDetectionParam())
val n = faces[0].landmarkCount
// xy at landmarks_68[i * 2], landmarks_68[i * 2 + 1]The SDK does not store people. You keep templates (file, Room, backend). The kit’s FaceDatabase is a local JSON file if you want that.
val face = FaceRecognitionSDK.faceDetection(bitmap, FaceDetectionParam()).first()
val template: ByteArray? = FaceRecognitionSDK.templateExtraction(bitmap, face)
val thumbnail: Bitmap? = FaceRecognitionSDK.cropFace(bitmap, face)
// save personId + template (+ thumbnail)val a = FaceRecognitionSDK.templateExtraction(bitmapA, faceA)
val b = FaceRecognitionSDK.templateExtraction(bitmapB, faceB)
val score = FaceRecognitionSDK.similarityCalculation(a, b)
val samePerson = score >= 0.8f // demo identify thresholdTwo-image JSON helper: FaceRecognitionSDK.match(bitmapA, bitmapB, false).
val probe = FaceRecognitionSDK.templateExtraction(bitmap, face) ?: return
var bestName: String? = null
var best = 0.8f
for ((name, enrolled) in yourEnrolledTemplates) {
val score = FaceRecognitionSDK.similarityCalculation(probe, enrolled)
if (score > best) {
best = score
bestName = name
}
}// 7 = front (270°), 6 = back (90°)
val bitmap = FaceRecognitionSDK.yuv2Bitmap(nv21, width, height, if (backCamera) 6 else 7)Then the same faceDetection / templateExtraction / addVideoWorkerFrame as stills. Kit: CameraFrameUtils.fromImageProxy(imageProxy, backCamera) (NV21 + rotate + long side ≤ 640). Close imageProxy in finally before native work.
This is live boxes + 1:N. Feed upright bitmaps (already rotated).
FaceRecognitionSDK.setVideoWorkerEventHandler { json ->
// "event": "tracking" → faces[], match.matched / person_index / score
// "event": "match" → matched, person_index, score
}
val config = FaceRecognitionSDK.VideoWorkerConfig.withMatchThreshold(0.8f)
config.activeLiveness.enabled = false // tracking only; see §11 for challenges
val started = FaceRecognitionSDK.startVideoWorker(config) // 0 = OK
val synced = FaceRecognitionSDK.syncVideoWorkerDatabase(templates, 0.8f)
// each preview frame (do not block CameraX — copy bitmap, queue native add):
FaceRecognitionSDK.addVideoWorkerFrame(frame)
// onPause / onDestroy:
FaceRecognitionSDK.setVideoWorkerEventHandler(null)
FaceRecognitionSDK.stopVideoWorker()person_index is the index in the list you passed to syncVideoWorkerDatabase (if a lookup misses, try index - 1).
2D liveness on live Identify is a still detect next to VideoWorker (that is what the demo does):
val live = FaceDetectionParam()
live.check_liveness = true
live.check_liveness_level = 0
live.check_pose = false
live.check_landmarks = false
val boxes = FaceRecognitionSDK.faceDetection(frameCopy, live)Kit: LiveDetect.livenessOnly(level) and LiveDetect.mergeLiveness(trackBoxes, pbBoxes).
Same VideoWorker for boxes + pose. Eyes: DETECT_EYES still detect (LiveDetect.eyesOnly() in the kit). After a still capture, run allAttributes() off the UI thread for the result panel.
Set on VideoWorkerConfig before startVideoWorker:
val config = FaceRecognitionSDK.VideoWorkerConfig.withMatchThreshold(0.8f)
val al = FaceRecognitionSDK.ActiveLivenessConfig.defaults()
al.enabled = true
al.checks = intArrayOf(
FaceRecognitionSDK.AL_CHECK_SMILE,
FaceRecognitionSDK.AL_CHECK_BLINK,
FaceRecognitionSDK.AL_CHECK_TURN_LEFT,
)
config.activeLiveness = al| Constant | Challenge |
|---|---|
| AL_CHECK_SMILE | Smile |
| AL_CHECK_BLINK | Blink |
| AL_CHECK_TURN_UP / _DOWN / _LEFT / _RIGHT | Turn |
| AL_CHECK_PERSPECTIVE | Move closer / farther |
Tracking events include activeLiveness (verdict, checkType, progress). Kit: client.makeIdentityConfig(...) / IdentityLiveness.instruction(...).
val qualityJson = FaceRecognitionSDK.quality(bitmap, false)
val featureJson = FaceRecognitionSDK.extractFeature(crop) // crop first
val statusJson = FaceRecognitionSDK.estimatorStatusJSON()templateExtraction already crops + parses the feature to byte[].
FaceRecognitionSDK.stopVideoWorker()
FaceRecognitionSDK.deinit()| Code | Constant | Status |
|---|---|---|
| 0 | SDK_SUCCESS | Activate / init OK |
| 1 | SDK_LICENSE_INVALID | Invalid license |
| 2 | SDK_LICENSE_EXPIRED | Expired license |
| 3 | SDK_NOT_ACTIVATED | Not activated |
| 4 | SDK_INIT_FAILED | Init failed |
app/src/main/java/com/faceplugin/facerecognitionsdk/kit/ is not inside the AAR. Copy that folder (Kotlin) if you want the demo’s wiring instead of calling FaceRecognitionSDK yourself.
Use FaceRecognitionClient.get(context) as the only entry. Do not mix raw FaceRecognitionSDK.* on other threads while the client is running.
| File | Use it for |
|---|---|
| FaceRecognitionClient | Activate, detect, enroll, 1:N, VideoWorker |
| FaceRecognitionQueue | Serial native access; live addFrame does not block CameraX |
| FaceDatabase | Local enrolled people (filesDir/face_database.json) |
| CameraFrameUtils | ImageProxy → upright bitmap; gallery downscale to 1280 |
| CameraPreview | CameraX preview + analysis bind (720×1280) |
| LiveDetect | Live 2D liveness / eyes params + merge onto track boxes |
| IdentityLiveness | VideoWorker tracking vs active-liveness configs |
| FaceJson | Parse detect JSON and VideoWorker events |
| FaceModels | EnrolledPerson, VideoWorkerEvent, … |
val client = FaceRecognitionClient.get(this)
client.activate("FP1.…") { code ->
runOnUiThread {
if (code == FaceRecognitionSDK.SDK_SUCCESS) {
client.loadDatabase()
// enable Enroll / Identify / Capture / Attribute
}
}
}client.async {
val prepared = CameraFrameUtils.enginePreparedImage(bitmap)
val faces = client.faceDetection(prepared, FaceDetectionParam.allAttributes())
val face = faces.first()
val template = client.templateExtraction(prepared, face) ?: return@async
val thumb = FaceRecognitionSDK.cropFace(prepared, face)
client.enroll("Person12345", template, thumb)
val hit = client.bestMatch(template, 0.8f) // or enroll then identify another photo
}Gallery enroll in the demo requires exactly one face.
client.setVideoWorkerEventHandler { json ->
val event = FaceJson.parseVideoWorkerEvent(json)
// Tracking → boxes; Match → personIndex + score
}
client.async {
val config = client.makeTrackingConfig(0.8f) // or makeIdentityConfig(...) for challenges
client.startVideoWorker(config)
client.syncDatabase(0.8f)
}
// CameraX analyzer (close ImageProxy first):
val frame = CameraFrameUtils.fromImageProxy(imageProxy, backCamera)
client.addFrame(frame) // non-blocking copy + native add
// live 2D liveness (Identify) or eyes (Capture), also on the SDK thread:
client.async {
client.faceDetection(copy, LiveDetect.livenessOnly(0))
}
// onPause:
client.stopVideoWorker()Bind camera: CameraPreview.bind(this, cameraProvider, previewView, lensFacing, executor, analyzer).
personAtVideoWorkerIndex(index) maps a VideoWorker hit to FaceDatabase.
AAR-only is enough if you already have a camera pipeline and a person DB. Then call FaceRecognitionSDK on one background thread and follow the tables above.
| Back | FazBrowse Home | New Git URL |