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 bylucas-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:
- First, with your project open, go to File --> Project Structure --> Dependencies.
- 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.
- On step 1 input the AAR file path, and select the implementation option on step 2.
- 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.