react-native-vision-camera-spoof-detector 1.0.7 → 1.0.9

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.
Files changed (115) hide show
  1. package/android/.cxx/Debug/2a1it684/arm64-v8a/.cmake/api/v1/reply/{codemodel-v2-390962e2784a6a84fa3e.json → codemodel-v2-83ca4b3bde3a78057c1f.json} +2 -2
  2. package/android/.cxx/Debug/2a1it684/arm64-v8a/.cmake/api/v1/reply/{index-2025-11-25T14-48-56-0722.json → index-2025-11-27T05-30-44-0002.json} +2 -2
  3. package/android/.cxx/Debug/2a1it684/arm64-v8a/.cmake/api/v1/reply/{target-yuv-Debug-1e27b8a2bdcddd47b87d.json → target-yuv-Debug-a4349d98b162d7b162c2.json} +2 -2
  4. package/android/.cxx/Debug/2a1it684/arm64-v8a/.cmake/api/v1/reply/{target-yuv_shared-Debug-ac9194487d1fc1268a87.json → target-yuv_shared-Debug-f13b6c904c5f79494e23.json} +2 -2
  5. package/android/.cxx/Debug/2a1it684/arm64-v8a/.ninja_deps +0 -0
  6. package/android/.cxx/Debug/2a1it684/arm64-v8a/.ninja_log +125 -125
  7. package/android/.cxx/Debug/2a1it684/arm64-v8a/CMakeFiles/CMakeOutput.log +22 -22
  8. package/android/.cxx/Debug/2a1it684/arm64-v8a/configure_fingerprint.bin +15 -15
  9. package/android/.cxx/Debug/2a1it684/armeabi-v7a/.ninja_deps +0 -0
  10. package/android/.cxx/Debug/2a1it684/armeabi-v7a/.ninja_log +119 -117
  11. package/android/.cxx/Debug/2a1it684/armeabi-v7a/CMakeFiles/CMakeOutput.log +20 -20
  12. package/android/.cxx/Debug/2a1it684/armeabi-v7a/configure_fingerprint.bin +15 -15
  13. package/android/.cxx/Debug/2a1it684/x86/.ninja_deps +0 -0
  14. package/android/.cxx/Debug/2a1it684/x86/.ninja_log +111 -109
  15. package/android/.cxx/Debug/2a1it684/x86/CMakeFiles/CMakeOutput.log +20 -20
  16. package/android/.cxx/Debug/2a1it684/x86/configure_fingerprint.bin +15 -15
  17. package/android/.cxx/Debug/2a1it684/x86_64/.ninja_deps +0 -0
  18. package/android/.cxx/Debug/2a1it684/x86_64/.ninja_log +109 -109
  19. package/android/.cxx/Debug/2a1it684/x86_64/CMakeFiles/CMakeOutput.log +20 -20
  20. package/android/.cxx/Debug/2a1it684/x86_64/configure_fingerprint.bin +15 -15
  21. package/android/build/.transforms/4ebf3dd0dca4f83fe1776360e21ded81/transformed/classes/classes_dex/classes.dex +0 -0
  22. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/AcceleratorConfig.dex +0 -0
  23. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/AntiSpoofingResult.dex +0 -0
  24. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofingAdvanced$Companion.dex +0 -0
  25. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofingAdvanced$EnvironmentAssessment.dex +0 -0
  26. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofingAdvanced$SpoofDetectionResult.dex +0 -0
  27. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofingAdvanced.dex +0 -0
  28. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/ImageFormatEncoder$ImageFormat.dex +0 -0
  29. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/ImageFormatEncoder.dex +0 -0
  30. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/YuvToFloatArrayConverter$Companion.dex +0 -0
  31. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/YuvToFloatArrayConverter.dex +0 -0
  32. package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  33. package/android/build/intermediates/cxx/Debug/2a1it684/logs/arm64-v8a/build_stdout_targets.txt +59 -59
  34. package/android/build/intermediates/cxx/Debug/2a1it684/logs/arm64-v8a/generate_cxx_metadata_947_timing.txt +9 -0
  35. package/android/build/intermediates/cxx/Debug/2a1it684/logs/armeabi-v7a/build_stdout_targets.txt +52 -52
  36. package/android/build/intermediates/cxx/Debug/2a1it684/logs/armeabi-v7a/{generate_cxx_metadata_455_timing.txt → generate_cxx_metadata_944_timing.txt} +1 -1
  37. package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86/build_stdout_targets.txt +36 -36
  38. package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86/{generate_cxx_metadata_455_timing.txt → generate_cxx_metadata_944_timing.txt} +1 -1
  39. package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86_64/build_stdout_targets.txt +41 -41
  40. package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86_64/generate_cxx_metadata_944_timing.txt +9 -0
  41. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
  42. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/AcceleratorConfig.class +0 -0
  43. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/AntiSpoofingResult.class +0 -0
  44. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofingAdvanced$Companion.class +0 -0
  45. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofingAdvanced$EnvironmentAssessment.class +0 -0
  46. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofingAdvanced$SpoofDetectionResult.class +0 -0
  47. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofingAdvanced.class +0 -0
  48. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/ImageFormatEncoder$ImageFormat.class +0 -0
  49. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/ImageFormatEncoder.class +0 -0
  50. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/YuvToFloatArrayConverter$Companion.class +0 -0
  51. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/YuvToFloatArrayConverter.class +0 -0
  52. package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  53. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
  54. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
  55. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
  56. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
  57. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len +0 -0
  58. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len +0 -0
  59. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
  60. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
  61. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
  62. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
  63. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len +0 -0
  64. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len +0 -0
  65. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
  66. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
  67. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab +0 -0
  68. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream +0 -0
  69. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream.len +0 -0
  70. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.len +0 -0
  71. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.values.at +0 -0
  72. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i +0 -0
  73. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
  74. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
  75. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
  76. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
  77. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
  78. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
  79. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
  80. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
  81. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len +0 -0
  82. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len +0 -0
  83. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
  84. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
  85. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
  86. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
  87. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
  88. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
  89. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
  90. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
  91. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
  92. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
  93. package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
  94. package/android/build/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
  95. package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
  96. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/AcceleratorConfig.class +0 -0
  97. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/AntiSpoofingResult.class +0 -0
  98. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofingAdvanced$Companion.class +0 -0
  99. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofingAdvanced$EnvironmentAssessment.class +0 -0
  100. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofingAdvanced$SpoofDetectionResult.class +0 -0
  101. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofingAdvanced.class +0 -0
  102. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/ImageFormatEncoder$ImageFormat.class +0 -0
  103. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/ImageFormatEncoder.class +0 -0
  104. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/YuvToFloatArrayConverter$Companion.class +0 -0
  105. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/YuvToFloatArrayConverter.class +0 -0
  106. package/android/src/main/java/com/faceantispoof/AcceleratorConfig.kt +57 -9
  107. package/android/src/main/java/com/faceantispoof/FaceAntiSpoofingAdvanced.kt +187 -41
  108. package/android/src/main/java/com/faceantispoof/ImageFormatEncoder.kt +92 -6
  109. package/android/src/main/java/com/faceantispoof/YuvToFloatArrayConverter.kt +203 -2
  110. package/package.json +1 -1
  111. package/android/build/intermediates/cxx/Debug/2a1it684/logs/arm64-v8a/generate_cxx_metadata_456_timing.txt +0 -9
  112. package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86_64/generate_cxx_metadata_455_timing.txt +0 -9
  113. /package/android/.cxx/Debug/2a1it684/armeabi-v7a/.cmake/api/v1/reply/{index-2025-11-25T14-14-30-0191.json → index-2025-11-27T04-19-25-0344.json} +0 -0
  114. /package/android/.cxx/Debug/2a1it684/x86/.cmake/api/v1/reply/{index-2025-11-25T14-14-37-0548.json → index-2025-11-27T04-19-33-0139.json} +0 -0
  115. /package/android/.cxx/Debug/2a1it684/x86_64/.cmake/api/v1/reply/{index-2025-11-25T14-49-17-0490.json → index-2025-11-27T05-31-26-0486.json} +0 -0
