Start using packagecloud in minutes

Join thousands of developers using packagecloud to distribute software securely, consistently, and affordably.

README

last updated: Thu 05/16/24 at 07:09:26 PM by lucas-yupistudios

BioPass ID Face Recognition SDK

Latest Version

May 16, 2024 - [v1.0.2]

Table of Contents

Quick Start Guide

First, you will need a license key to use the SDK. To get your license key contact us through our website BioPass ID.

Check out our official documentation for more in depth information on BioPass ID.

1. Prerequisites:

Attention: To use Face Recognition you will need a physical device, Face Recognition does not work on emulators.

- Java 17 or higher
- Kotlin 1.9.0 or highr
- Gradle 8.6 or higher
- Android Gradle Plugin 8.4.0 or higher
- A physical device
- License key
- Internet connection is required to activate the license

Change the minimum Android sdk version to 21 (or higher) in your app/build.gradle file.

minSdkVersion 21

2. Installation

With Gradle

The simplest and easiest way to install the plugin to your project, is to just add the following dependencies to your build.gradle:

dependencies 
    implementation 'com.biopassid:facerecognitionsdk:1.0.2' // latest version

Then on your settings.gradle file:

repositories 
    maven 
        url "https://packagecloud.io/biopassid/FaceMatchingSDK/maven2"


With Local File

Another alternative to use Face Recognition SDK is to download and install the AAR file locally. Here you can find the latest releases and after downloading place the .aar file in any folder of your choice.

We will use Android Studio for the following steps:

  1. First, with your project open, go to File --> Project Structure --> Dependencies.
  2. Then in the Dependencies tab, select your app in the modules tab and click on the plus symbol to show the option to add a JAR/AAR dependency.
  3. On step 1 input the AAR file path, and select the implementation option on step 2.
  4. Just rebuild your project and should be ready to use.

3. How to use

By now you should have all the tools available to start using the plugin in your own project. Here is some code samples that show how to use Face Recognition SDK.

Basic Example

activity_main

In your xml layout of your main activity:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:orientation="horizontal">

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginEnd="20dp"
                android:gravity="center"
                android:orientation="vertical">

                <ImageView
                    android:id="@+id/ivImageA"
                    android:layout_width="100dp"
                    android:layout_height="150dp"
                    android:layout_marginTop="20dp"
                    android:layout_gravity="center" />

                <Button
                    android:id="@+id/btnExtractA"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="20dp"
                    android:text="Extract A" />

            </LinearLayout>

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:orientation="vertical">

                <ImageView
                    android:id="@+id/ivImageB"
                    android:layout_width="100dp"
                    android:layout_height="150dp"
                    android:layout_marginTop="20dp"
                    android:layout_gravity="center" />

                <Button
                    android:id="@+id/btnExtractB"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="20dp"
                    android:text="Extratc B" />

            </LinearLayout>

        </LinearLayout>

        <Button
            android:id="@+id/btnVerify"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="Verify" />

    </LinearLayout>

</LinearLayout>

MainActivity

In your main activity:

package com.example.facerecognitiontest

import android.app.Activity
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import android.widget.Button
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import br.com.biopassid.facerecognitionsdk.FaceRecognition

