react-native-vision-camera-spoof-detector 1.1.19 → 1.1.21
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.
|
@@ -55,31 +55,60 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
|
|
|
55
55
|
private fun initializeInterpreter() {
|
|
56
56
|
try {
|
|
57
57
|
val modelBuffer = loadModelFile(assetManager, MODEL_FILE)
|
|
58
|
-
val
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
58
|
+
val optimalThreads = 4
|
|
59
|
+
val compatibilityList = CompatibilityList()
|
|
60
|
+
var selectedAccelerator = ACCELERATOR_CPU
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
if (compatibilityList.isDelegateSupportedOnThisDevice) {
|
|
64
|
+
val delegate = GpuDelegate(compatibilityList.bestOptionsForThisDevice)
|
|
65
|
+
gpuDelegate = delegate
|
|
66
|
+
val options = Interpreter.Options().apply {
|
|
67
|
+
setNumThreads(optimalThreads)
|
|
68
|
+
addDelegate(delegate)
|
|
69
|
+
}
|
|
70
|
+
interpreter = Interpreter(modelBuffer, options)
|
|
71
|
+
selectedAccelerator = ACCELERATOR_GPU
|
|
72
|
+
Log.i(TAG, "Face Anti-Spoof initialized | GPU delegate enabled | Threads: $optimalThreads")
|
|
73
|
+
} else {
|
|
74
|
+
throw IllegalStateException("GPU delegate not supported")
|
|
75
|
+
}
|
|
76
|
+
} catch (e: Exception) {
|
|
77
|
+
Log.w(TAG, "GPU delegate unavailable or failed: ${e.message}", e)
|
|
78
|
+
try {
|
|
79
|
+
val nnapiOptions = org.tensorflow.lite.nnapi.NnApiDelegate()
|
|
80
|
+
val options = Interpreter.Options().apply {
|
|
81
|
+
setNumThreads(optimalThreads)
|
|
82
|
+
addDelegate(nnapiOptions)
|
|
83
|
+
}
|
|
84
|
+
interpreter = Interpreter(modelBuffer, options)
|
|
85
|
+
selectedAccelerator = ACCELERATOR_NNAPI
|
|
86
|
+
Log.i(TAG, "Face Anti-Spoof initialized | NNAPI delegate enabled | Threads: $optimalThreads")
|
|
87
|
+
} catch (nnapiError: Exception) {
|
|
88
|
+
Log.w(TAG, "NNAPI delegate unavailable or failed: ${nnapiError.message}", nnapiError)
|
|
89
|
+
val options = Interpreter.Options().apply {
|
|
90
|
+
setNumThreads(optimalThreads)
|
|
91
|
+
}
|
|
92
|
+
interpreter = Interpreter(modelBuffer, options)
|
|
93
|
+
selectedAccelerator = ACCELERATOR_CPU
|
|
94
|
+
Log.i(TAG, "Face Anti-Spoof initialized | CPU fallback enabled | Threads: $optimalThreads")
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
currentAccelerator = selectedAccelerator
|
|
99
|
+
|
|
69
100
|
try {
|
|
70
101
|
outputIndex0 = interpreter!!.getOutputIndex("Identity")
|
|
71
102
|
outputIndex1 = interpreter!!.getOutputIndex("Identity_1")
|
|
72
103
|
} catch (e: Exception) {
|
|
73
104
|
Log.w(TAG, "Could not resolve named output indices, using defaults: ${e.message}")
|
|
74
|
-
// Fallback to default indices
|
|
75
105
|
outputIndex0 = 0
|
|
76
106
|
outputIndex1 = 1
|
|
77
107
|
}
|
|
78
|
-
|
|
108
|
+
|
|
79
109
|
outputs[outputIndex0] = clssPred
|
|
80
110
|
outputs[outputIndex1] = leafNodeMask
|
|
81
111
|
isInitialized = true
|
|
82
|
-
Log.i(TAG, "Face Anti-Spoof initialized | CPU-ONLY MODE | Threads: $optimalThreads")
|
|
83
112
|
} catch (e: Exception) {
|
|
84
113
|
Log.e(TAG, "FAILED to load TFLite model: ${e.message}", e)
|
|
85
114
|
isInitialized = false
|
package/android/src/main/java/com/margelo/nitro/camera/spoofdetector/HybridSpoofDetectorOutput.kt
CHANGED
|
@@ -13,6 +13,9 @@ import com.margelo.nitro.camera.extensions.setAllowDroppingLateFrames
|
|
|
13
13
|
import com.margelo.nitro.camera.extensions.surfaceRotation
|
|
14
14
|
import com.margelo.nitro.camera.public.NativeCameraOutput
|
|
15
15
|
import com.faceantispoof.FaceAntiSpoofingAdvanced
|
|
16
|
+
import kotlin.math.abs
|
|
17
|
+
import kotlin.math.max
|
|
18
|
+
import kotlin.math.min
|
|
16
19
|
import java.util.concurrent.Executors
|
|
17
20
|
import java.util.concurrent.atomic.AtomicBoolean
|
|
18
21
|
|
|
@@ -32,10 +35,19 @@ class HybridSpoofDetectorOutput(
|
|
|
32
35
|
private val executor = Executors.newSingleThreadExecutor()
|
|
33
36
|
private val busy = AtomicBoolean(false)
|
|
34
37
|
private val disposed = AtomicBoolean(false)
|
|
38
|
+
private val frameCounter = java.util.concurrent.atomic.AtomicInteger(0)
|
|
39
|
+
private var lastFrameBrightness = 0f
|
|
35
40
|
private val detector = FaceAntiSpoofingAdvanced(
|
|
36
41
|
NitroModules.applicationContext?.assets ?: error("FaceAntiSpoof: no application context")
|
|
37
42
|
)
|
|
38
43
|
private var imageAnalysis: ImageAnalysis? = null
|
|
44
|
+
private companion object {
|
|
45
|
+
private const val FRAME_EVALUATION_INTERVAL = 3
|
|
46
|
+
private const val MIN_FRAME_BRIGHTNESS = 24f
|
|
47
|
+
private const val MAX_FRAME_BRIGHTNESS = 220f
|
|
48
|
+
private const val MIN_VARIANCE_FOR_ANALYSIS = 1500f
|
|
49
|
+
private const val MIN_BRIGHTNESS_DELTA = 8f
|
|
50
|
+
}
|
|
39
51
|
|
|
40
52
|
override fun createUseCase(
|
|
41
53
|
mirrorMode: MirrorMode,
|
|
@@ -72,6 +84,10 @@ class HybridSpoofDetectorOutput(
|
|
|
72
84
|
}
|
|
73
85
|
try {
|
|
74
86
|
val rgba = extractRgbaBytes(image)
|
|
87
|
+
if (!shouldProcessFrame(rgba, image.width, image.height)) {
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
|
|
75
91
|
val result = detector.advancedAntiSpoofingRGBA(rgba, image.width, image.height)
|
|
76
92
|
val isLive = result.neuralNetworkScore < FaceAntiSpoofingAdvanced.BASE_THRESHOLD &&
|
|
77
93
|
result.laplacianScore > FaceAntiSpoofingAdvanced.LAPLACIAN_THRESHOLD
|
|
@@ -93,6 +109,50 @@ class HybridSpoofDetectorOutput(
|
|
|
93
109
|
}
|
|
94
110
|
}
|
|
95
111
|
|
|
112
|
+
private fun shouldProcessFrame(rgba: ByteArray, width: Int, height: Int): Boolean {
|
|
113
|
+
val frameIndex = frameCounter.incrementAndGet()
|
|
114
|
+
if (frameIndex % FRAME_EVALUATION_INTERVAL != 0) {
|
|
115
|
+
return false
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
val sampleStep = max(1, min(width, height) / 32)
|
|
119
|
+
var brightnessSum = 0L
|
|
120
|
+
var brightnessSquaredSum = 0L
|
|
121
|
+
var sampleCount = 0
|
|
122
|
+
|
|
123
|
+
for (y in 0 until height step sampleStep) {
|
|
124
|
+
val rowOffset = y * width * 4
|
|
125
|
+
for (x in 0 until width step sampleStep) {
|
|
126
|
+
val index = rowOffset + x * 4
|
|
127
|
+
if (index + 2 >= rgba.size) continue
|
|
128
|
+
|
|
129
|
+
val r = rgba[index].toInt() and 0xFF
|
|
130
|
+
val g = rgba[index + 1].toInt() and 0xFF
|
|
131
|
+
val b = rgba[index + 2].toInt() and 0xFF
|
|
132
|
+
val luma = (0.299 * r + 0.587 * g + 0.114 * b).toInt()
|
|
133
|
+
|
|
134
|
+
brightnessSum += luma.toLong()
|
|
135
|
+
brightnessSquaredSum += (luma.toLong() * luma.toLong())
|
|
136
|
+
sampleCount += 1
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (sampleCount == 0) {
|
|
141
|
+
return false
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
val avgBrightness = brightnessSum.toFloat() / sampleCount
|
|
145
|
+
val variance = (brightnessSquaredSum.toFloat() / sampleCount) - (avgBrightness * avgBrightness)
|
|
146
|
+
val brightnessDelta = kotlin.math.abs(avgBrightness - lastFrameBrightness)
|
|
147
|
+
lastFrameBrightness = avgBrightness
|
|
148
|
+
|
|
149
|
+
val brightnessOk = avgBrightness in MIN_FRAME_BRIGHTNESS..MAX_FRAME_BRIGHTNESS
|
|
150
|
+
val textureOk = variance >= MIN_VARIANCE_FOR_ANALYSIS
|
|
151
|
+
val motionLikely = brightnessDelta >= MIN_BRIGHTNESS_DELTA || lastFrameBrightness == 0f
|
|
152
|
+
|
|
153
|
+
return brightnessOk && textureOk && motionLikely
|
|
154
|
+
}
|
|
155
|
+
|
|
96
156
|
private fun extractRgbaBytes(image: ImageProxy): ByteArray {
|
|
97
157
|
val plane = image.planes.firstOrNull() ?: throw IllegalStateException("RGBA image has no planes")
|
|
98
158
|
val rowStride = plane.rowStride
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-vision-camera-spoof-detector",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.21",
|
|
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/dpraful/react-native-vision-camera-spoof-detector",
|
|
6
6
|
"repository": {
|