Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/shubham0204/OnDevice-Face-Recognition-Android/llms.txt

Use this file to discover all available pages before exploring further.

APIs for interacting with the ObjectBox database to manage persons and their associated face records.

PersonDB

Database access layer for managing person records.
@Single
class PersonDB {
    private val personBox = ObjectBoxStore.store.boxFor(PersonRecord::class.java)
    
    fun addPerson(person: PersonRecord): Long
    fun removePerson(personID: Long)
    fun getCount(): Long
    fun getAll(): Flow<MutableList<PersonRecord>>
}

Methods

addPerson

Add a new person to the database.
person
PersonRecord
required
The person record to add
Returns: Long - The auto-generated person ID
val person = PersonRecord(
    personName = "John Doe",
    numImages = 0,
    addTime = System.currentTimeMillis()
)
val personID = personDB.addPerson(person)

removePerson

Remove a person and all associated face records from the database.
personID
Long
required
The ID of the person to remove
personDB.removePerson(personID = 123)
This operation only removes the PersonRecord. You must also call ImagesVectorDB.removeFaceRecordsWithPersonID() to delete the associated face embeddings.

getCount

Get the total number of persons in the database. Returns: Long - The count of person records
val totalPersons = personDB.getCount()
println("Database contains $totalPersons persons")

getAll

Get a Flow of all person records, automatically updated when the database changes. Returns: Flow<MutableList<PersonRecord>> - Reactive flow of person records
personDB.getAll().collect { persons ->
    persons.forEach { person ->
        println("${person.personName}: ${person.numImages} images")
    }
}
The Flow uses Dispatchers.IO internally, so database queries happen on a background thread.

Usage example

Complete workflow for managing persons:
// Inject PersonDB
@Single
class PersonUseCase(
    private val personDB: PersonDB
) {
    // Add a new person
    fun addPerson(name: String, numImages: Long): Long {
        return personDB.addPerson(
            PersonRecord(
                personName = name,
                numImages = numImages,
                addTime = System.currentTimeMillis()
            )
        )
    }
    
    // Remove a person
    fun removePerson(id: Long) {
        personDB.removePerson(id)
    }
    
    // Get all persons
    fun getAll(): Flow<List<PersonRecord>> = personDB.getAll()
}

PersonUseCase

Use case layer for person management operations, providing a clean API for ViewModels.
@Single
class PersonUseCase(
    private val personDB: PersonDB
) {
    fun addPerson(name: String, numImages: Long): Long
    fun removePerson(id: Long)
    fun getAll(): Flow<List<PersonRecord>>
    fun getCount(): Long
}

Methods

addPerson

Add a new person with the current timestamp.
name
String
required
The person’s name
numImages
Long
required
Initial number of face images (typically 0)
Returns: Long - The auto-generated person ID
val personID = personUseCase.addPerson(
    name = "Alice Johnson",
    numImages = 0
)

removePerson

Remove a person from the database.
id
Long
required
The person ID to remove
personUseCase.removePerson(id = personID)

getAll

Get a reactive Flow of all persons. Returns: Flow<List<PersonRecord>> - Flow emitting updated person lists
val personsFlow = personUseCase.getAll()

getCount

Get the total count of persons. Returns: Long - Number of persons in database
val count = personUseCase.getCount()

ImageVectorUseCase

Use case for face recognition operations, coordinating face detection, embedding generation, and vector search.
@Single
class ImageVectorUseCase(
    private val faceDetector: BaseFaceDetector,
    private val faceSpoofDetector: FaceSpoofDetector,
    private val imagesVectorDB: ImagesVectorDB,
    private val faceNet: FaceNet
) {
    data class FaceRecognitionResult(
        val personName: String,
        val boundingBox: Rect,
        val spoofResult: FaceSpoofDetector.FaceSpoofResult? = null
    )
    
    suspend fun addImage(personID: Long, personName: String, imageUri: Uri): Result<Boolean>
    suspend fun getNearestPersonName(frameBitmap: Bitmap, flatSearch: Boolean): Pair<RecognitionMetrics?, List<FaceRecognitionResult>>
    fun removeAllImagesForPerson(personID: Long)
}

Data classes

FaceRecognitionResult

Recognition result for a detected face.
personName
String
The recognized person’s name, or “NOT RECOGNIZED” if no match found
boundingBox
Rect
Face bounding box coordinates in the frame
spoofResult
FaceSpoofDetector.FaceSpoofResult?
default:"null"
Spoof detection result if enabled, null otherwise

Methods

addImage

Add a face image for enrollment.
personID
Long
required
The person’s database ID
personName
String
required
The person’s name
imageUri
Uri
required
URI of the image to process
Returns: Result<Boolean> - Success/failure with error details
val result = imageVectorUseCase.addImage(
    personID = 123,
    personName = "John Doe",
    imageUri = selectedImageUri
)

result.onSuccess {
    println("Face enrolled successfully")
}.onFailure { error ->
    println("Enrollment failed: ${error.message}")
}
The method performs:
  1. Face detection on the image
  2. FaceNet embedding generation
  3. Storage in vector database with person metadata

getNearestPersonName

Recognize faces in a camera frame.
frameBitmap
Bitmap
required
The camera frame to analyze
Whether to use precise flat search (true) or HNSW approximate search (false)
Returns: Pair<RecognitionMetrics?, List<FaceRecognitionResult>> - Metrics and recognition results for all detected faces
val (metrics, results) = imageVectorUseCase.getNearestPersonName(
    frameBitmap = cameraFrame,
    flatSearch = false
)

results.forEach { result ->
    if (result.personName != "NOT RECOGNIZED") {
        println("Recognized: ${result.personName}")
        println("Bounding box: ${result.boundingBox}")
        
        result.spoofResult?.let { spoof ->
            if (spoof.isSpoof) {
                println("WARNING: Spoof detected!")
            }
        }
    }
}
The pipeline:
  1. Detect all faces in frame
  2. Generate embeddings for each face
  3. Search vector database for matches
  4. Run spoof detection
  5. Return results with metrics
Use flatSearch = false for real-time recognition (faster). Use flatSearch = true when accuracy is critical and you have time for linear search.

removeAllImagesForPerson

Remove all face embeddings for a person.
personID
Long
required
The person ID whose face records should be deleted
imageVectorUseCase.removeAllImagesForPerson(personID = 123)
This only removes FaceImageRecord entries. To fully remove a person, also call PersonUseCase.removePerson().

Complete enrollment workflow

// 1. Create person record
val personID = personUseCase.addPerson(
    name = "Alice",
    numImages = 0
)

// 2. Enroll multiple face images
imageUris.forEach { uri ->
    imageVectorUseCase.addImage(
        personID = personID,
        personName = "Alice",
        imageUri = uri
    ).onFailure { error ->
        println("Failed to enroll image: ${error.message}")
    }
}

// 3. Update person record with image count
val updatedPerson = PersonRecord(
    personID = personID,
    personName = "Alice",
    numImages = imageUris.size.toLong(),
    addTime = System.currentTimeMillis()
)

Complete recognition workflow

// Get camera frame
val bitmap = cameraPreview.getBitmap()

// Perform recognition
val (metrics, results) = imageVectorUseCase.getNearestPersonName(
    frameBitmap = bitmap,
    flatSearch = false
)

// Process results
results.forEach { result ->
    val isRecognized = result.personName != "NOT RECOGNIZED"
    val isReal = result.spoofResult?.isSpoof == false
    
    when {
        !isRecognized -> drawBox(result.boundingBox, Color.RED, "Unknown")
        !isReal -> drawBox(result.boundingBox, Color.YELLOW, "Spoof")
        else -> drawBox(result.boundingBox, Color.GREEN, result.personName)
    }
}

// Display metrics
metrics?.let {
    println("Total pipeline time: ${
        it.timeFaceDetection + 
        it.timeFaceEmbedding + 
        it.timeVectorSearch + 
        it.timeFaceSpoofDetection
    }ms")
}
Source: domain/PersonUseCase.kt, domain/ImageVectorUseCase.kt, data/PersonDB.kt

Build docs developers (and LLMs) love