class MainActivity : AppCompatActivity() 

    private lateinit var ivImageA: ImageView
    private lateinit var ivImageB: ImageView
    private lateinit var btnExtractA: Button
    private lateinit var btnExtractB: Button
    private lateinit var btnVerify: Button
    private var templateA: ByteArray? = null
    private var templateB: ByteArray? = null
    private lateinit var faceRecognition: FaceRecognition
    private val EXTRACT_A = 1
    private val EXTRACT_B = 2

    override fun onDestroy() 
        super.onDestroy()
        faceRecognition.close()


    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        ivImageA = findViewById(R.id.ivImageA)
        ivImageB = findViewById(R.id.ivImageB)
        btnExtractA = findViewById(R.id.btnExtractA)
        btnExtractB = findViewById(R.id.btnExtractB)
        btnVerify = findViewById(R.id.btnVerify)

        faceRecognition = FaceRecognition.getInstance(this, "your-license-key")

        btnExtractA.setOnClickListener  openCamera(EXTRACT_A) 

        btnExtractB.setOnClickListener  openCamera(EXTRACT_B) 

        btnVerify.setOnClickListener 
            if (templateA != null && templateB != null) 
                val verify = faceRecognition.verify(templateA!!, templateB!!)
                Log.d(TAG, "verify: $verify")




    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) 
        super.onActivityResult(requestCode, resultCode, data)
        if (resultCode == Activity.RESULT_OK) 
            if (requestCode == EXTRACT_A) 
                val image = data?.extras?.get("data") as Bitmap
                ivImageA.setImageBitmap(image)
                val extractA = faceRecognition.extract(image)
                Log.d(TAG, "extractA: $extractA")
                templateA = extractA?.template


            if (requestCode == EXTRACT_B) 
                val image = data?.extras?.get("data") as Bitmap
                ivImageB.setImageBitmap(image)
                val bitmapB = (ivImageB.drawable as BitmapDrawable).bitmap
                val extractB = faceRecognition.extract(bitmapB)
                Log.d(TAG, "extractB: $extractB")
                templateB = extractB?.template




    private fun openCamera(requestCode: Int) 
        val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
        startActivityForResult(intent, requestCode)


    companion object 
        private const val TAG = "FaceRecognitionTest"


Example using local DB to save extracts

Extract data class

Create the Extract data class:

package com.example.facerecognitiondbexample

import java.io.Serializable

data class Extract(var id: Int = -1, var image: ByteArray, var template: ByteArray) : Serializable

DBHelper

Create the DBHelper class to access local DB and create the extract table:

package com.example.facerecognitiondbexample

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper

class DBHelper(context: Context) : SQLiteOpenHelper(context, "extract.db", null, 1) 
    override fun onCreate(db: SQLiteDatabase?) 
        val sql = "create table if not exists extract (" +
                "id integer primary key autoincrement, " +
                "image blob, " +
                "template blob)"
        db?.execSQL(sql)


    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) 
        db?.execSQL("drop table extract")
        onCreate(db)


ExtractDAO

Create the ExtractDAO class to handle DB operations:

package com.example.facerecognitiondbexample

import android.annotation.SuppressLint
import android.content.ContentValues
import android.content.Context

class ExtractDAO(context: Context) 
    private val db: DBHelper

    init 
        db = DBHelper(context)


    fun create(extract: Extract) 
        val contentValues = ContentValues()
        contentValues.put("image", extract.image)
        contentValues.put("template", extract.template)
        db.writableDatabase.insert("extract", null, contentValues)


    @SuppressLint("Range")
    fun readAll(): ArrayList<Extract> 
        val extractList = ArrayList<Extract>()
        val columns = arrayOf("id", "image", "template")
        val cursor = db.readableDatabase.query("extract", columns, null, null, null, null, null)
        if (cursor.count > 0) 
            cursor.moveToFirst()
            do 
                val id = cursor.getInt(cursor.getColumnIndex("id"))
                val image = cursor.getBlob(cursor.getColumnIndex("image"))
                val template = cursor.getBlob(cursor.getColumnIndex("template"))
                extractList.add(Extract(id, image, template))
             while (cursor.moveToNext())

        return extractList


    @SuppressLint("Range")
    fun read(id: Int): Extract? 
        val extractList = ArrayList<Extract>()
        val columns = arrayOf("id", "image", "template")
        val cursor = db.readableDatabase.query("extract", columns, null, null, null, null, null)
        if (cursor.count > 0) 
            cursor.moveToFirst()
            do 
                val id = cursor.getInt(cursor.getColumnIndex("id"))
                val image = cursor.getBlob(cursor.getColumnIndex("image"))
                val template = cursor.getBlob(cursor.getColumnIndex("template"))
                extractList.add(Extract(id, image, template))
             while (cursor.moveToNext())

        for (extract in extractList) 
            if (extract.id == id) return extract

        return null


    fun update(extract: Extract) 
        val contentValues = ContentValues()
        val where = "id = ?"
        val wherep = arrayOf(extract.id.toString())
        contentValues.put("image", extract.image)
        contentValues.put("template", extract.template)
        this.db.writableDatabase.update("extract", contentValues, where, wherep)


    fun delete(id: Int) 
        val where = "id = ?"
        val wherep = arrayOf(id.toString())
        this.db.writableDatabase.delete("extract", where, wherep)


    fun count(): Int 
        val columns = arrayOf("id")
        val cursor = this.db.readableDatabase.query("extract", columns, null, null, null, null, null)
        return cursor.count