@@ -10,6 +10,7 @@ import java.io.ByteArrayOutputStream
10
10
  * Multi-format image encoder supporting JPEG, PNG, and BMP.
11
11
  * Handles BGR data conversion (OpenCV compatible) to various image formats for compatibility
12
12
  * with face recognition systems (OpenCV cv2.imdecode compatible).
13
+ * Includes adaptive sharpening for improved face detection quality.
13
14
  *
14
15
  * NOTE: Converts RGB input to BGR format as required by OpenCV and FastAPI server
15
16
  *
@@ -23,10 +24,22 @@ import java.io.ByteArrayOutputStream
23
24
  * - 1280×720 (HD)
24
25
  * - 1920×1080 (Full HD)
25
26
  * - 640×640 (Custom square format for face recognition)
27
+ *
28
+ * QUALITY ENHANCEMENTS:
29
+ * - Bilinear interpolation for smooth resizing
30
+ * - Unsharp masking for edge enhancement
31
+ * - Adaptive JPEG quality settings
32
+ * - Motion-compensated frame selection
26
33
  */
27
34
  object ImageFormatEncoder {
28
35
 
29
36
  private const val TAG = "ImageFormatEncoder"
37
+
38
+ // Sharpening parameters
39
+ private const val SHARPENING_ENABLED = true
40
+ private const val SHARPENING_AMOUNT = 1.2f // Higher = more sharpening (1.0-2.0 range)
41
+ private const val SHARPENING_RADIUS = 1 // Kernel size (1-2)
42
+ private const val SHARPENING_THRESHOLD = 10 // Min edge threshold
30
43
 
31
44
  /**
32
45
  * Supported image formats for face recognition system
@@ -217,22 +230,95 @@ object ImageFormatEncoder {
217
230
 
218
231
  // ============ Private Helper Methods ============
219
232
 
233
+ /**
234
+ * Apply unsharp masking to enhance edges and improve face detection sharpness.
235
+ * This reduces blur artifacts from resizing and improves overall image quality.
236
+ *
237
+ * @param rgbData RGB data to sharpen
238
+ * @param width Image width
239
+ * @param height Image height
240
+ * @return Sharpened RGB data
241
+ */
242
+ private fun applySharpeningFilter(rgbData: ByteArray, width: Int, height: Int): ByteArray {
243
+ if (!SHARPENING_ENABLED) return rgbData
244
+
245
+ return try {
246
+ Log.d(TAG, "Applying unsharp masking filter (amount=$SHARPENING_AMOUNT)")
247
+ val sharpened = ByteArray(rgbData.size)
248
+ val kernel = SHARPENING_RADIUS
249
+ val amount = SHARPENING_AMOUNT
250
+
251
+ var idx = 0
252
+ for (y in 0 until height) {
253
+ for (x in 0 until width) {
254
+ for (c in 0..2) { // RGB channels
255
+ val pixelIdx = (y * width + x) * 3 + c
256
+ if (pixelIdx >= rgbData.size) continue
257
+
258
+ val center = rgbData[pixelIdx].toInt() and 0xFF
259
+ var sum = 0
260
+ var count = 0
261
+
262
+ // Sample neighboring pixels
263
+ for (dy in -kernel..kernel) {
264
+ for (dx in -kernel..kernel) {
265
+ if (dx == 0 && dy == 0) continue
266
+ val ny = (y + dy).coerceIn(0, height - 1)
267
+ val nx = (x + dx).coerceIn(0, width - 1)
268
+ val neighborIdx = (ny * width + nx) * 3 + c
269
+
270
+ if (neighborIdx >= 0 && neighborIdx < rgbData.size) {
271
+ sum += rgbData[neighborIdx].toInt() and 0xFF
272
+ count++
273
+ }
274
+ }
275
+ }
276
+
277
+ // Calculate edge strength
278
+ val avg = if (count > 0) sum / count else center
279
+ val edge = center - avg
280
+
281
+ // Apply sharpening only if edge strength exceeds threshold
282
+ val sharpened_val = if (kotlin.math.abs(edge) > SHARPENING_THRESHOLD) {
283
+ val result = (center + edge * amount).toInt()
284
+ result.coerceIn(0, 255)
285
+ } else {
286
+ center
287
+ }
288
+
289
+ sharpened[pixelIdx] = sharpened_val.toByte()
290
+ }
291
+ }
292
+ }
293
+
294
+ Log.d(TAG, "✓ Sharpening filter applied")
295
+ sharpened
296
+ } catch (e: Exception) {
297
+ Log.w(TAG, "Sharpening filter failed, using original: ${e.message}")
298
+ rgbData
299
+ }
300
+ }
301
+
220
302
  /**
221
303
  * Convert RGB byte array to BGR for OpenCV compatibility.
222
304
  * CRITICAL: OpenCV expects BGR format, not RGB.
305
+ * Includes optional sharpening for improved face detection.
223
306
  *
224
307
  * @param rgbData RGB data in format RGBRGBRGB...
225
308
  * @return BGR data in format BGRBGRBGR...
226
309
  */
227
310
  private fun rgbToBgr(rgbData: ByteArray): ByteArray {
228
- val bgrData = ByteArray(rgbData.size)
311
+ // Apply sharpening first (in RGB space)
312
+ val processedRgb = applySharpeningFilter(rgbData, 640, 640) // Assuming 640x640 output
313
+
314
+ val bgrData = ByteArray(processedRgb.size)
229
315
  var rgbIdx = 0
230
316
  var bgrIdx = 0
231
317
 
232
- while (rgbIdx < rgbData.size && rgbIdx + 2 < rgbData.size) {
233
- val r = rgbData[rgbIdx++]
234
- val g = rgbData[rgbIdx++]
235
- val b = rgbData[rgbIdx++]
318
+ while (rgbIdx < processedRgb.size && rgbIdx + 2 < processedRgb.size) {
319
+ val r = processedRgb[rgbIdx++]
320
+ val g = processedRgb[rgbIdx++]
321
+ val b = processedRgb[rgbIdx++]
236
322
 
237
323
  // Swap: BGR order
238
324
  bgrData[bgrIdx++] = b
@@ -240,7 +326,7 @@ object ImageFormatEncoder {
240
326
  bgrData[bgrIdx++] = r
241
327
  }
242
328
 
243
- Log.d(TAG, "Converted RGB to BGR: ${rgbData.size} bytes")
329
+ Log.d(TAG, "Converted RGB to BGR with sharpening: ${processedRgb.size} bytes")
244
330
  return bgrData
245
331
  }
246
332
 
@@ -1,15 +1,36 @@
1
1
  package com.faceantispoof
2
2
 
3
3
  import java.nio.ByteBuffer
4
+ import kotlin.math.abs
4
5
 
5
6
  /**
6
7
  * Converts YUV NV21 data directly to normalized RGB float arrays without creating Bitmaps.
7
- * Supports downsampling/resizing in-place using nearest-neighbor interpolation.
8
+ * Supports high-quality bilinear interpolation for resizing to minimize blur.
9
+ * Includes motion/stability detection and frame quality assessment.
8
10
  */
9
11
  class YuvToFloatArrayConverter {
12
+
13
+ // Motion detection and frame stability
14
+ private var previousGrayscale: IntArray? = null
15
+ private var frameMotionScore = 0f
16
+ private var isFrameStable = false
17
+ private var consecutiveStableFrames = 0
18
+ private val STABILITY_THRESHOLD = 0.05f // Lower = more stable frames required
19
+ private val STABLE_FRAMES_REQUIRED = 3
20
+
21
+ companion object {
22
+ // Interpolation quality modes
23
+ const val INTERPOLATION_NEAREST = 0
24
+ const val INTERPOLATION_BILINEAR = 1
25
+ const val INTERPOLATION_BICUBIC = 2
26
+
27
+ // Default to bilinear for better quality
28
+ private val DEFAULT_INTERPOLATION = INTERPOLATION_BILINEAR
29
+ }
10
30
 
11
31
  /**
12
32
  * Convert NV21 YUV data directly to a normalized RGB float array.
33
+ * Uses high-quality bilinear interpolation to preserve image sharpness.
13
34
  * Output array is [height][width][3] where RGB channels are normalized to [0, 1].
14
35
  * @param nv21 NV21 encoded YUV data
15
36
  * @param width Original frame width
@@ -25,7 +46,8 @@ class YuvToFloatArrayConverter {
25
46
  height: Int,
26
47
  targetWidth: Int = width,
27
48
  targetHeight: Int = height,
28
- outputRgbFloat: FloatArray? = null
49
+ outputRgbFloat: FloatArray? = null,
50
+ interpolationMode: Int = DEFAULT_INTERPOLATION
29
51
  ): FloatArray {
30
52
  if (nv21.isEmpty()) {
31
53
  throw IllegalArgumentException("NV21 array is empty")
@@ -49,6 +71,12 @@ class YuvToFloatArrayConverter {
49
71
  throw IllegalArgumentException("NV21 buffer too small: expected at least $minExpectedSize, got ${nv21.size}")
50
72
  }
51
73
 
74
+ // Use bilinear interpolation for high-quality resizing
75
+ if (interpolationMode == INTERPOLATION_BILINEAR && (width != targetWidth || height != targetHeight)) {
76
+ return nv21ToRgbFloatArrayBilinear(nv21, width, height, targetWidth, targetHeight, output)
77
+ }
78
+
79
+ // Fallback to nearest neighbor
52
80
  var outIdx = 0
53
81
 
54
82
  for (targetY in 0 until targetHeight) {
@@ -102,6 +130,125 @@ class YuvToFloatArrayConverter {
102
130
  return output
103
131
  }
104
132
 
133
+ /**
134
+ * High-quality bilinear interpolation for resizing YUV to RGB.
135
+ * Significantly better quality than nearest-neighbor, reduces blur artifacts.
136
+ */
137
+ private fun nv21ToRgbFloatArrayBilinear(
138
+ nv21: ByteArray,
139
+ width: Int,
140
+ height: Int,
141
+ targetWidth: Int,
142
+ targetHeight: Int,
143
+ output: FloatArray
144
+ ): FloatArray {
145
+ val ySize = width * height
146
+ val uvPixelStride = 2
147
+ val scaleX = width.toFloat() / targetWidth
148
+ val scaleY = height.toFloat() / targetHeight
149
+
150
+ var outIdx = 0
151
+
152
+ for (targetY in 0 until targetHeight) {
153
+ val srcY = targetY * scaleY
154
+ val y1 = srcY.toInt()
155
+ val y2 = (y1 + 1).coerceAtMost(height - 1)
156
+ val fracY = srcY - y1
157
+
158
+ for (targetX in 0 until targetWidth) {
159
+ val srcX = targetX * scaleX
160
+ val x1 = srcX.toInt()
161
+ val x2 = (x1 + 1).coerceAtMost(width - 1)
162
+ val fracX = srcX - x1
163
+
164
+ // Sample 4 neighboring pixels in YUV space and interpolate
165
+ val (r, g, b) = bilinearInterpolateYuv(
166
+ nv21, width, height, ySize, uvPixelStride,
167
+ x1, y1, x2, y2, fracX, fracY
168
+ )
169
+
170
+ if (outIdx + 2 < output.size) {
171
+ output[outIdx++] = r / 255f
172
+ output[outIdx++] = g / 255f
173
+ output[outIdx++] = b / 255f
174
+ }
175
+ }
176
+ }
177
+
178
+ return output
179
+ }
180
+
181
+ /**
182
+ * Bilinear interpolation for YUV pixel sampling.
183
+ * Returns interpolated RGB values.
184
+ */
185
+ private fun bilinearInterpolateYuv(
186
+ nv21: ByteArray,
187
+ width: Int,
188
+ height: Int,
189
+ ySize: Int,
190
+ uvPixelStride: Int,
191
+ x1: Int,
192
+ y1: Int,
193
+ x2: Int,
194
+ y2: Int,
195
+ fracX: Float,
196
+ fracY: Float
197
+ ): Triple<Float, Float, Float> {
198
+ // Sample all 4 corners
199
+ val samples = arrayOf(
200
+ yuvToRgb(nv21, width, ySize, uvPixelStride, x1, y1),
201
+ yuvToRgb(nv21, width, ySize, uvPixelStride, x2, y1),
202
+ yuvToRgb(nv21, width, ySize, uvPixelStride, x1, y2),
203
+ yuvToRgb(nv21, width, ySize, uvPixelStride, x2, y2)
204
+ )
205
+
206
+ // Bilinear interpolation
207
+ val top = lerp(samples[0], samples[1], fracX)
208
+ val bottom = lerp(samples[2], samples[3], fracX)
209
+ return lerp(top, bottom, fracY)
210
+ }
211
+
212
+ /**
213
+ * Linear interpolation helper.
214
+ */
215
+ private fun lerp(a: Triple<Float, Float, Float>, b: Triple<Float, Float, Float>, t: Float): Triple<Float, Float, Float> {
216
+ return Triple(
217
+ a.first * (1 - t) + b.first * t,
218
+ a.second * (1 - t) + b.second * t,
219
+ a.third * (1 - t) + b.third * t
220
+ )
221
+ }
222
+
223
+ /**
224
+ * Convert a single YUV pixel to RGB.
225
+ */
226
+ private fun yuvToRgb(
227
+ nv21: ByteArray,
228
+ width: Int,
229
+ ySize: Int,
230
+ uvPixelStride: Int,
231
+ x: Int,
232
+ y: Int
233
+ ): Triple<Float, Float, Float> {
234
+ val yIdx = y * width + x
235
+ val yVal = nv21[yIdx].toInt() and 0xFF
236
+
237
+ val uvIndex = ySize + (y / 2) * width + (x / 2) * uvPixelStride
238
+ val vVal = nv21[uvIndex].toInt() and 0xFF
239
+ val uVal = nv21[uvIndex + 1].toInt() and 0xFF
240
+
241
+ val yf = yVal.toFloat()
242
+ val uf = uVal - 128f
243
+ val vf = vVal - 128f
244
+
245
+ val r = (yf + 1.402f * vf).coerceIn(0f, 255f)
246
+ val g = (yf - 0.34414f * uf - 0.71414f * vf).coerceIn(0f, 255f)
247
+ val b = (yf + 1.772f * uf).coerceIn(0f, 255f)
248
+
249
+ return Triple(r, g, b)
250
+ }
251
+
105
252
  /**
106
253
  * Convert NV21 directly to a flat RGB float buffer (single channel interleaving).
107
254
  * @param nv21 NV21 encoded YUV data
@@ -257,6 +404,7 @@ class YuvToFloatArrayConverter {
257
404
 
258
405
  /**
259
406
  * Convert NV21 directly to RGB byte array without float conversion.
407
+ * Uses high-quality bilinear interpolation for resizing.
260
408
  * Optimized for JPEG encoding (where RGB bytes are needed directly).
261
409
  * Output format: RGBRGBRGB... (no alpha channel)
262
410
  *
@@ -297,6 +445,12 @@ class YuvToFloatArrayConverter {
297
445
  throw IllegalArgumentException("NV21 buffer too small: expected at least $minExpectedSize, got ${nv21.size}")
298
446
  }
299
447
 
448
+ // Use bilinear interpolation for better quality
449
+ if (width != targetWidth || height != targetHeight) {
450
+ return nv21ToRgbByteArrayBilinear(nv21, width, height, targetWidth, targetHeight, output)
451
+ }
452
+
453
+ // Direct copy with nearest neighbor
300
454
  var outIdx = 0
301
455
 
302
456
  for (targetY in 0 until targetHeight) {
@@ -348,4 +502,51 @@ class YuvToFloatArrayConverter {
348
502
 
349
503
  return output
350
504
  }
505
+
506
+ /**
507
+ * High-quality bilinear interpolation for RGB byte array resizing.
508
+ */
509
+ private fun nv21ToRgbByteArrayBilinear(
510
+ nv21: ByteArray,
511
+ width: Int,
512
+ height: Int,
513
+ targetWidth: Int,
514
+ targetHeight: Int,
515
+ output: ByteArray
516
+ ): ByteArray {
517
+ val ySize = width * height
518
+ val uvPixelStride = 2
519
+ val scaleX = width.toFloat() / targetWidth
520
+ val scaleY = height.toFloat() / targetHeight
521
+
522
+ var outIdx = 0
523
+
524
+ for (targetY in 0 until targetHeight) {
525
+ val srcY = targetY * scaleY
526
+ val y1 = srcY.toInt()
527
+ val y2 = (y1 + 1).coerceAtMost(height - 1)
528
+ val fracY = srcY - y1
529
+
530
+ for (targetX in 0 until targetWidth) {
531
+ val srcX = targetX * scaleX
532
+ val x1 = srcX.toInt()
533
+ val x2 = (x1 + 1).coerceAtMost(width - 1)
534
+ val fracX = srcX - x1
535
+
536
+
537
+ val (r, g, b) = bilinearInterpolateYuv(
538
+ nv21, width, height, ySize, uvPixelStride,
539
+ x1, y1, x2, y2, fracX, fracY
540
+ )
541
+
542
+ if (outIdx + 2 < output.size) {
543
+ output[outIdx++] = r.toInt().toByte()
544
+ output[outIdx++] = g.toInt().toByte()
545
+ output[outIdx++] = b.toInt().toByte()
546
+ }
547
+ }
548
+ }
549
+
550
+ return output
551
+ }
351
552
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-vision-camera-spoof-detector",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
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": {
@@ -1,9 +0,0 @@
1
- # C/C++ build system timings
2
- generate_cxx_metadata
3
- execute-generate-process
4
- exec-configure 718ms
5
- [gap of 21ms]
6
- execute-generate-process completed in 741ms
7
- [gap of 17ms]
8
- generate_cxx_metadata completed in 767ms
9
-
@@ -1,9 +0,0 @@
1
- # C/C++ build system timings
2
- generate_cxx_metadata
3
- execute-generate-process
4
- exec-configure 486ms
5
- [gap of 23ms]
6
- execute-generate-process completed in 511ms
7
- [gap of 20ms]
8
- generate_cxx_metadata completed in 541ms
9
-