├── .gitignore
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── faceplugin
│ │ └── facerecognition
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── faceplugin
│ │ │ └── facerecognition
│ │ │ ├── AboutActivity.kt
│ │ │ ├── AttributeActivity.kt
│ │ │ ├── CameraActivity.java
│ │ │ ├── CameraActivityKt.kt
│ │ │ ├── CaptureActivity.java
│ │ │ ├── CaptureView.java
│ │ │ ├── ContactUsActivity.kt
│ │ │ ├── DBManager.java
│ │ │ ├── FACE_CAPTURE_STATE.java
│ │ │ ├── FaceView.java
│ │ │ ├── IdentifyDetailsActivity.kt
│ │ │ ├── MainActivity.kt
│ │ │ ├── MyGlobal.java
│ │ │ ├── Person.java
│ │ │ ├── PersonAdapter.java
│ │ │ ├── ResultActivity.kt
│ │ │ ├── SettingsActivity.kt
│ │ │ ├── SplashActivity.java
│ │ │ └── Utils.java
│ └── res
│ │ ├── drawable
│ │ ├── attributr.png
│ │ ├── capture.png
│ │ ├── enroll.png
│ │ ├── gradient_back.png
│ │ ├── ic_camera.xml
│ │ ├── ic_delete.xml
│ │ ├── ic_email.xml
│ │ ├── ic_faceplugin.png
│ │ ├── ic_github.png
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_person_search.xml
│ │ ├── ic_register.xml
│ │ ├── ic_reset.xml
│ │ ├── ic_skype.png
│ │ ├── ic_telegram.png
│ │ ├── ic_threshold.xml
│ │ ├── ic_tip.xml
│ │ ├── ic_whatsapp.png
│ │ ├── identify.png
│ │ ├── information.png
│ │ ├── ripple.xml
│ │ ├── rounded_btn_bg.xml
│ │ ├── rounded_edge.xml
│ │ ├── rounded_image.xml
│ │ ├── settings.png
│ │ └── splash.png
│ │ ├── layout
│ │ ├── activity_about_new.xml
│ │ ├── activity_attribute.xml
│ │ ├── activity_camera.xml
│ │ ├── activity_camera_kt.xml
│ │ ├── activity_capture.xml
│ │ ├── activity_contacus.xml
│ │ ├── activity_identify_details.xml
│ │ ├── activity_main.xml
│ │ ├── activity_result_new.xml
│ │ ├── activity_settings.xml
│ │ ├── activity_splash.xml
│ │ └── item_person.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── values-night
│ │ └── themes.xml
│ │ ├── values
│ │ ├── arrays.xml
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ │ └── xml
│ │ ├── backup_rules.xml
│ │ ├── data_extraction_rules.xml
│ │ └── root_preferences.xml
│ └── test
│ └── java
│ └── com
│ └── faceplugin
│ └── facerecognition
│ └── ExampleUnitTest.kt
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── libfacesdk
├── build.gradle
├── build
│ └── .transforms
│ │ └── 13753554662a2f3c3d39dbdbb6d04141
│ │ └── transformed
│ │ └── jetified-facesdk
│ │ └── AndroidManifest.xml
└── facesdk.aar
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 | /.idea/
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |

3 |
4 |
5 | #### Hugging Face - [Here](https://huggingface.co/spaces/FacePlugin-Ltd/FaceRecognition-LivenessDetection-SDK)
6 | #### Documentation- [Here](https://doc.faceplugin.com)
7 |
8 | # Face Recognition SDK Android with 3D Passive Liveness Detection - Fully On Premise
9 | ## Overview
10 | Explore `face recognition SDK` from [Faceplugin](https://faceplugin.com/) Top-ranked on NIST FRVT , coupled with an advanced `iBeta level 2 liveness detection` engine that effectively safeguards against **printed photos, video replay, 3D masks, and deepfake threats**, ensuring top-tier security.
11 |
This is `on-premise face recognition SDK` which means everything is processed in your phone and **NO** data leaves the device.
12 |
13 |
14 | ## Try this APP on Google Play
15 |
16 |
17 |
18 |
19 |
20 |
26 |
27 | ## Screenshots
28 |
34 |
35 | ## On the Youtube
36 |
41 |
42 | ## Install License
43 | The code below shows how to use the license: https://github.com/Faceplugin-ltd/FaceRecognition-Android/blob/370ecadae564788eaa84f288e342da742fde0c1a/app/src/main/java/com/faceplugin/facerecognition/MainActivity.kt#L30-L45
44 |
45 | Please [contact us](#contact) to get the license.
46 |
47 | ## Documentation
48 |
49 |
50 | Setup
51 | Copy the SDK (`libfacesdk` folder) to the `root` folder in your project.
52 |
53 | Add SDK to the project in `settings.gradle`
54 |
55 | ```
56 | rootProject.name = "YourProjectName"
57 | include ':app'
58 | include ':libfacesdk'
59 | ```
60 | Add dependency to your build.gradle
61 |
62 | ```
63 | implementation project(path: ':libfacesdk')
64 | ```
65 |
66 | APIs
67 | Activate SDK using license
68 |
69 | ```java
70 | public static native int setActivation(java.lang.String s);
71 | ```
72 |
73 | Init model for face recognition and liveness detection
74 |
75 | ```java
76 | public static native int init(AssetManager var0);
77 | ```
78 | Convert camera frame in YUV to Bitmap
79 |
80 | ```java
81 | public static native Bitmap yuv2Bitmap(byte[] var0, int var1, int var2, int var3);
82 | ```
83 | Run face recognition and liveness detection
84 |
85 | ```java
86 | public static native List faceDetection(Bitmap var0, FaceDetectionParam var1);
87 | ```
88 | Extract feature vector for the enrollment
89 |
90 | ```java
91 | public static native byte[] templateExtraction(Bitmap var0, FaceBox var1);
92 | ```
93 | Calculate cosine similarity for the matching
94 |
95 | ```java
96 | public static native float similarityCalculation(byte[] var0, byte[] var1);
97 | ```
98 |
99 | SDK Codes
100 |
101 | | Code | Status |
102 | |:------:|------|
103 | |0|Activate SDK successfully|
104 | |-1|Invalid License Key |
105 | |-2|Invalid AppID |
106 | |-3|Expired License Key|
107 | |-4|Activation Failed|
108 | |-5|SDK Failed|
109 |
110 | Classes
111 | FaceResult
112 |
113 | | Type | Name | Description |
114 | |------------------|------------------|------------------|
115 | | Rect | rect | Bounding box for face |
116 | | int | liveness | Liveness status: 0 for spoof, 1 for real, less than 0 for unknown |
117 | | int | gender | Gender classification result |
118 | | int | mask | Mask presence: 0 for no mask, 1 for mask |
119 | | int | age | Age estimation result |
120 | | float | yaw | Yaw angle: -45 to 45 degrees |
121 | | float | roll | Roll angle: -45 to 45 degrees |
122 | | float | pitch | Pitch angle: -45 to 45 degrees |
123 | | byte[] | feature | 2056-byte facial feature data |
124 | | byte[] | faceData | Encrypted facial data |
125 | | int | orient | Face orientation: 1 for no rotation, 2 for 90° rotation, 3 for 270° rotation, 4 for 180° rotation |
126 | | int | faceId | Face ID in the tracking face mode |
127 |
128 | ```java
129 | public class FaceResult {
130 | public Rect rect;
131 | public int liveness;
132 | public int gender;
133 | public int mask;
134 | public int age;
135 | public float yaw;
136 | public float roll;
137 | public float pitch;
138 | public byte[] feature;
139 | public byte[] faceData;
140 | public int orient;
141 | public int faceId;
142 |
143 | public FaceResult() {
144 | }
145 | }
146 | ```
147 |
148 |
149 | Here's our official [document](https://doc.faceplugin.com/)
150 |
151 | ## List of our Products
152 |
153 | * **[Face Recognition with Liveness Detection-Android (Java, Kotlin)](https://github.com/Faceplugin-ltd/FaceRecognition-Android)**
154 | * **[Face Recognition with Liveness Detection-iOS (Objective C, Swift)](https://github.com/Faceplugin-ltd/FaceRecognition-iOS)**
155 | * **[Face Recognition with Liveness Detection-React Native](https://github.com/Faceplugin-ltd/FaceRecognition-React-Native)**
156 | * **[Face Recognition with Liveness Detection-Flutter](https://github.com/Faceplugin-ltd/FaceRecognition-Flutter)**
157 | * **[Face Recognition with Liveness Detection-Ionic Cordova](https://github.com/Faceplugin-ltd/FaceRecognition-Ionic-Cordova)**
158 | * **[Face Recognition with Liveness Detection-.Net MAUI](https://github.com/Faceplugin-ltd/FaceRecognition-.Net)**
159 | * **[Face Recognition with Liveness Detection-.Net WPF](https://github.com/Faceplugin-ltd/FaceRecognition-WPF-.Net)**
160 | * **[Face Recognition with Liveness Detection-Javascript](https://github.com/Faceplugin-ltd/FaceRecognition-LivenessDetection-Javascript)**
161 | * **[Face Recognition with LivenessDetection-React](https://github.com/Faceplugin-ltd/FaceRecognition-LivenessDetection-React)**
162 | * **[Face Recognition with LivenessDetection-Vue](https://github.com/Faceplugin-ltd/FaceRecognition-LivenessDetection-Vue)**
163 | * **[Face Liveness Detection-Android (Java, Kotlin)](https://github.com/Faceplugin-ltd/FaceLivenessDetection-Android)**
164 | * **[Face Liveness Detection-iOS (Objective C, Swift)](https://github.com/Faceplugin-ltd/FaceLivenessDetection-iOS)**
165 | * **[Face Liveness Detection-Linux](https://github.com/Faceplugin-ltd/FaceLivenessDetection-Linux)**
166 | * **[Face Liveness Detection-Docker](https://github.com/Faceplugin-ltd/FaceLivenessDetection-Docker)**
167 | * **[Open Source Face Recognition SDK](https://github.com/Faceplugin-ltd/Open-Source-Face-Recognition-SDK)**
168 | * **[Face Recognition SDK](https://github.com/Faceplugin-ltd/Face-Recognition-SDK)**
169 | * **[Liveness Detection SDK](https://github.com/Faceplugin-ltd/Face-Liveness-Detection-SDK)**
170 | * **[Palm Recognition SDK](https://github.com/Faceplugin-ltd/Palm-Recognition)**
171 | * **[ID Card Recognition](https://github.com/Faceplugin-ltd/ID-Card-Recognition)**
172 | * **[ID Document Liveness Detection](https://github.com/Faceplugin-ltd/ID-Document-Liveness-Detection)**
173 |
174 | ## Contact
175 |
180 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | android {
7 | namespace 'com.faceplugin.facerecognition'
8 | compileSdk 33
9 |
10 | defaultConfig {
11 | applicationId "com.faceplugin.facerecognition"
12 | minSdk 24
13 | targetSdk 33
14 | versionCode 2
15 | versionName "1.1"
16 |
17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
18 |
19 | ndk {
20 | abiFilters 'arm64-v8a', 'armeabi-v7a'
21 | }
22 | }
23 |
24 | buildTypes {
25 | release {
26 | minifyEnabled false
27 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
28 | }
29 | }
30 | compileOptions {
31 | sourceCompatibility JavaVersion.VERSION_1_8
32 | targetCompatibility JavaVersion.VERSION_1_8
33 | }
34 | kotlinOptions {
35 | jvmTarget = '1.8'
36 | }
37 | }
38 |
39 | dependencies {
40 |
41 |
42 | implementation 'androidx.appcompat:appcompat:1.6.1'
43 | implementation 'com.google.android.material:material:1.8.0'
44 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
45 | implementation 'androidx.preference:preference:1.2.0'
46 | implementation 'androidx.preference:preference-ktx:1.2.0'
47 |
48 | implementation "androidx.camera:camera-core:1.0.0-beta12"
49 | implementation "androidx.camera:camera-camera2:1.0.0-beta12"
50 | implementation "androidx.camera:camera-lifecycle:1.0.0-beta12"
51 | implementation 'androidx.camera:camera-view:1.0.0-alpha19'
52 |
53 | implementation project(path: ':libfacesdk')
54 |
55 | implementation 'io.fotoapparat:fotoapparat:2.7.0'
56 |
57 | testImplementation 'junit:junit:4.13.2'
58 | androidTestImplementation 'androidx.test.ext:junit:1.1.5'
59 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
60 | implementation 'com.github.roynx98:transition-button-android:c1bf882dc3'
61 |
62 | implementation 'com.github.ybq:Android-SpinKit:1.4.0'
63 | implementation 'com.google.android.material:material:1.2.0-alpha02'
64 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/faceplugin/facerecognition/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.faceplugin.facerecognition
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.faceplugin.faceattribute", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
18 |
21 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
35 |
40 |
44 |
48 |
52 |
56 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/app/src/main/java/com/faceplugin/facerecognition/AboutActivity.kt:
--------------------------------------------------------------------------------
1 | package com.faceplugin.facerecognition
2 |
3 | import android.content.Intent
4 | import android.content.pm.ResolveInfo
5 | import android.net.Uri
6 | import android.os.Bundle
7 | import android.widget.Button
8 | import android.widget.TextView
9 | import androidx.appcompat.app.AppCompatActivity
10 | import com.google.android.material.bottomsheet.BottomSheetDialog
11 |
12 |
13 | class AboutActivity : AppCompatActivity() {
14 | override fun onCreate(savedInstanceState: Bundle?) {
15 | super.onCreate(savedInstanceState)
16 | setContentView(R.layout.activity_about_new)
17 |
18 | findViewById(R.id.btn_contact).setOnClickListener {
19 | val bottomSheet = ContactUsActivity()
20 | bottomSheet.show(supportFragmentManager, "ContactUsActivity")
21 | }
22 |
23 |
24 | }
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/faceplugin/facerecognition/AttributeActivity.kt:
--------------------------------------------------------------------------------
1 | package com.faceplugin.facerecognition
2 |
3 | import android.graphics.Bitmap
4 | import android.os.Bundle
5 | import android.widget.ImageView
6 | import android.widget.TextView
7 | import androidx.appcompat.app.AppCompatActivity
8 |
9 | class AttributeActivity : AppCompatActivity() {
10 | override fun onCreate(savedInstanceState: Bundle?) {
11 | super.onCreate(savedInstanceState)
12 | setContentView(R.layout.activity_attribute)
13 |
14 | val faceImage = intent.getParcelableExtra("face_image") as? Bitmap
15 | val livenessScore = intent.getFloatExtra("liveness", 0f)
16 | val yaw = intent.getFloatExtra("yaw", 0f)
17 | val roll = intent.getFloatExtra("roll", 0f)
18 | val pitch = intent.getFloatExtra("pitch", 0f)
19 | val face_quality = intent.getFloatExtra("face_quality", 0f)
20 | val face_luminance = intent.getFloatExtra("face_luminance", 0f)
21 | val left_eye_closed = intent.getFloatExtra("left_eye_closed", 0f)
22 | val right_eye_closed = intent.getFloatExtra("right_eye_closed", 0f)
23 | val face_occlusion = intent.getFloatExtra("face_occlusion", 0f)
24 | val mouth_opened = intent.getFloatExtra("mouth_opened", 0f)
25 | val age = intent.getIntExtra("age", 0)
26 | val gender = intent.getIntExtra("gender", 0)
27 |
28 | findViewById(R.id.imageFace).setImageBitmap(faceImage)
29 |
30 | if (livenessScore > SettingsActivity.getLivenessThreshold(this)) {
31 | val msg = String.format("Liveness: Real, score = %.03f", livenessScore)
32 | findViewById(R.id.txtLiveness).text = msg
33 | } else {
34 | val msg = String.format("Liveness: Spoof, score = %.03f", livenessScore)
35 | findViewById(R.id.txtLiveness).text = msg
36 | }
37 |
38 | if (face_quality < 0.5f) {
39 | val msg = String.format("Quality: Low, score = %.03f", face_quality)
40 | findViewById(R.id.txtQuality).text = msg
41 | } else if(face_quality < 0.75f){
42 | val msg = String.format("Quality: Medium, score = %.03f", face_quality)
43 | findViewById(R.id.txtQuality).text = msg
44 | } else {
45 | val msg = String.format("Quality: High, score = %.03f", face_quality)
46 | findViewById(R.id.txtQuality).text = msg
47 | }
48 |
49 | var msg = String.format("Luminance: %.03f", face_luminance)
50 | findViewById(R.id.txtLuminance).text = msg
51 |
52 | msg = String.format("Angles: yaw = %.03f, roll = %.03f, pitch = %.03f", yaw, roll, pitch)
53 | findViewById(R.id.txtAngles).text = msg
54 |
55 | if (face_occlusion > SettingsActivity.getOcclusionThreshold(this)) {
56 | msg = String.format("Face occluded: score = %.03f", face_occlusion)
57 | findViewById(R.id.txtOcclusion).text = msg
58 | } else {
59 | msg = String.format("Face not occluded: score = %.03f", face_occlusion)
60 | findViewById(R.id.txtOcclusion).text = msg
61 | }
62 |
63 | msg = String.format("Left eye closed: %b, %.03f, Right eye closed: %b, %.03f", left_eye_closed > SettingsActivity.getEyecloseThreshold(this),
64 | left_eye_closed, right_eye_closed > SettingsActivity.getEyecloseThreshold(this), right_eye_closed)
65 | findViewById(R.id.txtEyeClosed).text = msg
66 |
67 | msg = String.format("Mouth opened: %b, %.03f", mouth_opened > SettingsActivity.getMouthopenThreshold(this), mouth_opened)
68 | findViewById(R.id.txtMouthOpened).text = msg
69 |
70 | msg = String.format("Age: %d", age)
71 | findViewById(R.id.txtAge).text = msg
72 |
73 | if(gender == 0) {
74 | msg = String.format("Gender: Male")
75 | } else {
76 | msg = String.format("Gender: Female")
77 | }
78 | findViewById(R.id.txtGender).text = msg
79 | }
80 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/faceplugin/facerecognition/CameraActivity.java:
--------------------------------------------------------------------------------
1 | package com.faceplugin.facerecognition;
2 |
3 |
4 | import static androidx.camera.core.ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST;
5 |
6 | import android.Manifest;
7 | import android.annotation.SuppressLint;
8 | import android.content.Context;
9 | import android.content.Intent;
10 | import android.content.pm.PackageManager;
11 | import android.graphics.Bitmap;
12 | import android.media.Image;
13 | import android.os.Bundle;
14 | import android.util.Size;
15 |
16 | import androidx.annotation.NonNull;
17 | import androidx.appcompat.app.AppCompatActivity;
18 | import androidx.camera.core.Camera;
19 | import androidx.camera.core.CameraSelector;
20 | import androidx.camera.core.ImageAnalysis;
21 | import androidx.camera.core.ImageProxy;
22 | import androidx.camera.core.Preview;
23 | import androidx.camera.lifecycle.ProcessCameraProvider;
24 | import androidx.camera.view.PreviewView;
25 | import androidx.core.app.ActivityCompat;
26 | import androidx.core.content.ContextCompat;
27 |
28 | import com.google.common.util.concurrent.ListenableFuture;
29 | import com.ocp.facesdk.FaceBox;
30 | import com.ocp.facesdk.FaceDetectionParam;
31 | import com.ocp.facesdk.FaceSDK;
32 |
33 | import java.nio.ByteBuffer;
34 | import java.util.List;
35 | import java.util.concurrent.ExecutionException;
36 | import java.util.concurrent.ExecutorService;
37 | import java.util.concurrent.Executors;
38 |
39 | public class CameraActivity extends AppCompatActivity {
40 |
41 | static String TAG = CameraActivity.class.getSimpleName();
42 | static int PREVIEW_WIDTH = 720;
43 | static int PREVIEW_HEIGHT = 1280;
44 |
45 | private ExecutorService cameraExecutorService;
46 | private PreviewView viewFinder;
47 | private Preview preview = null;
48 | private ImageAnalysis imageAnalyzer = null;
49 | private Camera camera = null;
50 | private CameraSelector cameraSelector = null;
51 | private ProcessCameraProvider cameraProvider = null;
52 |
53 | private FaceView faceView;
54 |
55 | private Context context;
56 |
57 | private Boolean recognized = false;
58 |
59 | @Override
60 | protected void onCreate(Bundle savedInstanceState) {
61 | super.onCreate(savedInstanceState);
62 | setContentView(R.layout.activity_camera);
63 |
64 | context = this;
65 |
66 | viewFinder = findViewById(R.id.preview);
67 | faceView = findViewById(R.id.faceView);
68 | cameraExecutorService = Executors.newFixedThreadPool(1);
69 |
70 | if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
71 | == PackageManager.PERMISSION_DENIED) {
72 |
73 | ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 1);
74 | } else {
75 | viewFinder.post(() ->
76 | {
77 | setUpCamera();
78 | });
79 | }
80 | }
81 |
82 | @Override
83 | public void onResume() {
84 | super.onResume();
85 |
86 | recognized = false;
87 | }
88 |
89 | @Override
90 | public void onPause() {
91 | super.onPause();
92 |
93 | faceView.setFaceBoxes(null);
94 | }
95 |
96 | @Override
97 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
98 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
99 |
100 | if(requestCode == 1) {
101 | if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
102 | == PackageManager.PERMISSION_GRANTED) {
103 |
104 | viewFinder.post(() ->
105 | {
106 | setUpCamera();
107 | });
108 | }
109 | }
110 | }
111 |
112 | private void setUpCamera()
113 | {
114 | ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(CameraActivity.this);
115 | cameraProviderFuture.addListener(() -> {
116 |
117 | // CameraProvider
118 | try {
119 | cameraProvider = cameraProviderFuture.get();
120 | } catch (ExecutionException e) {
121 | } catch (InterruptedException e) {
122 | }
123 |
124 | // Build and bind the camera use cases
125 | bindCameraUseCases();
126 |
127 | }, ContextCompat.getMainExecutor(CameraActivity.this));
128 | }
129 |
130 | @SuppressLint({"RestrictedApi", "UnsafeExperimentalUsageError"})
131 | private void bindCameraUseCases()
132 | {
133 | int rotation = viewFinder.getDisplay().getRotation();
134 |
135 | cameraSelector = new CameraSelector.Builder().requireLensFacing(SettingsActivity.getCameraLens(this)).build();
136 |
137 | preview = new Preview.Builder()
138 | .setTargetResolution(new Size(PREVIEW_WIDTH, PREVIEW_HEIGHT))
139 | .setTargetRotation(rotation)
140 | .build();
141 |
142 | imageAnalyzer = new ImageAnalysis.Builder()
143 | .setBackpressureStrategy(STRATEGY_KEEP_ONLY_LATEST)
144 | .setTargetResolution(new Size(PREVIEW_WIDTH, PREVIEW_HEIGHT))
145 | // Set initial target rotation, we will have to call this again if rotation changes
146 | // during the lifecycle of this use case
147 | .setTargetRotation(rotation)
148 | .build();
149 |
150 | imageAnalyzer.setAnalyzer(cameraExecutorService, new FaceAnalyzer());
151 |
152 | cameraProvider.unbindAll();
153 |
154 | try {
155 | camera = cameraProvider.bindToLifecycle(
156 | this, cameraSelector, preview, imageAnalyzer);
157 |
158 | preview.setSurfaceProvider(viewFinder.getSurfaceProvider());
159 | } catch (Exception exc) {
160 | }
161 | }
162 |
163 | class FaceAnalyzer implements ImageAnalysis.Analyzer
164 | {
165 | @SuppressLint("UnsafeExperimentalUsageError")
166 | @Override
167 | public void analyze(@NonNull ImageProxy imageProxy)
168 | {
169 | analyzeImage(imageProxy);
170 | }
171 | }
172 |
173 | @SuppressLint("UnsafeExperimentalUsageError")
174 | private void analyzeImage(ImageProxy imageProxy)
175 | {
176 | if(recognized == true) {
177 | imageProxy.close();
178 | return;
179 | }
180 |
181 | try
182 | {
183 | Image image = imageProxy.getImage();
184 |
185 | Image.Plane[] planes = image.getPlanes();
186 | ByteBuffer yBuffer = planes[0].getBuffer();
187 | ByteBuffer uBuffer = planes[1].getBuffer();
188 | ByteBuffer vBuffer = planes[2].getBuffer();
189 |
190 | int ySize = yBuffer.remaining();
191 | int uSize = uBuffer.remaining();
192 | int vSize = vBuffer.remaining();
193 |
194 | byte[] nv21 = new byte[ySize + uSize + vSize];
195 | yBuffer.get(nv21, 0, ySize);
196 | vBuffer.get(nv21, ySize, vSize);
197 | uBuffer.get(nv21, ySize + vSize, uSize);
198 |
199 | int cameraMode = 7;
200 | if(SettingsActivity.getCameraLens(context) == CameraSelector.LENS_FACING_BACK) {
201 | cameraMode = 6;
202 | }
203 | Bitmap bitmap = FaceSDK.yuv2Bitmap(nv21, image.getWidth(), image.getHeight(), cameraMode);
204 |
205 | FaceDetectionParam faceDetectionParam = new FaceDetectionParam();
206 | faceDetectionParam.check_liveness = true;
207 | faceDetectionParam.check_liveness_level = SettingsActivity.getLivenessLevel(this);
208 | List faceBoxes = FaceSDK.faceDetection(bitmap, faceDetectionParam);
209 |
210 | runOnUiThread(new Runnable() {
211 | @Override
212 | public void run() {
213 | faceView.setFrameSize(new Size(bitmap.getWidth(), bitmap.getHeight()));
214 | faceView.setFaceBoxes(faceBoxes);
215 | }
216 | });
217 |
218 | if(faceBoxes.size() > 0) {
219 | FaceBox faceBox = faceBoxes.get(0);
220 | if(faceBox.liveness > SettingsActivity.getLivenessThreshold(context)) {
221 | byte[] templates = FaceSDK.templateExtraction(bitmap, faceBox);
222 |
223 | float maxSimiarlity = 0;
224 | Person maximiarlityPerson = null;
225 | for(Person person : DBManager.personList) {
226 | float similarity = FaceSDK.similarityCalculation(templates, person.templates);
227 | if(similarity > maxSimiarlity) {
228 | maxSimiarlity = similarity;
229 | maximiarlityPerson = person;
230 | }
231 | }
232 |
233 | if(maxSimiarlity > SettingsActivity.getIdentifyThreshold(this)) {
234 | recognized = true;
235 | final Person identifiedPerson = maximiarlityPerson;
236 | final float identifiedSimilarity = maxSimiarlity;
237 |
238 | runOnUiThread(new Runnable() {
239 | @Override
240 | public void run() {
241 | Bitmap faceImage = Utils.cropFace(bitmap, faceBox);
242 |
243 | Intent intent = new Intent(context, ResultActivity.class);
244 | intent.putExtra("identified_face", faceImage);
245 | intent.putExtra("enrolled_face", identifiedPerson.face);
246 | intent.putExtra("identified_name", identifiedPerson.name);
247 | intent.putExtra("similarity", identifiedSimilarity);
248 | intent.putExtra("liveness", faceBox.liveness);
249 | intent.putExtra("yaw", faceBox.yaw);
250 | intent.putExtra("roll", faceBox.roll);
251 | intent.putExtra("pitch", faceBox.pitch);
252 | intent.putExtra("face_quality", faceBox.face_quality);
253 | intent.putExtra("face_luminance", faceBox.face_luminance);
254 |
255 | startActivity(intent);
256 | }
257 | });
258 | }
259 | }
260 | }
261 | }
262 | catch (Exception e)
263 | {
264 | e.printStackTrace();
265 | }
266 | finally
267 | {
268 | imageProxy.close();
269 | }
270 | }
271 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/faceplugin/facerecognition/CameraActivityKt.kt:
--------------------------------------------------------------------------------
1 | package com.faceplugin.facerecognition
2 |
3 | import android.Manifest
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.content.pm.PackageManager
7 | import android.os.Bundle
8 | import android.util.Size
9 | import androidx.appcompat.app.AppCompatActivity
10 | import androidx.camera.core.CameraSelector
11 | import androidx.core.app.ActivityCompat
12 | import androidx.core.content.ContextCompat
13 | import com.ocp.facesdk.FaceDetectionParam
14 | import com.ocp.facesdk.FaceSDK
15 | import io.fotoapparat.Fotoapparat
16 | import io.fotoapparat.parameter.Resolution
17 | import io.fotoapparat.preview.Frame
18 | import io.fotoapparat.preview.FrameProcessor
19 | import io.fotoapparat.selector.front
20 | import io.fotoapparat.view.CameraView
21 |
22 | class CameraActivityKt : AppCompatActivity() {
23 |
24 | val TAG = CameraActivityKt::class.java.simpleName
25 | val PREVIEW_WIDTH = 720
26 | val PREVIEW_HEIGHT = 1280
27 |
28 | private lateinit var cameraView: CameraView
29 | private lateinit var faceView: FaceView
30 | private lateinit var fotoapparat: Fotoapparat
31 | private lateinit var context: Context
32 |
33 | private var recognized = false
34 |
35 | override fun onCreate(savedInstanceState: Bundle?) {
36 | super.onCreate(savedInstanceState)
37 | setContentView(R.layout.activity_camera_kt)
38 |
39 | context = this
40 | cameraView = findViewById(R.id.preview)
41 | faceView = findViewById(R.id.faceView)
42 |
43 | fotoapparat = Fotoapparat.with(this)
44 | .into(cameraView)
45 | .lensPosition(front())
46 | .frameProcessor(FaceFrameProcessor())
47 | .previewResolution { Resolution(PREVIEW_HEIGHT,PREVIEW_WIDTH) }
48 | .build()
49 |
50 | if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
51 | == PackageManager.PERMISSION_DENIED
52 | ) {
53 | ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), 1)
54 | } else {
55 | fotoapparat.start()
56 | }
57 | }
58 |
59 | override fun onResume() {
60 | super.onResume()
61 | recognized = false
62 | if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
63 | == PackageManager.PERMISSION_GRANTED
64 | ) {
65 | fotoapparat.start()
66 | }
67 | }
68 |
69 | override fun onPause() {
70 | super.onPause()
71 | fotoapparat.stop()
72 | faceView.setFaceBoxes(null)
73 | }
74 |
75 | override fun onRequestPermissionsResult(
76 | requestCode: Int,
77 | permissions: Array,
78 | grantResults: IntArray
79 | ) {
80 | super.onRequestPermissionsResult(requestCode, permissions, grantResults)
81 | if (requestCode == 1) {
82 | if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
83 | == PackageManager.PERMISSION_GRANTED
84 | ) {
85 | fotoapparat.start()
86 | }
87 | }
88 | }
89 |
90 | inner class FaceFrameProcessor : FrameProcessor {
91 |
92 | override fun process(frame: Frame) {
93 |
94 | if(recognized == true) {
95 | return
96 | }
97 |
98 | var cameraMode = 7
99 | if (SettingsActivity.getCameraLens(context) == CameraSelector.LENS_FACING_BACK) {
100 | cameraMode = 6
101 | }
102 |
103 | val bitmap = FaceSDK.yuv2Bitmap(frame.image, frame.size.width, frame.size.height, cameraMode)
104 |
105 | val faceDetectionParam = FaceDetectionParam()
106 | faceDetectionParam.check_liveness = true
107 | faceDetectionParam.check_liveness_level = SettingsActivity.getLivenessLevel(context)
108 | val faceBoxes = FaceSDK.faceDetection(bitmap, faceDetectionParam)
109 |
110 | runOnUiThread {
111 | faceView.setFrameSize(Size(bitmap.width, bitmap.height))
112 | faceView.setFaceBoxes(faceBoxes)
113 | }
114 |
115 | if(faceBoxes.size > 0) {
116 | val faceBox = faceBoxes[0]
117 | if (faceBox.liveness > SettingsActivity.getLivenessThreshold(context)) {
118 | val templates = FaceSDK.templateExtraction(bitmap, faceBox)
119 |
120 | var maxSimiarlity = 0f
121 | var maximiarlityPerson: Person? = null
122 | for (person in DBManager.personList) {
123 | val similarity = FaceSDK.similarityCalculation(templates, person.templates)
124 | if (similarity > maxSimiarlity) {
125 | maxSimiarlity = similarity
126 | maximiarlityPerson = person
127 | }
128 | }
129 | if (maxSimiarlity > SettingsActivity.getIdentifyThreshold(context)) {
130 | recognized = true
131 | val identifiedPerson = maximiarlityPerson
132 | val identifiedSimilarity = maxSimiarlity
133 |
134 | runOnUiThread {
135 | val faceImage = Utils.cropFace(bitmap, faceBox)
136 | val intent = Intent(context, ResultActivity::class.java)
137 | intent.putExtra("identified_face", faceImage)
138 | intent.putExtra("enrolled_face", identifiedPerson!!.face)
139 | intent.putExtra("identified_name", identifiedPerson!!.name)
140 | intent.putExtra("similarity", identifiedSimilarity)
141 | intent.putExtra("liveness", faceBox.liveness)
142 | intent.putExtra("yaw", faceBox.yaw)
143 | intent.putExtra("roll", faceBox.roll)
144 | intent.putExtra("pitch", faceBox.pitch)
145 | intent.putExtra("face_quality", faceBox.face_quality)
146 | intent.putExtra("face_luminance", faceBox.face_luminance)
147 | startActivity(intent)
148 | }
149 | }
150 | }
151 | }
152 | }
153 | }
154 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/faceplugin/facerecognition/CaptureActivity.java:
--------------------------------------------------------------------------------
1 | package com.faceplugin.facerecognition;
2 |
3 |
4 | import static androidx.camera.core.ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST;
5 |
6 | import android.Manifest;
7 | import android.annotation.SuppressLint;
8 | import android.content.Context;
9 | import android.content.pm.PackageManager;
10 | import android.graphics.Bitmap;
11 | import android.graphics.RectF;
12 | import android.media.Image;
13 | import android.os.Bundle;
14 | import android.util.Size;
15 | import android.view.View;
16 | import android.widget.TextView;
17 | import android.widget.Toast;
18 |
19 | import androidx.annotation.NonNull;
20 | import androidx.appcompat.app.AppCompatActivity;
21 | import androidx.camera.core.Camera;
22 | import androidx.camera.core.CameraSelector;
23 | import androidx.camera.core.ImageAnalysis;
24 | import androidx.camera.core.ImageProxy;
25 | import androidx.camera.core.Preview;
26 | import androidx.camera.lifecycle.ProcessCameraProvider;
27 | import androidx.camera.view.PreviewView;
28 | import androidx.constraintlayout.widget.ConstraintLayout;
29 | import androidx.core.app.ActivityCompat;
30 | import androidx.core.content.ContextCompat;
31 |
32 | import com.google.common.util.concurrent.ListenableFuture;
33 | import com.ocp.facesdk.FaceBox;
34 | import com.ocp.facesdk.FaceDetectionParam;
35 | import com.ocp.facesdk.FaceSDK;
36 |
37 | import java.nio.ByteBuffer;
38 | import java.util.List;
39 | import java.util.Random;
40 | import java.util.concurrent.ExecutionException;
41 | import java.util.concurrent.ExecutorService;
42 | import java.util.concurrent.Executors;
43 |
44 |
45 |
46 | public class CaptureActivity extends AppCompatActivity implements CaptureView.ViewModeChanged{
47 |
48 | static String TAG = CaptureActivity.class.getSimpleName();
49 | static int PREVIEW_WIDTH = 720;
50 | static int PREVIEW_HEIGHT = 1280;
51 |
52 | private ExecutorService cameraExecutorService;
53 | private PreviewView viewFinder;
54 | private Preview preview = null;
55 | private ImageAnalysis imageAnalyzer = null;
56 | private Camera camera = null;
57 | private CameraSelector cameraSelector = null;
58 | private ProcessCameraProvider cameraProvider = null;
59 |
60 | private CaptureView captureView;
61 |
62 | private TextView warningTxt;
63 |
64 | private TextView livenessTxt;
65 |
66 | private TextView qualityTxt;
67 |
68 | private TextView luminaceTxt;
69 |
70 | private ConstraintLayout lytCaptureResult;
71 |
72 | private Context context;
73 |
74 | private Bitmap capturedBitmap = null;
75 |
76 | private FaceBox capturedFace = null;
77 |
78 | @Override
79 | protected void onCreate(Bundle savedInstanceState) {
80 | super.onCreate(savedInstanceState);
81 | setContentView(R.layout.activity_capture);
82 |
83 | context = this;
84 |
85 | viewFinder = findViewById(R.id.preview);
86 | captureView = findViewById(R.id.captureView);
87 | warningTxt = findViewById(R.id.txtWarning);
88 | livenessTxt = findViewById(R.id.txtLiveness);
89 | qualityTxt = findViewById(R.id.txtQuality);
90 | luminaceTxt = findViewById(R.id.txtLuminance);
91 | lytCaptureResult = findViewById(R.id.lytCaptureResult);
92 | cameraExecutorService = Executors.newFixedThreadPool(1);
93 |
94 | if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
95 | == PackageManager.PERMISSION_DENIED) {
96 |
97 | ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 1);
98 | } else {
99 | viewFinder.post(() ->
100 | {
101 | setUpCamera();
102 | });
103 | }
104 |
105 | captureView.setViewModeInterface(this);
106 | captureView.setViewMode(CaptureView.VIEW_MODE.NO_FACE_PREPARE);
107 |
108 | findViewById(R.id.buttonEnroll).setOnClickListener(new View.OnClickListener() {
109 | @Override
110 | public void onClick(View view) {
111 | Bitmap faceImage = Utils.cropFace(capturedBitmap, capturedFace);
112 | byte[] templates = FaceSDK.templateExtraction(capturedBitmap, capturedFace);
113 |
114 | DBManager dbManager = new DBManager(context);
115 | final int min = 10000;
116 | final int max = 20000;
117 | final int random = new Random().nextInt((max - min) + 1) + min;
118 |
119 | dbManager.insertPerson("Person" + random, faceImage, templates);
120 | Toast.makeText(context, getString(R.string.person_enrolled), Toast.LENGTH_SHORT).show();
121 | finish();
122 | }
123 | });
124 | }
125 |
126 | @Override
127 | public void onResume() {
128 | super.onResume();
129 | }
130 |
131 | @Override
132 | public void onPause() {
133 | super.onPause();
134 |
135 | captureView.setFaceBoxes(null);
136 | }
137 |
138 | @Override
139 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
140 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
141 |
142 | if(requestCode == 1) {
143 | if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
144 | == PackageManager.PERMISSION_GRANTED) {
145 |
146 | viewFinder.post(() ->
147 | {
148 | setUpCamera();
149 | });
150 | }
151 | }
152 | }
153 |
154 | private void setUpCamera()
155 | {
156 | ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(CaptureActivity.this);
157 | cameraProviderFuture.addListener(() -> {
158 |
159 | // CameraProvider
160 | try {
161 | cameraProvider = cameraProviderFuture.get();
162 | } catch (ExecutionException e) {
163 | } catch (InterruptedException e) {
164 | }
165 |
166 | // Build and bind the camera use cases
167 | bindCameraUseCases();
168 |
169 | }, ContextCompat.getMainExecutor(CaptureActivity.this));
170 | }
171 |
172 | @SuppressLint({"RestrictedApi", "UnsafeExperimentalUsageError"})
173 | private void bindCameraUseCases()
174 | {
175 | int rotation = viewFinder.getDisplay().getRotation();
176 |
177 | cameraSelector = new CameraSelector.Builder().requireLensFacing(SettingsActivity.getCameraLens(this)).build();
178 |
179 | preview = new Preview.Builder()
180 | .setTargetResolution(new Size(PREVIEW_WIDTH, PREVIEW_HEIGHT))
181 | .setTargetRotation(rotation)
182 | .build();
183 |
184 | imageAnalyzer = new ImageAnalysis.Builder()
185 | .setBackpressureStrategy(STRATEGY_KEEP_ONLY_LATEST)
186 | .setTargetResolution(new Size(PREVIEW_WIDTH, PREVIEW_HEIGHT))
187 | // Set initial target rotation, we will have to call this again if rotation changes
188 | // during the lifecycle of this use case
189 | .setTargetRotation(rotation)
190 | .build();
191 |
192 | imageAnalyzer.setAnalyzer(cameraExecutorService, new FaceAnalyzer());
193 |
194 | cameraProvider.unbindAll();
195 |
196 | try {
197 | camera = cameraProvider.bindToLifecycle(
198 | this, cameraSelector, preview, imageAnalyzer);
199 |
200 | preview.setSurfaceProvider(viewFinder.getSurfaceProvider());
201 | } catch (Exception exc) {
202 | }
203 | }
204 |
205 | @Override
206 | public void view5_finished() {
207 |
208 | FaceDetectionParam param = new FaceDetectionParam();
209 | param.check_liveness = true;
210 | param.check_liveness_level = SettingsActivity.getLivenessLevel(this);
211 |
212 | List faceBoxes = FaceSDK.faceDetection(capturedBitmap, param);
213 | if(faceBoxes != null && faceBoxes.size() > 0) {
214 | if(faceBoxes.get(0).liveness > SettingsActivity.getLivenessThreshold(context)) {
215 | String msg = String.format("Liveness: Real, score = %.03f", faceBoxes.get(0).liveness);
216 | livenessTxt.setText(msg);
217 | }
218 | else {
219 | String msg = String.format("Liveness: Spoof, score = %.03f", faceBoxes.get(0).liveness);
220 | livenessTxt.setText(msg);
221 | }
222 | }
223 |
224 | if(capturedFace.face_quality < 0.5f) {
225 | String msg = String.format("Quality: Low, score = %.03f", capturedFace.face_quality);
226 | qualityTxt.setText(msg);
227 | } else if(capturedFace.face_quality < 0.75f) {
228 | String msg = String.format("Quality: Medium, score = %.03f", capturedFace.face_quality);
229 | qualityTxt.setText(msg);
230 | } else {
231 | String msg = String.format("Quality: High, score = %.03f", capturedFace.face_quality);
232 | qualityTxt.setText(msg);
233 | }
234 |
235 | String msg = String.format("Luminance: %.03f", capturedFace.face_luminance);
236 | luminaceTxt.setText(msg);
237 |
238 | lytCaptureResult.setVisibility(View.VISIBLE);
239 | }
240 |
241 | class FaceAnalyzer implements ImageAnalysis.Analyzer
242 | {
243 | @SuppressLint("UnsafeExperimentalUsageError")
244 | @Override
245 | public void analyze(@NonNull ImageProxy imageProxy)
246 | {
247 | analyzeImage(imageProxy);
248 | }
249 | }
250 |
251 | @SuppressLint("UnsafeExperimentalUsageError")
252 | private void analyzeImage(ImageProxy imageProxy)
253 | {
254 | if(captureView.viewMode == CaptureView.VIEW_MODE.NO_FACE_PREPARE) {
255 | imageProxy.close();
256 | return;
257 | }
258 |
259 | try
260 | {
261 | Image image = imageProxy.getImage();
262 |
263 | Image.Plane[] planes = image.getPlanes();
264 | ByteBuffer yBuffer = planes[0].getBuffer();
265 | ByteBuffer uBuffer = planes[1].getBuffer();
266 | ByteBuffer vBuffer = planes[2].getBuffer();
267 |
268 | int ySize = yBuffer.remaining();
269 | int uSize = uBuffer.remaining();
270 | int vSize = vBuffer.remaining();
271 |
272 | byte[] nv21 = new byte[ySize + uSize + vSize];
273 | yBuffer.get(nv21, 0, ySize);
274 | vBuffer.get(nv21, ySize, vSize);
275 | uBuffer.get(nv21, ySize + vSize, uSize);
276 |
277 | Bitmap bitmap = FaceSDK.yuv2Bitmap(nv21, image.getWidth(), image.getHeight(), 7);
278 |
279 | FaceDetectionParam param = new FaceDetectionParam();
280 | param.check_face_occlusion = true;
281 | param.check_eye_closeness = true;
282 | param.check_mouth_opened = true;
283 |
284 | List faceBoxes = FaceSDK.faceDetection(bitmap, param);
285 | FACE_CAPTURE_STATE faceCaptureState = checkFace(faceBoxes, this);
286 |
287 | if(captureView.viewMode == CaptureView.VIEW_MODE.REPEAT_NO_FACE_PREPARE) {
288 | if(faceCaptureState.compareTo(FACE_CAPTURE_STATE.NO_FACE) > 0) {
289 | runOnUiThread(new Runnable() {
290 | @Override
291 | public void run() {
292 | captureView.setViewMode(CaptureView.VIEW_MODE.TO_FACE_CIRCLE);
293 | }
294 | });
295 | }
296 | } else if(captureView.viewMode == CaptureView.VIEW_MODE.FACE_CIRCLE) {
297 | runOnUiThread(new Runnable() {
298 | @Override
299 | public void run() {
300 | captureView.setFrameSize(new Size(bitmap.getWidth(), bitmap.getHeight()));
301 | captureView.setFaceBoxes(faceBoxes);
302 |
303 | if(faceCaptureState == FACE_CAPTURE_STATE.NO_FACE) {
304 | warningTxt.setText("");
305 |
306 | captureView.setViewMode(CaptureView.VIEW_MODE.FACE_CIRCLE_TO_NO_FACE);
307 | }
308 | else if(faceCaptureState == FACE_CAPTURE_STATE.MULTIPLE_FACES)
309 | warningTxt.setText("Multiple face detected!");
310 | else if(faceCaptureState == FACE_CAPTURE_STATE.FIT_IN_CIRCLE)
311 | warningTxt.setText("Fit in circle!");
312 | else if(faceCaptureState == FACE_CAPTURE_STATE.MOVE_CLOSER)
313 | warningTxt.setText("Move closer!");
314 | else if(faceCaptureState == FACE_CAPTURE_STATE.NO_FRONT)
315 | warningTxt.setText("Not fronted face!");
316 | else if(faceCaptureState == FACE_CAPTURE_STATE.FACE_OCCLUDED)
317 | warningTxt.setText("Face occluded!");
318 | else if(faceCaptureState == FACE_CAPTURE_STATE.EYE_CLOSED)
319 | warningTxt.setText("Eye closed!");
320 | else if(faceCaptureState == FACE_CAPTURE_STATE.MOUTH_OPENED)
321 | warningTxt.setText("Mouth opened!");
322 | else if(faceCaptureState == FACE_CAPTURE_STATE.SPOOFED_FACE)
323 | warningTxt.setText("Spoof face");
324 | else {
325 | warningTxt.setText("");
326 | captureView.setViewMode(CaptureView.VIEW_MODE.FACE_CAPTURE_PREPARE);
327 |
328 | capturedBitmap = bitmap;
329 | capturedFace = faceBoxes.get(0);
330 | captureView.setCapturedBitmap(capturedBitmap);
331 | }
332 | }
333 | });
334 | } else if(captureView.viewMode == CaptureView.VIEW_MODE.FACE_CAPTURE_PREPARE) {
335 | if(faceCaptureState == FACE_CAPTURE_STATE.CAPTURE_OK) {
336 | if(faceBoxes.get(0).face_quality > capturedFace.face_quality) {
337 | capturedBitmap = bitmap;
338 | capturedFace = faceBoxes.get(0);
339 | captureView.setCapturedBitmap(capturedBitmap);
340 | }
341 | }
342 | } else if(captureView.viewMode == CaptureView.VIEW_MODE.FACE_CAPTURE_DONE) {
343 | runOnUiThread(new Runnable() {
344 | @Override
345 | public void run() {
346 | cameraProvider.unbindAll();
347 | }
348 | });
349 | }
350 | }
351 | catch (Exception e)
352 | {
353 | e.printStackTrace();
354 | }
355 | finally
356 | {
357 | imageProxy.close();
358 | }
359 | }
360 |
361 | public static FACE_CAPTURE_STATE checkFace(List faceBoxes, Context context) {
362 | if(faceBoxes == null || faceBoxes.size() == 0)
363 | return FACE_CAPTURE_STATE.NO_FACE;
364 |
365 | if(faceBoxes.size() > 1) {
366 | return FACE_CAPTURE_STATE.MULTIPLE_FACES;
367 | }
368 |
369 | FaceBox faceBox = faceBoxes.get(0);
370 | float faceLeft = Float.MAX_VALUE;
371 | float faceRight = 0f;
372 | float faceBottom = 0f;
373 | for(int i = 0; i < 68; i ++) {
374 | faceLeft = Math.min(faceLeft, faceBox.landmarks_68[i * 2]);
375 | faceRight = Math.max(faceRight, faceBox.landmarks_68[i * 2]);
376 | faceBottom = Math.max(faceBottom, faceBox.landmarks_68[i * 2 + 1]);
377 | }
378 |
379 | float sizeRate = 0.30f;
380 | float interRate = 0.03f;
381 | Size frameSize = new Size(PREVIEW_WIDTH, PREVIEW_HEIGHT);
382 | RectF roiRect = CaptureView.getROIRect(frameSize);
383 | float centerY = (faceBox.y2 + faceBox.y1) / 2;
384 | float topY = centerY - (faceBox.y2 - faceBox.y1) * 2 / 3;
385 | float interX = Math.max(0f, roiRect.left - faceLeft) + Math.max(0f, faceRight - roiRect.right);
386 | float interY = Math.max(0f, roiRect.top - topY) + Math.max(0f, faceBottom - roiRect.bottom);
387 | if(interX / roiRect.width() > interRate || interY / roiRect.height() > interRate) {
388 | return FACE_CAPTURE_STATE.FIT_IN_CIRCLE;
389 | }
390 |
391 | if(interX / roiRect.width() > interRate || interY / roiRect.height() > interRate) {
392 | return FACE_CAPTURE_STATE.FIT_IN_CIRCLE;
393 | }
394 |
395 | if((faceBox.y2 - faceBox.y1) * (faceBox.x2 - faceBox.x1) < roiRect.width() * roiRect.height() * sizeRate) {
396 | return FACE_CAPTURE_STATE.MOVE_CLOSER;
397 | }
398 |
399 | if(Math.abs(faceBox.yaw) > SettingsActivity.getYawThreshold(context) ||
400 | Math.abs(faceBox.roll) > SettingsActivity.getRollThreshold(context) ||
401 | Math.abs(faceBox.pitch) > SettingsActivity.getPitchThreshold(context)) {
402 | return FACE_CAPTURE_STATE.NO_FRONT;
403 | }
404 |
405 | if(faceBox.face_occlusion > SettingsActivity.getOcclusionThreshold(context)) {
406 | return FACE_CAPTURE_STATE.FACE_OCCLUDED;
407 | }
408 |
409 | if(faceBox.left_eye_closed > SettingsActivity.getEyecloseThreshold(context) ||
410 | faceBox.right_eye_closed > SettingsActivity.getEyecloseThreshold(context)) {
411 | return FACE_CAPTURE_STATE.EYE_CLOSED;
412 | }
413 |
414 | if(faceBox.mouth_opened > SettingsActivity.getMouthopenThreshold(context)) {
415 | return FACE_CAPTURE_STATE.MOUTH_OPENED;
416 | }
417 |
418 | return FACE_CAPTURE_STATE.CAPTURE_OK;
419 | }
420 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/faceplugin/facerecognition/ContactUsActivity.kt:
--------------------------------------------------------------------------------
1 | package com.faceplugin.facerecognition
2 |
3 | import android.content.Intent
4 | import android.content.pm.ResolveInfo
5 | import android.net.Uri
6 | import android.os.Bundle
7 | import android.view.LayoutInflater
8 | import android.view.View
9 | import android.view.ViewGroup
10 | import android.widget.TextView
11 | import androidx.appcompat.app.AppCompatActivity
12 | import com.google.android.material.bottomsheet.BottomSheetDialogFragment
13 |
14 |
15 | class ContactUsActivity : BottomSheetDialogFragment() {
16 |
17 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
18 | val view = inflater.inflate(R.layout.activity_contacus, container, false)
19 |
20 | val mailTextView = view.findViewById(R.id.txtMail)
21 |
22 | mailTextView.setOnClickListener {
23 | val intent = Intent(Intent.ACTION_SEND)
24 | intent.type = "plain/text"
25 | intent.putExtra(Intent.EXTRA_EMAIL, arrayOf("info@faceplugin.com"))
26 | intent.putExtra(Intent.EXTRA_SUBJECT, "License Request")
27 | intent.putExtra(Intent.EXTRA_TEXT, "")
28 | startActivity(Intent.createChooser(intent, ""))
29 | //dismiss()
30 | }
31 |
32 | return view
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/faceplugin/facerecognition/DBManager.java:
--------------------------------------------------------------------------------
1 | package com.faceplugin.facerecognition;
2 |
3 | import android.content.ContentValues;
4 | import android.content.Context;
5 | import android.database.Cursor;
6 | import android.database.sqlite.SQLiteDatabase;
7 | import android.database.sqlite.SQLiteOpenHelper;
8 | import android.graphics.Bitmap;
9 | import android.graphics.BitmapFactory;
10 |
11 | import java.io.ByteArrayOutputStream;
12 | import java.util.ArrayList;
13 |
14 | public class DBManager extends SQLiteOpenHelper {
15 |
16 | public static ArrayList personList = new ArrayList();
17 |
18 | public DBManager(Context context) {
19 | super(context, "mydb" , null, 1);
20 | }
21 |
22 | @Override
23 | public void onCreate(SQLiteDatabase db) {
24 | // TODO Auto-generated method stub
25 | db.execSQL(
26 | "create table person " +
27 | "(name text, face blob, templates blob)"
28 | );
29 | }
30 |
31 | @Override
32 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
33 | // TODO Auto-generated method stub
34 | db.execSQL("DROP TABLE IF EXISTS person");
35 | onCreate(db);
36 | }
37 |
38 | public void insertPerson (String name, Bitmap face, byte[] templates) {
39 |
40 | ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
41 | face.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
42 | byte[] faceJpg = byteArrayOutputStream.toByteArray();
43 |
44 | SQLiteDatabase db = this.getWritableDatabase();
45 | ContentValues contentValues = new ContentValues();
46 | contentValues.put("name", name);
47 | contentValues.put("face", faceJpg);
48 | contentValues.put("templates", templates);
49 | db.insert("person", null, contentValues);
50 |
51 | personList.add(new Person(name, face, templates));
52 | }
53 |
54 | public Integer deletePerson (String name) {
55 | for(int i = 0; i < personList.size(); i ++) {
56 | if(personList.get(i).name == name) {
57 | personList.remove(i);
58 | i --;
59 | }
60 | }
61 |
62 | SQLiteDatabase db = this.getWritableDatabase();
63 | return db.delete("person",
64 | "name = ? ",
65 | new String[] { name });
66 | }
67 |
68 | public Integer clearDB () {
69 | personList.clear();
70 |
71 | SQLiteDatabase db = this.getWritableDatabase();
72 | db.execSQL("delete from person");
73 | return 0;
74 | }
75 |
76 | public void loadPerson() {
77 | personList.clear();
78 |
79 | SQLiteDatabase db = this.getReadableDatabase();
80 | Cursor res = db.rawQuery( "select * from person", null );
81 | res.moveToFirst();
82 |
83 | while(res.isAfterLast() == false){
84 | String name = res.getString(res.getColumnIndex("name"));
85 | byte[] faceJpg = res.getBlob(res.getColumnIndex("face"));
86 | byte[] templates = res.getBlob(res.getColumnIndex("templates"));
87 | Bitmap face = BitmapFactory.decodeByteArray(faceJpg, 0, faceJpg.length);
88 |
89 | Person person = new Person(name, face, templates);
90 | personList.add(person);
91 |
92 | res.moveToNext();
93 | }
94 | }
95 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/faceplugin/facerecognition/FACE_CAPTURE_STATE.java:
--------------------------------------------------------------------------------
1 | package com.faceplugin.facerecognition;
2 |
3 | public enum FACE_CAPTURE_STATE {
4 | NO_FACE, MULTIPLE_FACES, FIT_IN_CIRCLE, MOVE_CLOSER, NO_FRONT, FACE_OCCLUDED, EYE_CLOSED, MOUTH_OPENED, SPOOFED_FACE, CAPTURE_OK
5 | }
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/faceplugin/facerecognition/FaceView.java:
--------------------------------------------------------------------------------
1 | package com.faceplugin.facerecognition;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.graphics.Rect;
8 | import android.util.AttributeSet;
9 | import android.util.Size;
10 | import android.view.View;
11 |
12 | import androidx.annotation.Nullable;
13 |
14 | import com.ocp.facesdk.FaceBox;
15 |
16 | import java.util.List;
17 |
18 | public class FaceView extends View {
19 |
20 | private Context context;
21 | private Paint realPaint;
22 | private Paint spoofPaint;
23 |
24 | private Size frameSize;
25 |
26 | private List faceBoxes;
27 |
28 | public FaceView(Context context) {
29 | this(context, null);
30 |
31 | this.context = context;
32 | init();
33 | }
34 |
35 | public FaceView(Context context, @Nullable AttributeSet attrs) {
36 | super(context, attrs);
37 | this.context = context;
38 |
39 | init();
40 | }
41 |
42 | public void init() {
43 | setLayerType(View.LAYER_TYPE_SOFTWARE, null);
44 |
45 | realPaint = new Paint();
46 | realPaint.setStyle(Paint.Style.STROKE);
47 | realPaint.setStrokeWidth(3);
48 | realPaint.setColor(Color.GREEN);
49 | realPaint.setAntiAlias(true);
50 | realPaint.setTextSize(50);
51 |
52 | spoofPaint = new Paint();
53 | spoofPaint.setStyle(Paint.Style.STROKE);
54 | spoofPaint.setStrokeWidth(3);
55 | spoofPaint.setColor(Color.RED);
56 | spoofPaint.setAntiAlias(true);
57 | spoofPaint.setTextSize(50);
58 | }
59 |
60 | public void setFrameSize(Size frameSize)
61 | {
62 | this.frameSize = frameSize;
63 | }
64 |
65 | public void setFaceBoxes(List faceBoxes)
66 | {
67 | this.faceBoxes = faceBoxes;
68 | invalidate();
69 | }
70 |
71 | @Override
72 | protected void onDraw(Canvas canvas) {
73 | super.onDraw(canvas);
74 |
75 | if (frameSize != null && faceBoxes != null) {
76 | float x_scale = this.frameSize.getWidth() / (float)canvas.getWidth();
77 | float y_scale = this.frameSize.getHeight() / (float)canvas.getHeight();
78 |
79 | for (int i = 0; i < faceBoxes.size(); i++) {
80 | FaceBox faceBox = faceBoxes.get(i);
81 |
82 | if (faceBox.liveness < SettingsActivity.getLivenessThreshold(context))
83 | {
84 | spoofPaint.setStrokeWidth(3);
85 | spoofPaint.setStyle(Paint.Style.FILL_AND_STROKE);
86 | canvas.drawText("SPOOF " + faceBox.liveness, (faceBox.x1 / x_scale) + 10, (faceBox.y1 / y_scale) - 30, spoofPaint);
87 |
88 | spoofPaint.setStrokeWidth(5);
89 | spoofPaint.setStyle(Paint.Style.STROKE);
90 | canvas.drawRect(new Rect((int)(faceBox.x1 / x_scale), (int)(faceBox.y1 / y_scale),
91 | (int)(faceBox.x2 / x_scale), (int)(faceBox.y2 / y_scale)), spoofPaint);
92 | }
93 | else
94 | {
95 | realPaint.setStrokeWidth(3);
96 | realPaint.setStyle(Paint.Style.FILL_AND_STROKE);
97 | canvas.drawText("REAL " + faceBox.liveness, (faceBox.x1 / x_scale) + 10, (faceBox.y1 / y_scale) - 30, realPaint);
98 |
99 | realPaint.setStyle(Paint.Style.STROKE);
100 | realPaint.setStrokeWidth(5);
101 | canvas.drawRect(new Rect((int)(faceBox.x1 / x_scale), (int)(faceBox.y1 / y_scale),
102 | (int)(faceBox.x2 / x_scale), (int)(faceBox.y2 / y_scale)), realPaint);
103 | }
104 | }
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/app/src/main/java/com/faceplugin/facerecognition/IdentifyDetailsActivity.kt:
--------------------------------------------------------------------------------
1 | package com.faceplugin.facerecognition
2 |
3 | import android.content.Intent
4 | import android.content.pm.ResolveInfo
5 | import android.net.Uri
6 | import android.os.Bundle
7 | import android.view.LayoutInflater
8 | import android.view.View
9 | import android.view.ViewGroup
10 | import android.widget.TextView
11 | import androidx.appcompat.app.AppCompatActivity
12 | import com.google.android.material.bottomsheet.BottomSheetDialogFragment
13 |
14 |
15 | class IdentifyDetailsActivity : BottomSheetDialogFragment() {
16 |
17 | override fun onCreateView(
18 | inflater: LayoutInflater,
19 | container: ViewGroup?,
20 | savedInstanceState: Bundle?
21 | ): View? {
22 | val view = inflater.inflate(R.layout.activity_identify_details, container, false)
23 |
24 | val identifiedName = arguments?.getString("identified_name")
25 | val similarity = arguments?.getFloat("similarity", 0f)
26 | val livenessScore = arguments?.getFloat("liveness", 0f)
27 | val yaw = arguments?.getFloat("yaw", 0f)
28 | val roll = arguments?.getFloat("roll", 0f)
29 | val pitch = arguments?.getFloat("pitch", 0f)
30 | val face_quality = arguments?.getFloat("face_quality", 0f)
31 | val face_luminance = arguments?.getFloat("face_luminance", 0f)
32 |
33 | view.findViewById(R.id.textPerson).text = "Identified: " + identifiedName
34 | view.findViewById(R.id.textSimilarity).text = "Similarity: " + similarity
35 | view.findViewById(R.id.textLiveness).text = "Liveness score: " + livenessScore
36 | view.findViewById(R.id.textYaw).text = "Yaw: " + yaw
37 | view.findViewById(R.id.textRoll).text = "Roll: " + roll
38 | view.findViewById(R.id.textPitch).text = "Pitch: " + pitch
39 |
40 | if (face_quality != null) {
41 | if (face_quality < 0.5f) {
42 | val msg = String.format("Quality: Low, score = %.03f", face_quality)
43 | view.findViewById(R.id.txtQuality).text = msg
44 | } else if (face_quality < 0.75f) {
45 | val msg = String.format("Quality: Medium, score = %.03f", face_quality)
46 | view.findViewById(R.id.txtQuality).text = msg
47 | } else {
48 | val msg = String.format("Quality: High, score = %.03f", face_quality)
49 | view.findViewById(R.id.txtQuality).text = msg
50 | }
51 | }
52 |
53 | var msg = String.format("Luminance: %.03f", face_luminance)
54 | view.findViewById(R.id.txtLuminance).text = msg
55 |
56 | return view
57 | }
58 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/faceplugin/facerecognition/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.faceplugin.facerecognition
2 |
3 | import android.content.Intent
4 | import android.graphics.Bitmap
5 | import android.net.Uri
6 | import android.os.Bundle
7 | import android.view.View
8 | import android.widget.*
9 | import androidx.appcompat.app.AppCompatActivity
10 | import com.ocp.facesdk.FaceBox
11 | import com.ocp.facesdk.FaceDetectionParam
12 | import com.ocp.facesdk.FaceSDK
13 | import kotlin.random.Random
14 |
15 | class MainActivity : AppCompatActivity() {
16 |
17 | companion object {
18 | private val SELECT_PHOTO_REQUEST_CODE = 1
19 | private val SELECT_ATTRIBUTE_REQUEST_CODE = 2
20 | }
21 |
22 | private lateinit var dbManager: DBManager
23 | private lateinit var textWarning: TextView
24 | private lateinit var textEnrolledFace: TextView
25 | private lateinit var personAdapter: PersonAdapter
26 |
27 | override fun onCreate(savedInstanceState: Bundle?) {
28 | super.onCreate(savedInstanceState)
29 | setContentView(R.layout.activity_main)
30 |
31 | textWarning = findViewById(R.id.textWarning)
32 | textEnrolledFace = findViewById(R.id.tv_enrolledface)
33 | textEnrolledFace.setVisibility(View.INVISIBLE)
34 |
35 |
36 |
37 | var ret = FaceSDK.setActivation(
38 | "Fqk7LKLbzfSCBor1Oidf0+aPu7OsAJgjxU5m6EQMP3WQ4JZ0Rt44C8T7auT27jjx9iwYmG/8l3TB\n" +
39 | "9MBZuaQKCKMiBvwu+JGfbyrQPrs0vyunAZplg0qUm3MUjz/ko1oJNDzh90jOvsdy8C+SGFWgLULQ\n" +
40 | "rA6K0dipo5B0v8uPXHkGliNVRuxdKg86iaGHpVzE9V+oqecdXqiuJyRloIqC+vWEYObQkJAocnwR\n" +
41 | "M51gg1HHqFYZ0RS9PI5DVzRNHHT4X/ws7e1tc2R0LgU22gd/4SHDYfoV8gHtyi/QdMthKgyzcJrN\n" +
42 | "p0lS+CrpoQuOzWl1toECPoSfcrbmmNP6v67ISA=="
43 | )
44 |
45 | if (ret == FaceSDK.SDK_SUCCESS) {
46 | ret = FaceSDK.init(assets)
47 | }
48 |
49 | if (ret != FaceSDK.SDK_SUCCESS) {
50 | textWarning.setVisibility(View.VISIBLE)
51 | if (ret == FaceSDK.SDK_LICENSE_KEY_ERROR) {
52 | textWarning.setText("Invalid license!")
53 | } else if (ret == FaceSDK.SDK_LICENSE_APPID_ERROR) {
54 | textWarning.setText("Invalid error!")
55 | } else if (ret == FaceSDK.SDK_LICENSE_EXPIRED) {
56 | textWarning.setText("License expired!")
57 | } else if (ret == FaceSDK.SDK_NO_ACTIVATED) {
58 | textWarning.setText("No activated!")
59 | } else if (ret == FaceSDK.SDK_INIT_ERROR) {
60 | textWarning.setText("Init error!")
61 | }
62 | }
63 |
64 | dbManager = DBManager(this)
65 | dbManager.loadPerson()
66 |
67 | personAdapter = PersonAdapter(this, DBManager.personList, this.textEnrolledFace)
68 | val listView: ListView = findViewById(R.id.listPerson) as ListView
69 | listView.setAdapter(personAdapter)
70 |
71 | findViewById(R.id.ll_enroll).setOnClickListener {
72 | val intent = Intent()
73 | intent.setType("image/*")
74 | intent.setAction(Intent.ACTION_PICK)
75 | startActivityForResult(Intent.createChooser(intent, getString(R.string.select_picture)), SELECT_PHOTO_REQUEST_CODE)
76 | }
77 |
78 | findViewById(R.id.ll_identify).setOnClickListener {
79 | startActivity(Intent(this, CameraActivity::class.java))
80 | }
81 |
82 | findViewById(R.id.ll_capture).setOnClickListener {
83 | startActivity(Intent(this, CaptureActivity::class.java))
84 | }
85 |
86 | findViewById(R.id.ll_attribute).setOnClickListener {
87 | val intent = Intent()
88 | intent.setType("image/*")
89 | intent.setAction(Intent.ACTION_PICK)
90 | startActivityForResult(Intent.createChooser(intent, getString(R.string.select_picture)), SELECT_ATTRIBUTE_REQUEST_CODE)
91 | }
92 |
93 | findViewById(R.id.ll_settings).setOnClickListener {
94 | startActivity(Intent(this, SettingsActivity::class.java))
95 | }
96 | findViewById(R.id.ll_about).setOnClickListener {
97 | startActivity(Intent(this, AboutActivity::class.java))
98 | }
99 |
100 | findViewById(R.id.lytBrand).setOnClickListener {
101 | val browse = Intent(Intent.ACTION_VIEW, Uri.parse("https://faceplugin.com"))
102 | startActivity(browse)
103 | }
104 | }
105 |
106 |
107 | override fun onResume() {
108 | super.onResume()
109 |
110 | personAdapter.notifyDataSetChanged()
111 | if (personAdapter.count == 0){
112 | textEnrolledFace.setVisibility(View.INVISIBLE)
113 | } else {
114 | textEnrolledFace.setVisibility(View.VISIBLE)
115 | }
116 | }
117 |
118 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
119 | if (requestCode == SELECT_PHOTO_REQUEST_CODE && resultCode == RESULT_OK) {
120 | try {
121 | var bitmap: Bitmap = Utils.getCorrectlyOrientedImage(this, data?.data!!)
122 | var faceBoxes: List? = FaceSDK.faceDetection(bitmap, null)
123 |
124 | if(faceBoxes.isNullOrEmpty()) {
125 | Toast.makeText(this, getString(R.string.no_face_detected), Toast.LENGTH_SHORT).show()
126 | } else if (faceBoxes.size > 1) {
127 | Toast.makeText(this, getString(R.string.multiple_face_detected), Toast.LENGTH_SHORT).show()
128 | } else {
129 | val faceImage = Utils.cropFace(bitmap, faceBoxes[0])
130 | val templates = FaceSDK.templateExtraction(bitmap, faceBoxes[0])
131 |
132 | dbManager.insertPerson("Person" + Random.nextInt(10000, 20000), faceImage, templates)
133 | personAdapter.notifyDataSetChanged()
134 | if (personAdapter.count == 0){
135 | textEnrolledFace.setVisibility(View.INVISIBLE)
136 | } else {
137 | textEnrolledFace.setVisibility(View.VISIBLE)
138 | }
139 | Toast.makeText(this, getString(R.string.person_enrolled), Toast.LENGTH_SHORT).show()
140 | }
141 | } catch (e: java.lang.Exception) {
142 | //handle exception
143 | e.printStackTrace()
144 | }
145 | } else if (requestCode == SELECT_ATTRIBUTE_REQUEST_CODE && resultCode == RESULT_OK) {
146 | try {
147 | var bitmap: Bitmap = Utils.getCorrectlyOrientedImage(this, data?.data!!)
148 |
149 |
150 | val param = FaceDetectionParam()
151 | param.check_liveness = true
152 | param.check_liveness_level = SettingsActivity.getLivenessLevel(this)
153 | param.check_eye_closeness = true
154 | param.check_face_occlusion = true
155 | param.check_mouth_opened = true
156 | param.estimate_age_gender = true
157 | var faceBoxes: List? = FaceSDK.faceDetection(bitmap, param)
158 |
159 | if(faceBoxes.isNullOrEmpty()) {
160 | Toast.makeText(this, getString(R.string.no_face_detected), Toast.LENGTH_SHORT).show()
161 | } else if (faceBoxes.size > 1) {
162 | Toast.makeText(this, getString(R.string.multiple_face_detected), Toast.LENGTH_SHORT).show()
163 | } else {
164 | val faceImage = Utils.cropFace(bitmap, faceBoxes[0])
165 |
166 | val intent = Intent(this, AttributeActivity::class.java)
167 | intent.putExtra("face_image", faceImage)
168 | intent.putExtra("yaw", faceBoxes[0].yaw)
169 | intent.putExtra("roll", faceBoxes[0].roll)
170 | intent.putExtra("pitch", faceBoxes[0].pitch)
171 | intent.putExtra("face_quality", faceBoxes[0].face_quality)
172 | intent.putExtra("face_luminance", faceBoxes[0].face_luminance)
173 | intent.putExtra("liveness", faceBoxes[0].liveness)
174 | intent.putExtra("left_eye_closed", faceBoxes[0].left_eye_closed)
175 | intent.putExtra("right_eye_closed", faceBoxes[0].right_eye_closed)
176 | intent.putExtra("face_occlusion", faceBoxes[0].face_occlusion)
177 | intent.putExtra("mouth_opened", faceBoxes[0].mouth_opened)
178 | intent.putExtra("age", faceBoxes[0].age)
179 | intent.putExtra("gender", faceBoxes[0].gender)
180 |
181 | startActivity(intent)
182 | }
183 | } catch (e: java.lang.Exception) {
184 | //handle exception
185 | e.printStackTrace()
186 | }
187 | }
188 | }
189 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/faceplugin/facerecognition/MyGlobal.java:
--------------------------------------------------------------------------------
1 | package com.faceplugin.facerecognition;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapFactory;
6 | import android.graphics.Canvas;
7 | import android.graphics.Color;
8 | import android.graphics.ImageFormat;
9 | import android.graphics.Matrix;
10 | import android.graphics.Paint;
11 | import android.graphics.Rect;
12 | import android.graphics.RectF;
13 | import android.graphics.YuvImage;
14 | import android.media.Image;
15 | import android.net.Uri;
16 | import android.os.ParcelFileDescriptor;
17 |
18 | import java.io.ByteArrayOutputStream;
19 | import java.io.FileDescriptor;
20 | import java.io.IOException;
21 | import java.nio.ByteBuffer;
22 | import java.nio.ReadOnlyBufferException;
23 |
24 | public class MyGlobal {
25 |
26 |
27 | public static String adminEmail="admin@recotech.com";
28 | public static String adminPwd="12345678";
29 |
30 |
31 | public static boolean lockStatus=false;
32 | public static boolean cameraStatus=false;
33 | public static int nLockedCount=-1;
34 | public static Image imgBefore=null;
35 |
36 | public static Bitmap bitmapBefore=null;
37 |
38 |
39 | public static long lock_delay_time=5000;
40 | public static long splash_delay_time=3000;
41 | public static int curStatus=-1;
42 | public static int UNKNOWN=-1;
43 | public static int ADD_NEW=0;
44 | public static int CLOCK_IN=1;
45 | public static int CLOCK_OUT=2;
46 | public static int BREAK_IN=3;
47 | public static int BREAK_OUT=4;
48 |
49 |
50 | //--------------
51 | public static Context context=null;
52 |
53 | public static MainActivity mainActivity=null;
54 |
55 | public static int OUTPUT_SIZE=192; //Output size of model
56 | public static int inputSize=112;
57 | public static float IMAGE_MEAN = 128.0f;
58 | public static float IMAGE_STD = 128.0f;
59 | public static float[][] embedings;
60 |
61 | public static Bitmap getBitmapFromUri(Uri uri) throws IOException {
62 | ParcelFileDescriptor parcelFileDescriptor =
63 | context.getContentResolver().openFileDescriptor(uri, "r");
64 | FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
65 | Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
66 | parcelFileDescriptor.close();
67 | return image;
68 | }
69 |
70 | //IMPORTANT. If conversion not done ,the toBitmap conversion does not work on some devices.
71 | public static byte[] YUV_420_888toNV21(Image image) {
72 |
73 | int width = image.getWidth();
74 | int height = image.getHeight();
75 | int ySize = width*height;
76 | int uvSize = width*height/4;
77 |
78 | byte[] nv21 = new byte[ySize + uvSize*2];
79 |
80 | ByteBuffer yBuffer = image.getPlanes()[0].getBuffer(); // Y
81 | ByteBuffer uBuffer = image.getPlanes()[1].getBuffer(); // U
82 | ByteBuffer vBuffer = image.getPlanes()[2].getBuffer(); // V
83 |
84 | int rowStride = image.getPlanes()[0].getRowStride();
85 | assert(image.getPlanes()[0].getPixelStride() == 1);
86 |
87 | int pos = 0;
88 |
89 | if (rowStride == width) { // likely
90 | yBuffer.get(nv21, 0, ySize);
91 | pos += ySize;
92 | }
93 | else {
94 | long yBufferPos = -rowStride; // not an actual position
95 | for (; pos {
14 |
15 | DBManager dbManager;
16 | TextView txtEnrolledFace;
17 | public PersonAdapter(Context context, ArrayList personList, TextView textEnrolledFace) {
18 | super(context, 0, personList);
19 |
20 | dbManager = new DBManager(context);
21 | txtEnrolledFace = textEnrolledFace;
22 | }
23 |
24 | @Override
25 | public View getView(int position, View convertView, ViewGroup parent) {
26 |
27 | Person person = getItem(position);
28 | if (convertView == null) {
29 | convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_person, parent, false);
30 | }
31 |
32 | TextView tvName = (TextView) convertView.findViewById(R.id.textName);
33 | ImageView faceView = (ImageView) convertView.findViewById(R.id.imageFace);
34 | convertView.findViewById(R.id.buttonDelete).setOnClickListener(new View.OnClickListener() {
35 | @Override
36 | public void onClick(View view) {
37 | dbManager.deletePerson(DBManager.personList.get(position).name);
38 | notifyDataSetChanged();
39 | if (DBManager.personList.size() == 0){
40 | txtEnrolledFace.setVisibility(View.INVISIBLE);
41 | } else {
42 | txtEnrolledFace.setVisibility(View.VISIBLE);
43 | }
44 | }
45 | });
46 |
47 | tvName.setText(person.name);
48 | faceView.setImageBitmap(person.face);
49 | // Return the completed view to render on screen
50 | return convertView;
51 | }
52 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/faceplugin/facerecognition/ResultActivity.kt:
--------------------------------------------------------------------------------
1 | package com.faceplugin.facerecognition
2 |
3 | import android.content.Intent
4 | import android.graphics.Bitmap
5 | import android.os.Bundle
6 | import android.widget.ImageView
7 | import android.widget.TextView
8 | import androidx.appcompat.app.AppCompatActivity
9 |
10 | class ResultActivity : AppCompatActivity() {
11 | override fun onCreate(savedInstanceState: Bundle?) {
12 | super.onCreate(savedInstanceState)
13 | setContentView(R.layout.activity_result_new)
14 |
15 | val identifyedFace = intent.getParcelableExtra("identified_face") as? Bitmap
16 | val enrolledFace = intent.getParcelableExtra("enrolled_face") as? Bitmap
17 | val identifiedName = intent.getStringExtra("identified_name")
18 |
19 |
20 | findViewById(R.id.imageEnrolled).setImageBitmap(enrolledFace)
21 | findViewById(R.id.imageIdentified).setImageBitmap(identifyedFace)
22 | findViewById(R.id.textPerson).text = "ID: " + identifiedName
23 | /*findViewById(R.id.textSimilarity).text = "Similarity: " + similarity
24 | findViewById(R.id.textLiveness).text = "Liveness score: " + livenessScore
25 | findViewById(R.id.textYaw).text = "Yaw: " + yaw
26 | findViewById(R.id.textRoll).text = "Roll: " + roll
27 | findViewById(R.id.textPitch).text = "Pitch: " + pitch
28 |
29 | if (face_quality < 0.5f) {
30 | val msg = String.format("Quality: Low, score = %.03f", face_quality)
31 | findViewById(R.id.txtQuality).text = msg
32 | } else if(face_quality < 0.75f){
33 | val msg = String.format("Quality: Medium, score = %.03f", face_quality)
34 | findViewById(R.id.txtQuality).text = msg
35 | } else {
36 | val msg = String.format("Quality: High, score = %.03f", face_quality)
37 | findViewById(R.id.txtQuality).text = msg
38 | }
39 |
40 | var msg = String.format("Luminance: %.03f", face_luminance)
41 | findViewById(R.id.txtLuminance).text = msg*/
42 |
43 |
44 | findViewById(R.id.btn_details).setOnClickListener {
45 | val bottomSheet = IdentifyDetailsActivity()
46 | val bundle = Bundle()
47 | bundle.putString("identified_name", identifiedName)
48 | bundle.putFloat("similarity", intent.getFloatExtra("similarity", 0f))
49 | bundle.putFloat("liveness", intent.getFloatExtra("liveness", 0f))
50 | bundle.putFloat("yaw", intent.getFloatExtra("yaw", 0f))
51 | bundle.putFloat("roll", intent.getFloatExtra("roll", 0f))
52 | bundle.putFloat("pitch", intent.getFloatExtra("pitch", 0f))
53 | bundle.putFloat("face_quality", intent.getFloatExtra("face_quality", 0f))
54 | bundle.putFloat("face_luminance", intent.getFloatExtra("face_luminance", 0f))
55 | bottomSheet.arguments = bundle
56 |
57 | //startActivity(intent)
58 | bottomSheet.show(supportFragmentManager, "IdentifyDetailsActivity")
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/faceplugin/facerecognition/SettingsActivity.kt:
--------------------------------------------------------------------------------
1 | package com.faceplugin.facerecognition
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.widget.Toast
6 | import androidx.appcompat.app.AppCompatActivity
7 | import androidx.camera.core.CameraSelector
8 | import androidx.preference.*
9 |
10 |
11 | class SettingsActivity : AppCompatActivity() {
12 |
13 | companion object {
14 | const val DEFAULT_CAMERA_LENS = "front"
15 | const val DEFAULT_LIVENESS_THRESHOLD = "0.7"
16 | const val DEFAULT_IDENTIFY_THRESHOLD = "0.8"
17 | const val DEFAULT_LIVENESS_LEVEL = "0"
18 | const val DEFAULT_YAW_THRESHOLD = "10.0"
19 | const val DEFAULT_ROLL_THRESHOLD = "10.0"
20 | const val DEFAULT_PITCH_THRESHOLD = "10.0"
21 | const val DEFAULT_OCCLUSION_THRESHOLD = "0.5"
22 | const val DEFAULT_EYECLOSE_THRESHOLD = "0.5"
23 | const val DEFAULT_MOUTHOPEN_THRESHOLD = "0.5"
24 |
25 | @JvmStatic
26 | fun getLivenessThreshold(context: Context): Float {
27 | val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
28 | return sharedPreferences.getString("liveness_threshold", SettingsActivity.DEFAULT_LIVENESS_THRESHOLD)!!.toFloat()
29 | }
30 |
31 | @JvmStatic
32 | fun getIdentifyThreshold(context: Context): Float {
33 | val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
34 | return sharedPreferences.getString("identify_threshold", SettingsActivity.DEFAULT_IDENTIFY_THRESHOLD)!!.toFloat()
35 | }
36 |
37 | @JvmStatic
38 | fun getCameraLens(context: Context): Int {
39 | val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
40 | val cameraLens = sharedPreferences.getString("camera_lens", SettingsActivity.DEFAULT_CAMERA_LENS)
41 | if(cameraLens == "back") {
42 | return CameraSelector.LENS_FACING_BACK
43 | } else {
44 | return CameraSelector.LENS_FACING_FRONT
45 | }
46 | }
47 |
48 | @JvmStatic
49 | fun getLivenessLevel(context: Context): Int {
50 | val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
51 | val livenessLevel = sharedPreferences.getString("liveness_level", SettingsActivity.DEFAULT_LIVENESS_LEVEL)
52 | if(livenessLevel == "0") {
53 | return 0
54 | } else {
55 | return 1
56 | }
57 | }
58 |
59 | @JvmStatic
60 | fun getYawThreshold(context: Context): Float {
61 | val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
62 | return sharedPreferences.getString("yaw_threshold", SettingsActivity.DEFAULT_YAW_THRESHOLD)!!.toFloat()
63 | }
64 |
65 | @JvmStatic
66 | fun getRollThreshold(context: Context): Float {
67 | val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
68 | return sharedPreferences.getString("roll_threshold", SettingsActivity.DEFAULT_ROLL_THRESHOLD)!!.toFloat()
69 | }
70 |
71 | @JvmStatic
72 | fun getPitchThreshold(context: Context): Float {
73 | val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
74 | return sharedPreferences.getString("pitch_threshold", SettingsActivity.DEFAULT_PITCH_THRESHOLD)!!.toFloat()
75 | }
76 |
77 | @JvmStatic
78 | fun getOcclusionThreshold(context: Context): Float {
79 | val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
80 | return sharedPreferences.getString("occlusion_threshold", SettingsActivity.DEFAULT_OCCLUSION_THRESHOLD)!!.toFloat()
81 | }
82 |
83 | @JvmStatic
84 | fun getEyecloseThreshold(context: Context): Float {
85 | val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
86 | return sharedPreferences.getString("eyeclose_threshold", SettingsActivity.DEFAULT_EYECLOSE_THRESHOLD)!!.toFloat()
87 | }
88 |
89 | @JvmStatic
90 | fun getMouthopenThreshold(context: Context): Float {
91 | val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
92 | return sharedPreferences.getString("mouthopen_threshold", SettingsActivity.DEFAULT_MOUTHOPEN_THRESHOLD)!!.toFloat()
93 | }
94 | }
95 |
96 | lateinit var dbManager: DBManager
97 |
98 | override fun onCreate(savedInstanceState: Bundle?) {
99 | super.onCreate(savedInstanceState)
100 | setContentView(R.layout.activity_settings)
101 | if (savedInstanceState == null) {
102 | supportFragmentManager
103 | .beginTransaction()
104 | .replace(R.id.settings, SettingsFragment())
105 | .commit()
106 | }
107 | supportActionBar?.setDisplayHomeAsUpEnabled(true)
108 |
109 | dbManager = DBManager(this)
110 | }
111 |
112 | class SettingsFragment : PreferenceFragmentCompat() {
113 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
114 | setPreferencesFromResource(R.xml.root_preferences, rootKey)
115 |
116 | val cameraLensPref = findPreference("camera_lens")
117 | val livenessThresholdPref = findPreference("liveness_threshold")
118 | val livenessLevelPref = findPreference("liveness_level")
119 | val identifyThresholdPref = findPreference("identify_threshold")
120 | val yawThresholdPref = findPreference("yaw_threshold")
121 | val rollThresholdPref = findPreference("roll_threshold")
122 | val pitchThresholdPref = findPreference("pitch_threshold")
123 | val occlusionThresholdPref = findPreference("occlusion_threshold")
124 | val eyeCloseThresholdPref = findPreference("eyeclose_threshold")
125 | val mouthOpenThresholdPref = findPreference("mouthopen_threshold")
126 | val buttonRestorePref = findPreference("restore_default_settings")
127 |
128 | livenessThresholdPref?.setOnPreferenceChangeListener{ preference, newValue ->
129 | val stringPref = newValue as String
130 | try {
131 | if(stringPref.toFloat() < 0.0f || stringPref.toFloat() > 1.0f) {
132 | Toast.makeText(context, getString(R.string.invalid_value), Toast.LENGTH_SHORT).show()
133 | false
134 | } else {
135 | true
136 | }
137 | } catch (e:Exception) {
138 | Toast.makeText(context, getString(R.string.invalid_value), Toast.LENGTH_SHORT).show()
139 | false
140 | }
141 | }
142 |
143 | identifyThresholdPref?.setOnPreferenceChangeListener{ preference, newValue ->
144 | val stringPref = newValue as String
145 | try {
146 | if(stringPref.toFloat() < 0.0f || stringPref.toFloat() > 1.0f) {
147 | Toast.makeText(context, getString(R.string.invalid_value), Toast.LENGTH_SHORT).show()
148 | false
149 | } else {
150 | true
151 | }
152 | } catch (e:Exception) {
153 | Toast.makeText(context, getString(R.string.invalid_value), Toast.LENGTH_SHORT).show()
154 | false
155 | }
156 | }
157 |
158 | yawThresholdPref?.setOnPreferenceChangeListener{ preference, newValue ->
159 | val stringPref = newValue as String
160 | try {
161 | if(stringPref.toFloat() < 0.0f || stringPref.toFloat() > 30.0f) {
162 | Toast.makeText(context, getString(R.string.invalid_value), Toast.LENGTH_SHORT).show()
163 | false
164 | } else {
165 | true
166 | }
167 | } catch (e:Exception) {
168 | Toast.makeText(context, getString(R.string.invalid_value), Toast.LENGTH_SHORT).show()
169 | false
170 | }
171 | }
172 |
173 | rollThresholdPref?.setOnPreferenceChangeListener{ preference, newValue ->
174 | val stringPref = newValue as String
175 | try {
176 | if(stringPref.toFloat() < 0.0f || stringPref.toFloat() > 30.0f) {
177 | Toast.makeText(context, getString(R.string.invalid_value), Toast.LENGTH_SHORT).show()
178 | false
179 | } else {
180 | true
181 | }
182 | } catch (e:Exception) {
183 | Toast.makeText(context, getString(R.string.invalid_value), Toast.LENGTH_SHORT).show()
184 | false
185 | }
186 | }
187 |
188 | pitchThresholdPref?.setOnPreferenceChangeListener{ preference, newValue ->
189 | val stringPref = newValue as String
190 | try {
191 | if(stringPref.toFloat() < 0.0f || stringPref.toFloat() > 30.0f) {
192 | Toast.makeText(context, getString(R.string.invalid_value), Toast.LENGTH_SHORT).show()
193 | false
194 | } else {
195 | true
196 | }
197 | } catch (e:Exception) {
198 | Toast.makeText(context, getString(R.string.invalid_value), Toast.LENGTH_SHORT).show()
199 | false
200 | }
201 | }
202 |
203 | occlusionThresholdPref?.setOnPreferenceChangeListener{ preference, newValue ->
204 | val stringPref = newValue as String
205 | try {
206 | if(stringPref.toFloat() < 0.0f || stringPref.toFloat() > 1.0f) {
207 | Toast.makeText(context, getString(R.string.invalid_value), Toast.LENGTH_SHORT).show()
208 | false
209 | } else {
210 | true
211 | }
212 | } catch (e:Exception) {
213 | Toast.makeText(context, getString(R.string.invalid_value), Toast.LENGTH_SHORT).show()
214 | false
215 | }
216 | }
217 |
218 | eyeCloseThresholdPref?.setOnPreferenceChangeListener{ preference, newValue ->
219 | val stringPref = newValue as String
220 | try {
221 | if(stringPref.toFloat() < 0.0f || stringPref.toFloat() > 1.0f) {
222 | Toast.makeText(context, getString(R.string.invalid_value), Toast.LENGTH_SHORT).show()
223 | false
224 | } else {
225 | true
226 | }
227 | } catch (e:Exception) {
228 | Toast.makeText(context, getString(R.string.invalid_value), Toast.LENGTH_SHORT).show()
229 | false
230 | }
231 | }
232 |
233 | mouthOpenThresholdPref?.setOnPreferenceChangeListener{ preference, newValue ->
234 | val stringPref = newValue as String
235 | try {
236 | if(stringPref.toFloat() < 0.0f || stringPref.toFloat() > 1.0f) {
237 | Toast.makeText(context, getString(R.string.invalid_value), Toast.LENGTH_SHORT).show()
238 | false
239 | } else {
240 | true
241 | }
242 | } catch (e:Exception) {
243 | Toast.makeText(context, getString(R.string.invalid_value), Toast.LENGTH_SHORT).show()
244 | false
245 | }
246 | }
247 |
248 | buttonRestorePref?.setOnPreferenceClickListener {
249 |
250 | cameraLensPref?.value = SettingsActivity.DEFAULT_CAMERA_LENS
251 | livenessLevelPref?.value = SettingsActivity.DEFAULT_LIVENESS_LEVEL
252 | livenessThresholdPref?.text = SettingsActivity.DEFAULT_LIVENESS_THRESHOLD
253 | identifyThresholdPref?.text = SettingsActivity.DEFAULT_IDENTIFY_THRESHOLD
254 | yawThresholdPref?.text = SettingsActivity.DEFAULT_YAW_THRESHOLD
255 | rollThresholdPref?.text = SettingsActivity.DEFAULT_ROLL_THRESHOLD
256 | pitchThresholdPref?.text = SettingsActivity.DEFAULT_PITCH_THRESHOLD
257 | occlusionThresholdPref?.text = SettingsActivity.DEFAULT_OCCLUSION_THRESHOLD
258 | eyeCloseThresholdPref?.text = SettingsActivity.DEFAULT_EYECLOSE_THRESHOLD
259 | mouthOpenThresholdPref?.text = SettingsActivity.DEFAULT_MOUTHOPEN_THRESHOLD
260 |
261 |
262 | Toast.makeText(activity, getString(R.string.restored_default_settings), Toast.LENGTH_LONG).show()
263 | true
264 | }
265 |
266 | val buttonClearPref = findPreference("clear_all_person")
267 | buttonClearPref?.setOnPreferenceClickListener {
268 | val settingsActivity = activity as SettingsActivity
269 | settingsActivity.dbManager.clearDB()
270 |
271 | Toast.makeText(activity, getString(R.string.cleared_all_person), Toast.LENGTH_LONG).show()
272 | true
273 | }
274 | }
275 | }
276 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/faceplugin/facerecognition/SplashActivity.java:
--------------------------------------------------------------------------------
1 | package com.faceplugin.facerecognition;
2 |
3 | import androidx.appcompat.app.AppCompatActivity;
4 |
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.os.Handler;
8 |
9 | public class SplashActivity extends AppCompatActivity {
10 |
11 |
12 | @Override
13 | protected void onCreate(Bundle savedInstanceState) {
14 | super.onCreate(savedInstanceState);
15 | setContentView(R.layout.activity_splash);
16 |
17 | new Handler().postDelayed(new Runnable() {
18 | @Override
19 | public void run() {
20 | Intent intent =new Intent(SplashActivity.this, MainActivity.class);
21 | startActivity(intent);
22 | finish();
23 | }
24 | },MyGlobal.splash_delay_time);
25 |
26 | // Intent intent =new Intent(SplashActivity.this, ChooseActivity.class);
27 | // startActivity(intent);
28 | // finish();
29 |
30 | }
31 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/faceplugin/facerecognition/Utils.java:
--------------------------------------------------------------------------------
1 | package com.faceplugin.facerecognition;
2 |
3 | import android.content.Context;
4 | import android.database.Cursor;
5 | import android.graphics.Bitmap;
6 | import android.graphics.BitmapFactory;
7 | import android.graphics.Matrix;
8 | import android.net.Uri;
9 | import android.provider.MediaStore;
10 |
11 | import com.ocp.facesdk.FaceBox;
12 |
13 | import java.io.IOException;
14 | import java.io.InputStream;
15 |
16 | public class Utils {
17 |
18 | public static Bitmap cropFace(Bitmap src, FaceBox faceBox) {
19 | int centerX = (faceBox.x1 + faceBox.x2) / 2;
20 | int centerY = (faceBox.y1 + faceBox.y2) / 2;
21 | int cropWidth = (int)((faceBox.x2 - faceBox.x1) * 1.4f);
22 |
23 | int cropX1 = centerX - cropWidth / 2;
24 | int cropY1 = centerY - cropWidth / 2;
25 | int cropX2 = centerX + cropWidth / 2;
26 | int cropY2 = centerY + cropWidth / 2;
27 | if(cropX1 < 0) cropX1 = 0;
28 | if(cropX2 >= src.getWidth()) cropX2 = src.getWidth() - 1;
29 | if(cropY1 < 0) cropY1 = 0;
30 | if(cropY2 >= src.getHeight()) cropY2 = src.getHeight() - 1;
31 |
32 |
33 | int cropScaleWidth = 200;
34 | int cropScaleHeight = 200;
35 | float scaleWidth = ((float) cropScaleWidth) / (cropX2 - cropX1 + 1);
36 | float scaleHeight = ((float) cropScaleHeight) / (cropY2 - cropY1 + 1);
37 |
38 | final Matrix m = new Matrix();
39 |
40 | m.setScale(1.0f, 1.0f);
41 | m.postScale(scaleWidth, scaleHeight);
42 | final Bitmap cropped = Bitmap.createBitmap(src, cropX1, cropY1, (cropX2 - cropX1 + 1), (cropY2 - cropY1 + 1), m,
43 | true /* filter */);
44 | return cropped;
45 | }
46 |
47 | public static int getOrientation(Context context, Uri photoUri) {
48 | Cursor cursor = context.getContentResolver().query(photoUri,
49 | new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);
50 |
51 | if (cursor.getCount() != 1) {
52 | return -1;
53 | }
54 |
55 | cursor.moveToFirst();
56 | return cursor.getInt(0);
57 | }
58 |
59 | public static Bitmap getCorrectlyOrientedImage(Context context, Uri photoUri) throws IOException {
60 | InputStream is = context.getContentResolver().openInputStream(photoUri);
61 | BitmapFactory.Options dbo = new BitmapFactory.Options();
62 | dbo.inJustDecodeBounds = true;
63 | BitmapFactory.decodeStream(is, null, dbo);
64 | is.close();
65 |
66 | int orientation = getOrientation(context, photoUri);
67 |
68 | Bitmap srcBitmap;
69 | is = context.getContentResolver().openInputStream(photoUri);
70 | srcBitmap = BitmapFactory.decodeStream(is);
71 | is.close();
72 |
73 | if (orientation > 0) {
74 | Matrix matrix = new Matrix();
75 | matrix.postRotate(orientation);
76 |
77 | srcBitmap = Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(),
78 | srcBitmap.getHeight(), matrix, true);
79 | }
80 |
81 | return srcBitmap;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/attributr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/drawable/attributr.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/capture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/drawable/capture.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/enroll.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/drawable/enroll.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/gradient_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/drawable/gradient_back.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_camera.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_delete.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_email.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_faceplugin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/drawable/ic_faceplugin.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/drawable/ic_github.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_person_search.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_register.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_reset.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_skype.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/drawable/ic_skype.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_telegram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/drawable/ic_telegram.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_threshold.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_tip.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_whatsapp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/drawable/ic_whatsapp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/identify.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/drawable/identify.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/information.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/drawable/information.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ripple.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 | -
7 |
8 |
9 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/rounded_btn_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/rounded_edge.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
10 |
11 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/rounded_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
10 |
11 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/drawable/settings.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/drawable/splash.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_about_new.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
21 |
22 |
31 |
32 |
33 |
34 |
45 |
46 |
51 |
52 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_attribute.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
20 |
29 |
30 |
36 |
37 |
38 |
39 |
43 |
44 |
48 |
49 |
58 |
59 |
60 |
69 |
70 |
71 |
80 |
81 |
82 |
91 |
92 |
93 |
102 |
103 |
104 |
113 |
114 |
115 |
124 |
125 |
126 |
135 |
136 |
137 |
146 |
147 |
148 |
149 |
150 |
151 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_camera.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_camera_kt.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
15 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_capture.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
19 |
27 |
28 |
29 |
38 |
39 |
40 |
41 |
52 |
53 |
58 |
59 |
65 |
66 |
67 |
68 |
79 |
80 |
81 |
92 |
93 |
94 |
105 |
106 |
107 |
119 |
120 |
125 |
126 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_contacus.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
20 |
21 |
22 |
32 |
33 |
34 |
44 |
45 |
54 |
55 |
56 |
66 |
67 |
77 |
78 |
79 |
89 |
90 |
100 |
101 |
102 |
112 |
113 |
123 |
124 |
131 |
132 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_identify_details.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
20 |
21 |
32 |
33 |
34 |
45 |
46 |
47 |
58 |
59 |
60 |
71 |
72 |
73 |
84 |
85 |
86 |
97 |
98 |
99 |
109 |
110 |
117 |
118 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
20 |
21 |
30 |
31 |
42 |
43 |
53 |
54 |
63 |
64 |
65 |
66 |
76 |
77 |
87 |
88 |
97 |
98 |
99 |
109 |
110 |
120 |
121 |
130 |
131 |
132 |
133 |
134 |
143 |
144 |
154 |
155 |
165 |
166 |
175 |
176 |
177 |
178 |
188 |
189 |
199 |
200 |
209 |
210 |
211 |
221 |
222 |
232 |
233 |
242 |
243 |
244 |
245 |
246 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
276 |
277 |
278 |
279 |
290 |
291 |
307 |
308 |
309 |
310 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_result_new.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
19 |
20 |
21 |
31 |
32 |
38 |
39 |
45 |
46 |
47 |
48 |
58 |
59 |
65 |
66 |
72 |
73 |
81 |
82 |
83 |
84 |
95 |
96 |
101 |
102 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_settings.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
19 |
20 |
24 |
25 |
26 |
27 |
28 |
32 |
37 |
38 |
41 |
49 |
50 |
51 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_person.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
17 |
18 |
21 |
22 |
34 |
35 |
41 |
42 |
43 |
52 |
53 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - Front
5 | - Back
6 |
7 |
8 |
9 | - front
10 | - back
11 |
12 |
13 |
14 | - High Accuracy
15 | - Light Weight
16 |
17 |
18 |
19 | - 0
20 | - 1
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6750A4
4 | #6750A4
5 | #FFFFFF
6 | #EADDFF
7 | #21005D
8 | #625B71
9 | #FFFFFF
10 | #E8DEF8
11 | #1D192B
12 | #7D5260
13 | #FFFFFF
14 | #FFD8E4
15 | #31111D
16 | #B3261E
17 | #FFFFFF
18 | #F9DEDC
19 | #410E0B
20 | #79747E
21 | #FFFBFE
22 | #1C1B1F
23 | #FFFBFE
24 | #1C1B1F
25 | #E7E0EC
26 | #49454F
27 | #313033
28 | #F4EFF4
29 | #D0BCFF
30 | #000000
31 | #6750A4
32 | #CAC4D0
33 | #000000
34 | #D0BCFF
35 | #381E72
36 | #4F378B
37 | #EADDFF
38 | #CCC2DC
39 | #332D41
40 | #4A4458
41 | #E8DEF8
42 | #EFB8C8
43 | #492532
44 | #633B48
45 | #FFD8E4
46 | #F2B8B5
47 | #601410
48 | #8C1D18
49 | #F9DEDC
50 | #938F99
51 | #1C1B1F
52 | #E6E1E5
53 | #1C1B1F
54 | #E6E1E5
55 | #49454F
56 | #CAC4D0
57 | #E6E1E5
58 | #313033
59 | #6750A4
60 | #000000
61 | #D0BCFF
62 | #49454F
63 | #000000
64 |
65 | #252525
66 | #63317B
67 | #BF41E3
68 | #303033
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Face Recognition
3 | SettingsActivity
4 | Settings
5 |
6 |
7 | Camera
8 | Thresholds
9 | Reset
10 |
11 |
12 | Camera lens
13 | Liveness
14 | Liveness Level
15 | Identify
16 | Yaw
17 | Roll
18 | Pitch
19 | Face occlusion
20 | Eye closed
21 | Mouth opened
22 | Restore default settings
23 | Clear all person
24 |
25 | Select Picture
26 |
27 | Multiple face detected!
28 | No face detected!
29 | Person enrolled!
30 | Liveness check failed!
31 | Restored default settings
32 | Cleared all person
33 | Invalid value
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
33 |
34 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/root_preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
15 |
16 |
17 |
18 |
21 |
22 |
28 |
29 |
36 |
37 |
42 |
43 |
48 |
49 |
54 |
55 |
60 |
61 |
66 |
67 |
72 |
73 |
78 |
79 |
80 |
83 |
84 |
87 |
88 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/app/src/test/java/com/faceplugin/facerecognition/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.faceplugin.facerecognition
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | plugins {
3 | id 'com.android.application' version '8.3.1' apply false
4 | id 'com.android.library' version '8.3.1' apply false
5 | id 'org.jetbrains.kotlin.android' version '1.8.0' apply false
6 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
24 | android.enableJetifier=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 19 20:09:07 CST 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/libfacesdk/build.gradle:
--------------------------------------------------------------------------------
1 | configurations.maybeCreate("default")
2 | artifacts.add("default", file('facesdk.aar'))
--------------------------------------------------------------------------------
/libfacesdk/build/.transforms/13753554662a2f3c3d39dbdbb6d04141/transformed/jetified-facesdk/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/libfacesdk/facesdk.aar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Faceplugin-ltd/FaceRecognition-Android/94709269b47b367022cf82d36c62ce69086e7af0/libfacesdk/facesdk.aar
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | gradlePluginPortal()
6 | jcenter()
7 | }
8 | }
9 | dependencyResolutionManagement {
10 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
11 | repositories {
12 | google()
13 | mavenCentral()
14 | jcenter()
15 | maven { url 'https://www.jitpack.io'}
16 | }
17 | }
18 | rootProject.name = "FaceRecognition"
19 | include ':app'
20 | include ':libfacesdk'
21 |
--------------------------------------------------------------------------------