extract_layout

Create an xml layout to show each item in the extract list:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="100dp"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/ivExtractImage"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_marginEnd="10dp"/>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:id="@+id/tvExtractId"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="ID"
            android:textSize="16sp" />

    </LinearLayout>

</LinearLayout>

ExtractListViewAdapter

Create the ExtractListViewAdapter class to handle the extract ListView:

package com.example.facerecognitiondbexample

import android.content.Context
import android.graphics.BitmapFactory
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.ImageView
import android.widget.TextView

class ExtractListViewAdapter(var context: Context, var extractList: ArrayList<Extract>) : BaseAdapter() 
    override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View 
        val view: View = if (convertView != null) convertView
        else 
            val inflate =
                context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
            inflate.inflate(R.layout.extract_layout, null)


        val ivImage = view.findViewById<ImageView>(R.id.ivExtractImage)
        val tvId = view.findViewById<TextView>(R.id.tvExtractId)

        val extract = extractList[position]

        val bitmap = BitmapFactory.decodeByteArray(extract.image, 0, extract.image.size)

        ivImage.setImageBitmap(bitmap)

        tvId.text = extract.id.toString()

        return view


    override fun getItem(position: Int): Any 
        return extractList[position]


    override fun getItemId(position: Int): Long 
        return position.toLong()


    override fun getCount(): Int 
        return extractList.size


activity_main

In your xml layout of your main activity:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">

        <ListView
            android:id="@+id/lvExtracts"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </FrameLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:orientation="vertical">

        <Button
            android:id="@+id/btnExtract"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Extract" />

        <Button
            android:id="@+id/btnVerify"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Verify" />

        <Button
            android:id="@+id/btnGetAll"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Get all" />

    </LinearLayout>

</LinearLayout>

MainActivity

In your main activity:

package com.example.facerecognitiondbexample

import android.app.Activity
import android.content.Intent
import android.graphics.Bitmap
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.provider.MediaStore
import android.widget.BaseAdapter
import android.widget.Button
import android.widget.ListView
import android.widget.Toast
import br.com.biopassid.facerecognitionsdk.FaceRecognition
import java.io.ByteArrayOutputStream

