react-native-vision-camera-spoof-detector 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/.cxx/Debug/2a1it684/arm64-v8a/.cmake/api/v1/reply/{codemodel-v2-6af431df2d09cde56941.json → codemodel-v2-6c7de80461af72f456a3.json} +2 -2
- package/android/.cxx/Debug/2a1it684/arm64-v8a/.cmake/api/v1/reply/{index-2025-11-18T10-25-37-0358.json → index-2025-11-18T17-52-03-0810.json} +2 -2
- package/android/.cxx/Debug/2a1it684/arm64-v8a/.cmake/api/v1/reply/{target-yuv-Debug-d9c8b9c64fd8df9f1bcd.json → target-yuv-Debug-32bc4eddd343848e1c25.json} +3 -3
- package/android/.cxx/Debug/2a1it684/arm64-v8a/.cmake/api/v1/reply/{target-yuv_shared-Debug-ffb5efa9f8837691d492.json → target-yuv_shared-Debug-75ea769bf76a12914d29.json} +3 -3
- package/android/.cxx/Debug/2a1it684/arm64-v8a/.ninja_deps +0 -0
- package/android/.cxx/Debug/2a1it684/arm64-v8a/.ninja_log +63 -125
- package/android/.cxx/Debug/2a1it684/arm64-v8a/CMakeFiles/CMakeOutput.log +22 -22
- package/android/.cxx/Debug/2a1it684/arm64-v8a/configure_fingerprint.bin +15 -15
- package/android/.cxx/Debug/2a1it684/armeabi-v7a/.cmake/api/v1/reply/{codemodel-v2-053850119b681f93cecc.json → codemodel-v2-52ac1d8b40b69596389b.json} +2 -2
- package/android/.cxx/Debug/2a1it684/armeabi-v7a/.cmake/api/v1/reply/{index-2025-11-18T10-12-50-0571.json → index-2025-11-18T16-28-36-0058.json} +2 -2
- package/android/.cxx/Debug/2a1it684/armeabi-v7a/.cmake/api/v1/reply/{target-yuv-Debug-a12ad49ff79080871bce.json → target-yuv-Debug-97f9e822dbd84a186d44.json} +2 -2
- package/android/.cxx/Debug/2a1it684/armeabi-v7a/.cmake/api/v1/reply/{target-yuv_shared-Debug-2b00e64621a56b8dd632.json → target-yuv_shared-Debug-3730d20e27c3481c06b2.json} +2 -2
- package/android/.cxx/Debug/2a1it684/armeabi-v7a/.ninja_deps +0 -0
- package/android/.cxx/Debug/2a1it684/armeabi-v7a/.ninja_log +117 -119
- package/android/.cxx/Debug/2a1it684/armeabi-v7a/CMakeFiles/CMakeOutput.log +20 -20
- package/android/.cxx/Debug/2a1it684/armeabi-v7a/configure_fingerprint.bin +15 -15
- package/android/.cxx/Debug/2a1it684/x86/.ninja_deps +0 -0
- package/android/.cxx/Debug/2a1it684/x86/.ninja_log +109 -111
- package/android/.cxx/Debug/2a1it684/x86/CMakeFiles/CMakeOutput.log +20 -20
- package/android/.cxx/Debug/2a1it684/x86/configure_fingerprint.bin +15 -15
- package/android/.cxx/Debug/2a1it684/x86_64/.ninja_deps +0 -0
- package/android/.cxx/Debug/2a1it684/x86_64/.ninja_log +55 -109
- package/android/.cxx/Debug/2a1it684/x86_64/CMakeFiles/CMakeOutput.log +20 -20
- package/android/.cxx/Debug/2a1it684/x86_64/configure_fingerprint.bin +15 -15
- package/android/build/.transforms/4ebf3dd0dca4f83fe1776360e21ded81/transformed/classes/classes_dex/classes.dex +0 -0
- package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/AntiSpoofingResult.dex +0 -0
- package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofingAdvanced$Companion.dex +0 -0
- package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofingAdvanced$EnvironmentAssessment.dex +0 -0
- package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofingAdvanced$SpoofDetectionResult.dex +0 -0
- package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofingAdvanced.dex +0 -0
- package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/arm64-v8a/build_stdout_targets.txt +1 -62
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/arm64-v8a/generate_cxx_metadata_2398_timing.txt +9 -0
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/arm64-v8a/generate_cxx_metadata_2614_timing.txt +9 -0
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/armeabi-v7a/build_stdout_targets.txt +1 -58
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/{x86/generate_cxx_metadata_9843_timing.txt → armeabi-v7a/generate_cxx_metadata_2399_timing.txt} +1 -1
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86/build_stdout_targets.txt +1 -54
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86/generate_cxx_metadata_2399_timing.txt +3 -0
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86/generate_cxx_metadata_2616_timing.txt +3 -0
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86_64/build_stdout_targets.txt +1 -54
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86_64/generate_cxx_metadata_2399_timing.txt +9 -0
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86_64/generate_cxx_metadata_2616_timing.txt +9 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/AntiSpoofingResult.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofingAdvanced$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofingAdvanced$EnvironmentAssessment.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofingAdvanced$SpoofDetectionResult.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofingAdvanced.class +0 -0
- package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab +1 -1
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/AntiSpoofingResult.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofingAdvanced$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofingAdvanced$EnvironmentAssessment.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofingAdvanced$SpoofDetectionResult.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofingAdvanced.class +0 -0
- package/android/src/main/java/com/faceantispoof/FaceAntiSpoofingAdvanced.kt +298 -52
- package/package.json +1 -1
- package/CHANGELOG.md +0 -48
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/arm64-v8a/generate_cxx_metadata_9843_timing.txt +0 -9
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86_64/generate_cxx_metadata_9843_timing.txt +0 -9
- /package/android/.cxx/Debug/2a1it684/x86/.cmake/api/v1/reply/{index-2025-11-18T10-13-00-0335.json → index-2025-11-18T16-28-43-0678.json} +0 -0
- /package/android/.cxx/Debug/2a1it684/x86_64/.cmake/api/v1/reply/{index-2025-11-18T10-26-26-0673.json → index-2025-11-18T17-52-04-0655.json} +0 -0
- /package/android/build/intermediates/cxx/Debug/2a1it684/logs/armeabi-v7a/{generate_cxx_metadata_9843_timing.txt → generate_cxx_metadata_2616_timing.txt} +0 -0
|
@@ -8,20 +8,21 @@ import java.io.IOException
|
|
|
8
8
|
import java.nio.MappedByteBuffer
|
|
9
9
|
import java.nio.channels.FileChannel
|
|
10
10
|
import java.io.FileInputStream
|
|
11
|
-
import kotlin.math
|
|
11
|
+
import kotlin.math.*
|
|
12
12
|
import java.nio.ByteBuffer
|
|
13
13
|
import java.nio.ByteOrder
|
|
14
|
-
import java.util
|
|
14
|
+
import java.util.*
|
|
15
15
|
import android.util.Log
|
|
16
|
+
import kotlin.collections.ArrayList
|
|
16
17
|
|
|
17
18
|
class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
|
|
18
19
|
|
|
19
20
|
companion object {
|
|
20
21
|
const val INPUT_IMAGE_SIZE = 256
|
|
21
|
-
const val
|
|
22
|
+
const val BASE_THRESHOLD = 0.1f
|
|
22
23
|
const val ROUTE_INDEX = 6
|
|
23
24
|
const val LAPLACE_THRESHOLD = 50
|
|
24
|
-
const val LAPLACIAN_THRESHOLD =
|
|
25
|
+
const val LAPLACIAN_THRESHOLD = 10000
|
|
25
26
|
const val MODEL_FILE = "FaceAntiSpoofing.tflite"
|
|
26
27
|
private const val TAG = "FaceAntiSpoofing"
|
|
27
28
|
|
|
@@ -29,6 +30,16 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
|
|
|
29
30
|
const val ACCELERATOR_CPU = "CPU"
|
|
30
31
|
const val ACCELERATOR_GPU = "GPU"
|
|
31
32
|
const val ACCELERATOR_NNAPI = "NNAPI"
|
|
33
|
+
|
|
34
|
+
// Advanced spoof detection constants
|
|
35
|
+
private const val HISTORY_SIZE = 10
|
|
36
|
+
private const val TEMPORAL_CONSISTENCY_THRESHOLD = 0.08f
|
|
37
|
+
private const val SCORE_VARIANCE_THRESHOLD = 0.02f
|
|
38
|
+
private const val MIN_FRAMES_FOR_ANALYSIS = 5
|
|
39
|
+
private const val DYNAMIC_THRESHOLD_MULTIPLIER = 1.3f
|
|
40
|
+
private const val TEXTURE_COMPLEXITY_THRESHOLD = 800
|
|
41
|
+
private const val COLOR_SATURATION_THRESHOLD = 0.4f
|
|
42
|
+
private const val DEPTH_VARIATION_THRESHOLD = 0.1f
|
|
32
43
|
}
|
|
33
44
|
|
|
34
45
|
private var interpreter: Interpreter? = null
|
|
@@ -48,6 +59,21 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
|
|
|
48
59
|
private var grayscaleBuffer: IntArray? = null
|
|
49
60
|
private val yuvConverter = YuvToFloatArrayConverter()
|
|
50
61
|
|
|
62
|
+
// Advanced spoof detection fields
|
|
63
|
+
private val scoreHistory = LinkedList<Float>()
|
|
64
|
+
private val laplacianHistory = LinkedList<Int>()
|
|
65
|
+
private var frameCount = 0
|
|
66
|
+
private var adaptiveThreshold = BASE_THRESHOLD
|
|
67
|
+
private var environmentAssessment = EnvironmentAssessment()
|
|
68
|
+
|
|
69
|
+
data class EnvironmentAssessment(
|
|
70
|
+
var avgBrightness: Float = 0f,
|
|
71
|
+
var brightnessVariance: Float = 0f,
|
|
72
|
+
var estimatedDistance: Float = 0f,
|
|
73
|
+
var lightingConsistency: Float = 0f,
|
|
74
|
+
var lastAssessmentTime: Long = 0
|
|
75
|
+
)
|
|
76
|
+
|
|
51
77
|
init {
|
|
52
78
|
initializeInterpreter()
|
|
53
79
|
}
|
|
@@ -58,13 +84,11 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
|
|
|
58
84
|
val options = Interpreter.Options()
|
|
59
85
|
options.setNumThreads(4)
|
|
60
86
|
|
|
61
|
-
// Try to add GPU delegate first
|
|
62
87
|
if (tryAddGpuDelegate(options)) {
|
|
63
88
|
currentAccelerator = ACCELERATOR_GPU
|
|
64
89
|
Log.i(TAG, "GPU delegate enabled successfully")
|
|
65
90
|
}
|
|
66
91
|
else {
|
|
67
|
-
// GPU not available, enable NNAPI through interpreter options
|
|
68
92
|
try {
|
|
69
93
|
options.setUseNNAPI(true)
|
|
70
94
|
currentAccelerator = ACCELERATOR_NNAPI
|
|
@@ -77,12 +101,10 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
|
|
|
77
101
|
|
|
78
102
|
interpreter = Interpreter(modelBuffer, options)
|
|
79
103
|
|
|
80
|
-
// Try to find output indices once and prepare outputs map
|
|
81
104
|
try {
|
|
82
105
|
outputIndex0 = interpreter!!.getOutputIndex("Identity")
|
|
83
106
|
outputIndex1 = interpreter!!.getOutputIndex("Identity_1")
|
|
84
107
|
} catch (e: Exception) {
|
|
85
|
-
// Keep defaults (0 and 1) if named outputs not available
|
|
86
108
|
Log.w(TAG, "Could not resolve named output indices, using defaults: ${e.message}")
|
|
87
109
|
}
|
|
88
110
|
|
|
@@ -97,13 +119,8 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
|
|
|
97
119
|
}
|
|
98
120
|
}
|
|
99
121
|
|
|
100
|
-
/**
|
|
101
|
-
* Try to enable GPU delegate for modern devices
|
|
102
|
-
* Returns true if GPU delegate was successfully added
|
|
103
|
-
*/
|
|
104
122
|
private fun tryAddGpuDelegate(options: Interpreter.Options): Boolean {
|
|
105
123
|
return try {
|
|
106
|
-
// Check if device supports GPU delegate
|
|
107
124
|
val compatibilityList = CompatibilityList()
|
|
108
125
|
if (compatibilityList.isDelegateSupportedOnThisDevice) {
|
|
109
126
|
gpuDelegate = GpuDelegate(compatibilityList.bestOptionsForThisDevice)
|
|
@@ -122,9 +139,6 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
|
|
|
122
139
|
}
|
|
123
140
|
}
|
|
124
141
|
|
|
125
|
-
/**
|
|
126
|
-
* Get the currently active accelerator type
|
|
127
|
-
*/
|
|
128
142
|
fun getAccelerator(): String = currentAccelerator
|
|
129
143
|
|
|
130
144
|
fun advancedAntiSpoofing(nv21: ByteArray, width: Int, height: Int): AntiSpoofingResult {
|
|
@@ -132,58 +146,85 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
|
|
|
132
146
|
return AntiSpoofingResult(
|
|
133
147
|
neuralNetworkScore = 0f,
|
|
134
148
|
laplacianScore = 0,
|
|
149
|
+
textureComplexity = 0,
|
|
150
|
+
temporalConsistency = 0f,
|
|
151
|
+
colorSaturation = 0f,
|
|
135
152
|
combinedScore = 0f,
|
|
136
153
|
isLive = false,
|
|
137
|
-
|
|
154
|
+
confidence = 0f,
|
|
155
|
+
label = "Not Initialized",
|
|
156
|
+
spoofType = "UNKNOWN"
|
|
138
157
|
)
|
|
139
158
|
}
|
|
140
159
|
|
|
141
|
-
//
|
|
142
|
-
if (nv21
|
|
143
|
-
|
|
144
|
-
return AntiSpoofingResult(0f, 0, 0f, false, "Error: Invalid NV21 buffer")
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (width <= 0 || height <= 0) {
|
|
148
|
-
Log.e(TAG, "Invalid frame dimensions: width=$width, height=$height")
|
|
149
|
-
return AntiSpoofingResult(0f, 0, 0f, false, "Error: Invalid dimensions")
|
|
160
|
+
// Enhanced input validation
|
|
161
|
+
if (nv21.isEmpty()) {
|
|
162
|
+
return AntiSpoofingResult(0f, 0, 0, 0f, 0f, 0f, false, 0f, "Error: Invalid NV21 buffer", "INVALID_INPUT")
|
|
150
163
|
}
|
|
151
164
|
|
|
152
165
|
val expectedSize = width * height + (width * height) / 2
|
|
153
166
|
if (nv21.size < expectedSize) {
|
|
154
|
-
|
|
155
|
-
return AntiSpoofingResult(0f, 0, 0f, false, "Error: Buffer size mismatch")
|
|
167
|
+
return AntiSpoofingResult(0f, 0, 0, 0f, 0f, 0f, false, 0f, "Error: Buffer size mismatch", "INVALID_INPUT")
|
|
156
168
|
}
|
|
157
169
|
|
|
158
170
|
return try {
|
|
171
|
+
// Multiple detection techniques
|
|
159
172
|
val nnScore = neuralNetworkAntiSpoofing(nv21, width, height)
|
|
160
173
|
val laplacianScore = laplacian(nv21, width, height)
|
|
161
|
-
|
|
162
|
-
val
|
|
163
|
-
val
|
|
174
|
+
val textureScore = calculateTextureComplexity(nv21, width, height)
|
|
175
|
+
val colorSat = calculateColorSaturation(nv21, width, height)
|
|
176
|
+
val temporalConsistency = calculateTemporalConsistency(nnScore)
|
|
177
|
+
|
|
178
|
+
// Update adaptive threshold based on environment
|
|
179
|
+
updateAdaptiveThreshold(nv21, width, height)
|
|
180
|
+
|
|
181
|
+
// Multi-factor spoof detection
|
|
182
|
+
val spoofDetection = detectSpoofType(
|
|
183
|
+
nnScore,
|
|
184
|
+
laplacianScore,
|
|
185
|
+
textureScore,
|
|
186
|
+
colorSat,
|
|
187
|
+
temporalConsistency
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
val confidence = calculateConfidence(nnScore, laplacianScore, textureScore, temporalConsistency)
|
|
191
|
+
val combinedScore = calculateCombinedScore(nnScore, laplacianScore, textureScore, temporalConsistency)
|
|
192
|
+
|
|
193
|
+
// Final decision with multiple safeguards
|
|
194
|
+
val isLive = isLiveFace(
|
|
195
|
+
nnScore,
|
|
196
|
+
laplacianScore,
|
|
197
|
+
textureScore,
|
|
198
|
+
colorSat,
|
|
199
|
+
temporalConsistency,
|
|
200
|
+
spoofDetection
|
|
201
|
+
)
|
|
164
202
|
|
|
165
203
|
AntiSpoofingResult(
|
|
166
204
|
neuralNetworkScore = nnScore,
|
|
167
205
|
laplacianScore = laplacianScore,
|
|
206
|
+
textureComplexity = textureScore,
|
|
207
|
+
temporalConsistency = temporalConsistency,
|
|
208
|
+
colorSaturation = colorSat,
|
|
168
209
|
combinedScore = combinedScore,
|
|
169
210
|
isLive = isLive,
|
|
170
|
-
|
|
211
|
+
confidence = confidence,
|
|
212
|
+
label = if (isLive) "Live Face" else "Spoof Face: ${spoofDetection.type}",
|
|
213
|
+
spoofType = spoofDetection.type
|
|
171
214
|
)
|
|
172
215
|
} catch (e: Exception) {
|
|
173
216
|
Log.e(TAG, "Error in advancedAntiSpoofing", e)
|
|
174
|
-
AntiSpoofingResult(0f, 0, 0f, false, "Error: ${e.message}")
|
|
217
|
+
AntiSpoofingResult(0f, 0, 0, 0f, 0f, 0f, false, 0f, "Error: ${e.message}", "PROCESSING_ERROR")
|
|
175
218
|
}
|
|
176
219
|
}
|
|
177
220
|
|
|
178
221
|
private fun neuralNetworkAntiSpoofing(nv21: ByteArray, width: Int, height: Int): Float {
|
|
179
222
|
return try {
|
|
180
|
-
// Validate NV21 buffer before processing
|
|
181
223
|
val expectedSize = width * height + (width * height) / 2
|
|
182
224
|
if (nv21.size < expectedSize) {
|
|
183
225
|
throw IllegalArgumentException("NV21 buffer size mismatch: expected $expectedSize, got ${nv21.size}")
|
|
184
226
|
}
|
|
185
227
|
|
|
186
|
-
// Convert NV21 YUV to RGB float array, resized to model input size
|
|
187
228
|
if (rgbFloatBuffer == null || rgbFloatBuffer!!.size < INPUT_IMAGE_SIZE * INPUT_IMAGE_SIZE * 3) {
|
|
188
229
|
rgbFloatBuffer = FloatArray(INPUT_IMAGE_SIZE * INPUT_IMAGE_SIZE * 3)
|
|
189
230
|
}
|
|
@@ -197,32 +238,40 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
|
|
|
197
238
|
throw Exception("RGB conversion returned empty array")
|
|
198
239
|
}
|
|
199
240
|
|
|
200
|
-
// Fill reusable inputBuffer with normalized floats (row-major RGB)
|
|
201
241
|
inputBuffer.rewind()
|
|
202
242
|
for (i in 0 until (INPUT_IMAGE_SIZE * INPUT_IMAGE_SIZE * 3)) {
|
|
203
243
|
inputBuffer.putFloat(rgbFloats[i])
|
|
204
244
|
}
|
|
205
245
|
inputBuffer.rewind()
|
|
206
246
|
|
|
207
|
-
// Validate interpreter
|
|
208
247
|
if (interpreter == null) {
|
|
209
248
|
throw Exception("Interpreter is null")
|
|
210
249
|
}
|
|
211
250
|
|
|
212
|
-
// Reuse preallocated outputs map and arrays
|
|
213
251
|
outputs[outputIndex0] = clssPred
|
|
214
252
|
outputs[outputIndex1] = leafNodeMask
|
|
215
253
|
|
|
216
|
-
// Run model with ByteBuffer input (single input)
|
|
217
254
|
interpreter!!.runForMultipleInputsOutputs(arrayOf<Any>(inputBuffer), outputs)
|
|
218
255
|
|
|
219
|
-
leafScore1(clssPred, leafNodeMask)
|
|
256
|
+
val rawScore = leafScore1(clssPred, leafNodeMask)
|
|
257
|
+
|
|
258
|
+
// Apply non-linear scaling to make high scores more sensitive
|
|
259
|
+
applyNonLinearScaling(rawScore)
|
|
220
260
|
} catch (e: Exception) {
|
|
221
261
|
Log.e(TAG, "Error in neuralNetworkAntiSpoofing: ${e.message}", e)
|
|
222
262
|
throw e
|
|
223
263
|
}
|
|
224
264
|
}
|
|
225
265
|
|
|
266
|
+
private fun applyNonLinearScaling(score: Float): Float {
|
|
267
|
+
// Exponential scaling to make scores > 0.1 much more sensitive
|
|
268
|
+
return if (score > 0.1f) {
|
|
269
|
+
score * (1 + (score - 0.1f) * 2.0f) // Amplify higher scores
|
|
270
|
+
} else {
|
|
271
|
+
score
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
226
275
|
private fun leafScore1(clssPred: Array<FloatArray>, leafNodeMask: Array<FloatArray>): Float {
|
|
227
276
|
var score = 0f
|
|
228
277
|
for (i in 0 until 8) {
|
|
@@ -235,19 +284,17 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
|
|
|
235
284
|
return try {
|
|
236
285
|
calculateLaplacianScore(nv21, width, height)
|
|
237
286
|
} catch (e: Exception) {
|
|
238
|
-
|
|
287
|
+
Log.e(TAG, "Error in laplacian calculation", e)
|
|
239
288
|
throw e
|
|
240
289
|
}
|
|
241
290
|
}
|
|
242
291
|
|
|
243
292
|
private fun calculateLaplacianScore(nv21: ByteArray, width: Int, height: Int): Int {
|
|
244
|
-
// Validate NV21 buffer
|
|
245
293
|
val expectedSize = width * height + (width * height) / 2
|
|
246
294
|
if (nv21.size < expectedSize) {
|
|
247
295
|
throw IllegalArgumentException("NV21 buffer size mismatch for Laplacian: expected $expectedSize, got ${nv21.size}")
|
|
248
296
|
}
|
|
249
297
|
|
|
250
|
-
// Convert to grayscale intensity array (resized to model input size)
|
|
251
298
|
if (grayscaleBuffer == null || grayscaleBuffer!!.size < INPUT_IMAGE_SIZE * INPUT_IMAGE_SIZE) {
|
|
252
299
|
grayscaleBuffer = IntArray(INPUT_IMAGE_SIZE * INPUT_IMAGE_SIZE)
|
|
253
300
|
}
|
|
@@ -263,7 +310,6 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
|
|
|
263
310
|
}
|
|
264
311
|
|
|
265
312
|
var score = 0
|
|
266
|
-
// Apply 3x3 laplacian kernel without extra allocation
|
|
267
313
|
for (y in 1 until INPUT_IMAGE_SIZE - 1) {
|
|
268
314
|
val rowOffset = y * INPUT_IMAGE_SIZE
|
|
269
315
|
for (x in 1 until INPUT_IMAGE_SIZE - 1) {
|
|
@@ -280,9 +326,199 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
|
|
|
280
326
|
return score
|
|
281
327
|
}
|
|
282
328
|
|
|
283
|
-
private fun
|
|
329
|
+
private fun calculateTextureComplexity(nv21: ByteArray, width: Int, height: Int): Int {
|
|
330
|
+
// Enhanced texture analysis using multiple filters
|
|
331
|
+
if (grayscaleBuffer == null || grayscaleBuffer!!.size < INPUT_IMAGE_SIZE * INPUT_IMAGE_SIZE) {
|
|
332
|
+
grayscaleBuffer = IntArray(INPUT_IMAGE_SIZE * INPUT_IMAGE_SIZE)
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
val grayscale = yuvConverter.nv21ToGrayscaleIntArray(
|
|
336
|
+
nv21, width, height,
|
|
337
|
+
INPUT_IMAGE_SIZE, INPUT_IMAGE_SIZE,
|
|
338
|
+
grayscaleBuffer
|
|
339
|
+
) ?: return 0
|
|
340
|
+
|
|
341
|
+
var complexity = 0
|
|
342
|
+
|
|
343
|
+
// Sobel edge detection for texture analysis
|
|
344
|
+
for (y in 1 until INPUT_IMAGE_SIZE - 1) {
|
|
345
|
+
val rowOffset = y * INPUT_IMAGE_SIZE
|
|
346
|
+
for (x in 1 until INPUT_IMAGE_SIZE - 1) {
|
|
347
|
+
val gx = (-1 * grayscale[rowOffset - INPUT_IMAGE_SIZE + x - 1] +
|
|
348
|
+
1 * grayscale[rowOffset - INPUT_IMAGE_SIZE + x + 1] +
|
|
349
|
+
-2 * grayscale[rowOffset + x - 1] +
|
|
350
|
+
2 * grayscale[rowOffset + x + 1] +
|
|
351
|
+
-1 * grayscale[rowOffset + INPUT_IMAGE_SIZE + x - 1] +
|
|
352
|
+
1 * grayscale[rowOffset + INPUT_IMAGE_SIZE + x + 1])
|
|
353
|
+
|
|
354
|
+
val gy = (-1 * grayscale[rowOffset - INPUT_IMAGE_SIZE + x - 1] +
|
|
355
|
+
-2 * grayscale[rowOffset - INPUT_IMAGE_SIZE + x] +
|
|
356
|
+
-1 * grayscale[rowOffset - INPUT_IMAGE_SIZE + x + 1] +
|
|
357
|
+
1 * grayscale[rowOffset + INPUT_IMAGE_SIZE + x - 1] +
|
|
358
|
+
2 * grayscale[rowOffset + INPUT_IMAGE_SIZE + x] +
|
|
359
|
+
1 * grayscale[rowOffset + INPUT_IMAGE_SIZE + x + 1])
|
|
360
|
+
|
|
361
|
+
val gradient = sqrt((gx * gx + gy * gy).toDouble()).toInt()
|
|
362
|
+
if (gradient > 50) complexity++
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return complexity
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
private fun calculateColorSaturation(nv21: ByteArray, width: Int, height: Int): Float {
|
|
370
|
+
// Calculate average color saturation to detect printed attacks
|
|
371
|
+
val uvStart = width * height
|
|
372
|
+
var totalSaturation = 0f
|
|
373
|
+
var sampleCount = 0
|
|
374
|
+
|
|
375
|
+
for (i in uvStart until nv21.size step 2) {
|
|
376
|
+
val u = (nv21[i].toInt() and 0xFF) - 128
|
|
377
|
+
val v = (nv21[i + 1].toInt() and 0xFF) - 128
|
|
378
|
+
val saturation = sqrt((u * u + v * v).toDouble()).toFloat()
|
|
379
|
+
totalSaturation += saturation
|
|
380
|
+
sampleCount++
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return if (sampleCount > 0) totalSaturation / sampleCount / 128.0f else 0f
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
private fun calculateTemporalConsistency(currentScore: Float): Float {
|
|
387
|
+
// Analyze score consistency over time
|
|
388
|
+
scoreHistory.addFirst(currentScore)
|
|
389
|
+
if (scoreHistory.size > HISTORY_SIZE) {
|
|
390
|
+
scoreHistory.removeLast()
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (scoreHistory.size < MIN_FRAMES_FOR_ANALYSIS) {
|
|
394
|
+
return 1.0f // Maximum consistency initially
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Calculate variance of recent scores
|
|
398
|
+
val mean = scoreHistory.average().toFloat()
|
|
399
|
+
val variance = scoreHistory.map { (it - mean) * (it - mean) }.average().toFloat()
|
|
400
|
+
|
|
401
|
+
// Convert variance to consistency score (lower variance = higher consistency)
|
|
402
|
+
return max(0f, 1.0f - (variance / SCORE_VARIANCE_THRESHOLD))
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
private fun updateAdaptiveThreshold(nv21: ByteArray, width: Int, height: Int) {
|
|
406
|
+
// Adjust threshold based on environmental factors
|
|
407
|
+
val brightness = calculateBrightness(nv21, width, height)
|
|
408
|
+
val currentTime = System.currentTimeMillis()
|
|
409
|
+
|
|
410
|
+
if (currentTime - environmentAssessment.lastAssessmentTime > 1000) { // Assess every second
|
|
411
|
+
environmentAssessment.avgBrightness = brightness
|
|
412
|
+
environmentAssessment.lastAssessmentTime = currentTime
|
|
413
|
+
|
|
414
|
+
// Make threshold more strict in good lighting conditions
|
|
415
|
+
adaptiveThreshold = if (brightness > 0.6f) {
|
|
416
|
+
BASE_THRESHOLD * 0.8f // Stricter in good light
|
|
417
|
+
} else if (brightness < 0.3f) {
|
|
418
|
+
BASE_THRESHOLD * 1.2f // Slightly more lenient in poor light
|
|
419
|
+
} else {
|
|
420
|
+
BASE_THRESHOLD
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
private fun calculateBrightness(nv21: ByteArray, width: Int, height: Int): Float {
|
|
426
|
+
// Calculate average brightness from Y channel
|
|
427
|
+
var totalLuma = 0f
|
|
428
|
+
for (i in 0 until width * height) {
|
|
429
|
+
totalLuma += (nv21[i].toInt() and 0xFF) / 255.0f
|
|
430
|
+
}
|
|
431
|
+
return totalLuma / (width * height)
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
data class SpoofDetectionResult(
|
|
435
|
+
val type: String,
|
|
436
|
+
val confidence: Float
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
private fun detectSpoofType(
|
|
440
|
+
nnScore: Float,
|
|
441
|
+
laplacianScore: Int,
|
|
442
|
+
textureScore: Int,
|
|
443
|
+
colorSat: Float,
|
|
444
|
+
temporalConsistency: Float
|
|
445
|
+
): SpoofDetectionResult {
|
|
446
|
+
|
|
447
|
+
// Detect specific spoof types based on feature patterns
|
|
448
|
+
return when {
|
|
449
|
+
// Printed photo detection (low texture, low laplacian)
|
|
450
|
+
textureScore < TEXTURE_COMPLEXITY_THRESHOLD * 0.6 &&
|
|
451
|
+
laplacianScore < LAPLACIAN_THRESHOLD * 0.7 ->
|
|
452
|
+
SpoofDetectionResult("PRINTED_PHOTO", 0.8f)
|
|
453
|
+
|
|
454
|
+
// Screen replay detection (high color saturation, medium texture)
|
|
455
|
+
colorSat > COLOR_SATURATION_THRESHOLD * 1.2 &&
|
|
456
|
+
textureScore > TEXTURE_COMPLEXITY_THRESHOLD * 0.8 ->
|
|
457
|
+
SpoofDetectionResult("SCREEN_REPLAY", 0.7f)
|
|
458
|
+
|
|
459
|
+
// 3D mask detection (medium scores across all features)
|
|
460
|
+
nnScore > BASE_THRESHOLD * 1.5 &&
|
|
461
|
+
temporalConsistency < 0.7f ->
|
|
462
|
+
SpoofDetectionResult("3D_MASK", 0.6f)
|
|
463
|
+
|
|
464
|
+
// General spoof
|
|
465
|
+
nnScore > BASE_THRESHOLD ->
|
|
466
|
+
SpoofDetectionResult("GENERAL_SPOOF", 0.9f)
|
|
467
|
+
|
|
468
|
+
else -> SpoofDetectionResult("UNKNOWN", 0.5f)
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
private fun calculateConfidence(
|
|
473
|
+
nnScore: Float,
|
|
474
|
+
laplacianScore: Int,
|
|
475
|
+
textureScore: Int,
|
|
476
|
+
temporalConsistency: Float
|
|
477
|
+
): Float {
|
|
478
|
+
val nnConfidence = 1.0f - (nnScore / BASE_THRESHOLD).coerceIn(0f, 1f)
|
|
479
|
+
val textureConfidence = (textureScore.toFloat() / TEXTURE_COMPLEXITY_THRESHOLD).coerceIn(0f, 1f)
|
|
480
|
+
val laplacianConfidence = (laplacianScore.toFloat() / LAPLACIAN_THRESHOLD).coerceIn(0f, 1f)
|
|
481
|
+
|
|
482
|
+
return (nnConfidence * 0.4f + textureConfidence * 0.3f +
|
|
483
|
+
laplacianConfidence * 0.2f + temporalConsistency * 0.1f)
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
private fun calculateCombinedScore(
|
|
487
|
+
neuralScore: Float,
|
|
488
|
+
laplacianScore: Int,
|
|
489
|
+
textureScore: Int,
|
|
490
|
+
temporalConsistency: Float
|
|
491
|
+
): Float {
|
|
284
492
|
val normalizedLaplacian = laplacianScore.toFloat() / LAPLACIAN_THRESHOLD
|
|
285
|
-
|
|
493
|
+
val normalizedTexture = textureScore.toFloat() / TEXTURE_COMPLEXITY_THRESHOLD
|
|
494
|
+
|
|
495
|
+
return (1 - neuralScore) * 0.5f +
|
|
496
|
+
normalizedLaplacian * 0.25f +
|
|
497
|
+
normalizedTexture * 0.15f +
|
|
498
|
+
temporalConsistency * 0.1f
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
private fun isLiveFace(
|
|
502
|
+
nnScore: Float,
|
|
503
|
+
laplacianScore: Int,
|
|
504
|
+
textureScore: Int,
|
|
505
|
+
colorSat: Float,
|
|
506
|
+
temporalConsistency: Float,
|
|
507
|
+
spoofDetection: SpoofDetectionResult
|
|
508
|
+
): Boolean {
|
|
509
|
+
|
|
510
|
+
// Multi-layered spoof detection
|
|
511
|
+
val layer1 = nnScore < adaptiveThreshold
|
|
512
|
+
val layer2 = laplacianScore > LAPLACIAN_THRESHOLD
|
|
513
|
+
val layer3 = textureScore > TEXTURE_COMPLEXITY_THRESHOLD
|
|
514
|
+
val layer4 = temporalConsistency > 0.7f
|
|
515
|
+
val layer5 = colorSat < COLOR_SATURATION_THRESHOLD * 1.5f
|
|
516
|
+
|
|
517
|
+
// Require majority of layers to pass, with neural network score being most important
|
|
518
|
+
val passedLayers = listOf(layer1, layer2, layer3, layer4, layer5).count { it }
|
|
519
|
+
|
|
520
|
+
// Stricter requirement: must pass at least 4 out of 5 layers, including neural network
|
|
521
|
+
return passedLayers >= 4 && layer1
|
|
286
522
|
}
|
|
287
523
|
|
|
288
524
|
@Throws(IOException::class)
|
|
@@ -297,23 +533,28 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
|
|
|
297
533
|
fileDescriptor.declaredLength
|
|
298
534
|
)
|
|
299
535
|
} catch (e: Exception) {
|
|
300
|
-
|
|
536
|
+
Log.e(TAG, "Error loading model file", e)
|
|
301
537
|
throw e
|
|
302
538
|
}
|
|
303
539
|
}
|
|
304
540
|
|
|
305
541
|
fun isInitialized(): Boolean = isInitialized
|
|
306
542
|
|
|
543
|
+
fun resetHistory() {
|
|
544
|
+
scoreHistory.clear()
|
|
545
|
+
laplacianHistory.clear()
|
|
546
|
+
frameCount = 0
|
|
547
|
+
adaptiveThreshold = BASE_THRESHOLD
|
|
548
|
+
}
|
|
549
|
+
|
|
307
550
|
fun close() {
|
|
308
551
|
try {
|
|
309
552
|
interpreter?.close()
|
|
310
553
|
interpreter = null
|
|
311
|
-
|
|
312
|
-
// Clean up GPU delegate
|
|
313
554
|
gpuDelegate?.close()
|
|
314
555
|
gpuDelegate = null
|
|
315
|
-
|
|
316
556
|
currentAccelerator = ACCELERATOR_CPU
|
|
557
|
+
resetHistory()
|
|
317
558
|
Log.i(TAG, "Interpreter and delegates closed successfully")
|
|
318
559
|
} catch (e: Exception) {
|
|
319
560
|
Log.e(TAG, "Error closing interpreter", e)
|
|
@@ -324,7 +565,12 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
|
|
|
324
565
|
data class AntiSpoofingResult(
|
|
325
566
|
val neuralNetworkScore: Float,
|
|
326
567
|
val laplacianScore: Int,
|
|
568
|
+
val textureComplexity: Int,
|
|
569
|
+
val temporalConsistency: Float,
|
|
570
|
+
val colorSaturation: Float,
|
|
327
571
|
val combinedScore: Float,
|
|
328
572
|
val isLive: Boolean,
|
|
329
|
-
val
|
|
330
|
-
|
|
573
|
+
val confidence: Float,
|
|
574
|
+
val label: String,
|
|
575
|
+
val spoofType: String
|
|
576
|
+
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-vision-camera-spoof-detector",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "High-performance face anti-spoofing and liveness detection module for React Native Vision Camera. Uses TensorFlow Lite with GPU acceleration and optimized YUV processing.",
|
|
5
5
|
"homepage": "https://github.com/jescon-tech/react-native-vision-camera-spoof-detector",
|
|
6
6
|
"repository": {
|
package/CHANGELOG.md
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
|
|
5
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
-
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
-
|
|
8
|
-
## [1.0.0] - 2025-11-18
|
|
9
|
-
|
|
10
|
-
### Added
|
|
11
|
-
- Multi-threading support with `Executors.newSingleThreadExecutor()`
|
|
12
|
-
- Proper npm package structure with reduced bundle size
|
|
13
|
-
- TypeScript type definitions (`index.d.ts`)
|
|
14
|
-
- `.npmignore` and `.gitignore` files for proper package management
|
|
15
|
-
- Support for GPU acceleration via TensorFlow Lite GPU delegate
|
|
16
|
-
- Support for NNAPI acceleration as fallback
|
|
17
|
-
- Daemon thread configuration for proper app lifecycle management
|
|
18
|
-
- Comprehensive error handling and logging
|
|
19
|
-
|
|
20
|
-
### Changed
|
|
21
|
-
- Updated package.json with proper metadata and peer dependencies
|
|
22
|
-
- Improved module initialization and cleanup procedures
|
|
23
|
-
- Enhanced frame processor to prevent blocking VisionCamera callback thread
|
|
24
|
-
- Optimized YUV to RGB conversion with reusable buffers
|
|
25
|
-
- Increased version from 0.0.26 to 1.0.0 for stable release
|
|
26
|
-
|
|
27
|
-
### Fixed
|
|
28
|
-
- Frame drops caused by blocking processing in callback thread
|
|
29
|
-
- Memory leaks by implementing proper resource cleanup
|
|
30
|
-
- Executor thread lifecycle management
|
|
31
|
-
|
|
32
|
-
### Removed
|
|
33
|
-
- Build artifacts from `.cxx/` directory (49.44 MB)
|
|
34
|
-
- Build output from `build/` directory (56.99 MB)
|
|
35
|
-
- Unnecessary Gradle wrapper binaries
|
|
36
|
-
|
|
37
|
-
### Performance Improvements
|
|
38
|
-
- Reduced package size from 127.35 MB to 20.92 MB (83.6% reduction)
|
|
39
|
-
- Non-blocking callback returns immediately
|
|
40
|
-
- Single-frame processing prevents queue overflow
|
|
41
|
-
- Optimized memory usage with daemon threads
|
|
42
|
-
|
|
43
|
-
## [0.0.26] - Previous
|
|
44
|
-
|
|
45
|
-
### Initial Release
|
|
46
|
-
- Basic face anti-spoofing detection
|
|
47
|
-
- React Native Vision Camera integration
|
|
48
|
-
- TensorFlow Lite model support
|
|
File without changes
|
|
File without changes
|