FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Faceplugin-ltd/FaceRecognition-Android: Face Recognition, Face Liveness Detection, Face Anti-Spoofing, Face Detection, Face Landmarks, Face Compare, Face Matching, Face Pose, Face Expression, Face Attributes, Face Templates Extraction, Face Landmarks · GitHub

Repository files navigation

🌐 Company Site - Here

🤗 Hugging Face - Here

🛟 Help Center - Here

🐳 Docker Hub - Here

Face Recognition SDK — Android (Fully On-Premise)

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

Introduction

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:

  1. A working demo (Enroll, Identify, Capture, Attribute, Settings, About).
  2. app/.../kit/ — copy-paste Kotlin helpers (FaceRecognitionClient) so you can call every SDK function without rewriting threading, CameraX, or VideoWorker plumbing. See Demo kit.

◾ Main Functionalities

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

◾ Product List

Platform Repository
Android FaceRecognition-Android
iOS FaceRecognition-iOS-App
Windows FaceRecognition-Windows
Linux / Docker FaceRecognition-Linux-App

Before you start

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.

System requirements

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

Get the AAR (libfacesdk)

libfacesdk/facerecognitionsdk.aar is empty on GitHub because the binary is too large.

Where to download

FaceRecognitionSDK-Android-App runtime (Google Drive)

How to place it

  1. Clone this repo (if you have not already):
git clone https://github.com/Faceplugin-ltd/FaceRecognition-Android.git
cd FaceRecognition-Android
  1. Download facerecognitionsdk.aar from the Drive folder.
  2. Put it here (not in a nested folder):
FaceRecognition-Android/
└── libfacesdk/
    ├── build.gradle
    └── facerecognitionsdk.aar

Run the demo

  1. Open this folder in Android Studio.
  2. Run on a device. The demo already has a valid LICENSE_KEY for com.faceplugin.facerecognitionsdk.

The warning bar on the home screen is the SDK status (Loading native SDK…). Enroll / Identify / Capture / Attribute stay disabled until it disappears.

Screenshots

Home Identify Capture

Capture result Attribute Attribute (emotion)

Attribute (quality) Settings About

Home (tiles) Attribute (liveness)

SDK License

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.

How to get a license

The code below shows how to use the license:

/** `FP1.…` from FacePlugin for `applicationId` com.faceplugin.facerecognitionsdk. */
private const val LICENSE_KEY =
"FP1.RlBMMQMAAQDJx5NBpyjuxrTSuz8MAgAASPNMFWCS7q6vchdPDy23dWUgdnJm6T5LgA4HdMSGYv1yOd+oLCfrwRrNPknfqxACqbYHDTxu1SIMVNekHZW0lBnrkLNZvHNprQnTA/8GJ0XBhcT3+kUpasAT9GMzdBT5g7gM+FV8KTT2P71rWtYOIpDszqjhTpXBh0ZkSpRHFVftBlT+W94+4gLQmSg2VF6hMoPMazski4Llav+mfpgnoRDR67tcWhUyuf+wOnOS/v3uyhoE8AqXdpJKqhB4aVEXC/ZtjnQFuJwdANDSWRtzYBYX/Yb5rhzBc0c/p71ZcbP+ye054XUniZokjA/ZrQ+r4tftcAtF69sFiU60km2q6CtRu4tbQpL34YC2ztJPaLywBlwQz0lmEwXbKHmCHOc9SzdaYDWHt7lIgkxaEYztKGDjFzP0coB4R2MzKhh9vcZQePxo8TSwbZqBLb7Sk3BpZ6NYQKbM6iEwEd6VB8of2Meqc4/IJtBP9Yp6Q4P3FoIiZ+m5+Ik/P9O/Cb12zleqNLMU5qTibURBUGB0P/LCo3ueMUhlRBGz4cmbSw/OZifKrfw96axxo1uDyCi2qYIG0mTyXpQX0KW+r/aJ+3CosIukmabvPU3M/PO8Bbnem5P9udecXHsbmfgShAXQ5mDkMIhJQaB3zPwAIl5Agp2T/YRY+11bb5jN3zF7pLGQbgVc3VnDZcwv/hnsLviKADCBhwJCAIO0bZgO621nFz0Yup29vR45IcsQ7MdRHZkMs8LQk2EGwrR6gEn0Peu9Inxc25JXYUBPBN1rjWPyGW1dE4VTWQi6AkFnsguhXcZi1rnPz5et2fWhhzHPMk5wmt2cDrS62JkV0gXYFI4E8O+b2PVFHhkBO92m/kwXy2VsUk0VAQWItd///w=="

client.activate(LICENSE_KEY) { code ->
runOnUiThread {
sdkLoading = false
if (code == FaceRecognitionSDK.SDK_SUCCESS) {
applySdkReady()
} else {
sdkReady = false
textWarning.visibility = View.VISIBLE
textWarning.text = when (code) {
FaceRecognitionSDK.SDK_LICENSE_INVALID -> getString(R.string.sdk_license_invalid)
FaceRecognitionSDK.SDK_LICENSE_EXPIRED -> getString(R.string.sdk_license_expired)
FaceRecognitionSDK.SDK_NOT_ACTIVATED -> getString(R.string.sdk_not_activated)
else -> getString(R.string.sdk_init_failed)
}
setSdkActionsEnabled(false)
}
}
}

Please contact us to get the license.

Setup (your own app)

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.

  1. Copy the libfacesdk folder into your project root.
  2. Put facerecognitionsdk.aar inside it (from Drive).
  3. Wire Gradle:

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"
}
  1. Add permissions in your AndroidManifest.xml:
<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).

About SDK

Public class: com.faceplugin.facerecognitionsdk.FaceRecognitionSDK (Java; call it from Kotlin the same way).

All work stays on the device. 0 = SDK_SUCCESS.

What to call, in order

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.

Rules (read once)

  • Run init and every process call off the UI thread. First init unpacks models.
  • The engine is not concurrent. Serialize calls (one thread, or copy Demo kit which already does this).
  • Call init once per process. Calling it again tears the engine down and you wait for a full re-init.
  • The SDK downscales bitmaps to long side 1280. For live frames, ~640 is enough and faster.
  • Close ImageProxy as soon as you have copied pixels. Do not sync a native detect on the CameraX analysis thread.
import android.graphics.Bitmap
import com.faceplugin.facerecognitionsdk.FaceBox
import com.faceplugin.facerecognitionsdk.FaceDetectionParam
import com.faceplugin.facerecognitionsdk.FaceRecognitionSDK

Full API

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

1. Activate and init

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).

2. Detect a face

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).

3. Read attributes (FaceBox)

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
}

4. Landmarks

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]

5. Enroll (save a person)

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)

6. 1:1 (two photos)

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 threshold

Two-image JSON helper: FaceRecognitionSDK.match(bitmapA, bitmapB, false).

7. 1:N on a still

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
    }
}

8. Camera frame → Bitmap

// 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.

9. Live Identify (VideoWorker)

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).

10. Live Capture (oval / eyes)

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.

11. Active liveness (smile / blink / turn)

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(...).

12. Quality / feature JSON

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[].

13. Unload

FaceRecognitionSDK.stopVideoWorker()
FaceRecognitionSDK.deinit()

SDK codes

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

Demo kit (copy into your app)

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, …

Activate

val client = FaceRecognitionClient.get(this)
client.activate("FP1.…") { code ->
    runOnUiThread {
        if (code == FaceRecognitionSDK.SDK_SUCCESS) {
            client.loadDatabase()
            // enable Enroll / Identify / Capture / Attribute
        }
    }
}

Still: detect, enroll, 1:N, attributes

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.

Live Identify / Capture

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.

When you can skip the kit

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.


List of our Products

Contact

Releases

Packages

Contributors

Languages


Back | FazBrowse Home | New Git URL