class MainActivity : AppCompatActivity() 

    private lateinit var lvExtracts: ListView
    private lateinit var btnExtract: Button
    private lateinit var btnVerify: Button
    private lateinit var btnGetAll: Button
    private lateinit var extractDAO: ExtractDAO
    private lateinit var extracts: ArrayList<Extract>
    private lateinit var faceRecognition: FaceRecognition
    private val EXTRACT = 1
    private val VERIFY = 2

    override fun onDestroy() 
        super.onDestroy()
        faceRecognition.close()


    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Sets views
        lvExtracts = findViewById(R.id.lvExtracts)
        btnExtract = findViewById(R.id.btnExtract)
        btnVerify = findViewById(R.id.btnVerify)
        btnGetAll = findViewById(R.id.btnGetAll)

        // Instantiates an ExtractDAO to handle DB operations
        extractDAO = ExtractDAO(this)

        // Updates the extract list
        extracts = extractDAO.readAll()

        // Gets an instance of FaceRecognition
        faceRecognition = FaceRecognition.getInstance(this, "your-license-key")

        // Defines the list view adapter
        lvExtracts.adapter = ExtractListViewAdapter(this, extracts)

        // Sets click listener for buttons
        btnExtract.setOnClickListener  openCamera(EXTRACT) 
        btnVerify.setOnClickListener  openCamera(VERIFY) 
        btnGetAll.setOnClickListener  getAll() 


    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) 
        super.onActivityResult(requestCode, resultCode, data)
        if (resultCode == Activity.RESULT_OK) 
            // Performs extract
            if (requestCode == EXTRACT) 
                val image = data?.extras?.get("data") as Bitmap
                extract(image)


            // Performs verify
            if (requestCode == VERIFY) 
                val image = data?.extras?.get("data") as Bitmap
                verify(image)




    /** Helper method used to capture photos */
    private fun openCamera(requestCode: Int) 
        val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
        startActivityForResult(intent, requestCode)


    /** Helper method used to do an extract, save it to the DB and update the extract list */
    private fun extract(bitmap: Bitmap) 
        // Extracts the template from the image
        val template = faceRecognition.extract(bitmap)?.template

        if (template != null) 
            // Converts bitmap to byte array
            val image = getBitmapAsByteArray(bitmap)

            // Creates a new extract
            val extract = Extract(image = image, template = template)

            // Saves the new extract to the DB
            extractDAO.create(extract)

            // Updates the extract list
            val extractList = extractDAO.readAll()
            extracts.clear()
            extracts.addAll(extractList)
            (lvExtracts.adapter as BaseAdapter).notifyDataSetChanged()



    /** Helper method used to do a 1:N search in the extract list */
    private fun verify(bitmap: Bitmap) 
        // Extracts the template from the image
        val template = faceRecognition.extract(bitmap)?.template

        if (template != null) 
            // Gets all extracts from DB
            val extractList = extractDAO.readAll()

            // Performs a 1:N search in the extract list
            val filteredExtracts = extractList.filter  extract ->
                faceRecognition.verify(
                    template,
                    extract.template
                )?.isGenuine == true


            // Updates the extract list
            if (filteredExtracts.isNotEmpty()) 
                extracts.clear()
                extracts.addAll(filteredExtracts)
                (lvExtracts.adapter as BaseAdapter).notifyDataSetChanged()
             else 
                Toast.makeText(this, "No matching extract found", Toast.LENGTH_SHORT).show()




    /** Helper method used to get all extracts from DB and populate the extract list */
    private fun getAll() 
        // Gets all extracts from DB
        val extractList = extractDAO.readAll()

        // Updates the extract list
        extracts.clear()
        extracts.addAll(extractList)
        (lvExtracts.adapter as BaseAdapter).notifyDataSetChanged()


    /** Helper method used to convert bitmap to byte array */
    private fun getBitmapAsByteArray(bitmap: Bitmap): ByteArray 
        val stream = ByteArrayOutputStream()
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream)
        val byteArray = stream.toByteArray()
        stream.close()
        return byteArray


4. LicenseKey

First, you will need a license key to use the SDK. To get your license key contact us through our website BioPass ID.

To use Face Recognition you need a license key. To set the license key needed is simple as setting another attribute. Simply doing:

val faceRecognition = FaceRecognition.getInstance(this, "your-license-key")

5. Extract

Extract is a funcionality to extract a template from a given biometric image. The operation returns a FaceRecognitionExtractResult object which contains the resulting template as a byte array and a status.

val extract = faceRecognition.extract(byteArray)

// Or:
val extract = faceRecognition.extract(bitmap)

// Or:
val extract = faceRecognition.extract(base64String)

FaceRecognitionExtractResult

| Name     | Type      | Description                            |
| -------- | --------- | -------------------------------------- |
| status   | Int       | The resulting status                   |
| template | ByteArray | The resulting template as a byte array |

6. Verify

Verify is a funcionality to compares two biometric templates. The operation returns a FaceRecognitionVerifyResult object which contains the resulting score and if the templates are correspondent.

val verify = faceRecognition.verify(byteArray, byteArray)

FaceRecognitionVerifyResult

| Name      | Type    | Description                                                                                          |
| --------- | ------- | ---------------------------------------------------------------------------------------------------- |
| isGenuine | Boolean | Indicates whether the informed biometric templates are correspondent or not                          |
| score     | Float   | Indicates the level of similarity between the two given biometrics. Its value may vary from 0 to 100 |

Changelog

v1.0.2

  • Documentation update;
  • Upgrade to Gradle 8.6, see prerequisites section;
  • Upgrade to Android Gradle Plugin 8.4.0, see prerequisites section;
  • Upgrade to Java 17, see prerequisites section;
  • Upgrade to Kotlin 1.9.0, see prerequisites section.

v1.0.1

  • Documentation update;
  • Bug fixes.

v1.0.0

  • Documentation added;
  • Extract added:
    • Operation to extract a template from a given biometric image;
  • Verify added:
    • Operation that compares two biometric templates.
Quick install instructions for: