UNPKG

@ha_tecno/react-native-sdk

Version:

React Native SDK for biometric authentication, liveness detection, and fingerprint recognition

152 lines (147 loc) 5.33 kB
"use strict"; import { useRef, useState } from 'react'; import { Platform } from 'react-native'; import { runAtTargetFps, useFrameProcessor } from 'react-native-vision-camera'; import { Worklets } from 'react-native-worklets-core'; const TARGET_FPS = 1; // 3 medidas - triplicar esses valores // 80x80 - Melhor equilíbrio entre precisão e desempenho // 64x64 - Tamanho comum em algoritmos de detecção de foco // 50x50 - Aceitável se a restrição de processamento for extrema export const useFocusProcessor = () => { const { balanced } = { // quality: 80, balanced: 64 // fast: 50, }; const focusScoreRef = useRef({ meanScore: 0, stdScore: 0, varScore: 0 }); const [focusScore, setFocusScore] = useState({ meanScore: 0, stdScore: 0, varScore: 0 }); const handleSharedValues = Worklets.createRunOnJS(values => { focusScoreRef.current = values; setFocusScore(values); }); const focusProcessor = useFrameProcessor(frame => { 'worklet'; runAtTargetFps(TARGET_FPS, async () => { 'worklet'; const data = new Uint8Array(frame.toArrayBuffer()); const frameWidth = frame.width; const frameHeight = frame.height; const areaWidth = balanced * 3; const areaHeight = balanced * 3; const startX = Math.floor((frameWidth - areaWidth) / 2); const startY = Math.floor((frameHeight - areaHeight) / 2); const roiBuffer = new Uint8Array(areaWidth * areaHeight); if (frame.pixelFormat === 'yuv' && Platform.OS === 'android') { for (let y = 0; y < areaHeight; y++) { const srcY = startY + y; const dstY = y; for (let x = 0; x < areaWidth; x++) { const srcX = startX + x; const dstX = x; roiBuffer[dstY * areaWidth + dstX] = data[srcY * frameWidth + srcX]; } } } else if (frame.pixelFormat === 'rgb' && Platform.OS === 'ios') { for (let y = 0; y < areaHeight; y++) { const srcY = startY + y; const dstY = y * areaWidth; const srcLineStart = srcY * frameWidth * 4; for (let x = 0; x < areaWidth; x++) { const srcX = startX + x; const pixelIndex = srcLineStart + srcX * 4; roiBuffer[dstY + x] = data[pixelIndex + 1]; // canal G } } } const ArrayIM = Object.values(roiBuffer); const L4 = Math.floor(areaHeight / 4); const C4 = Math.floor(areaWidth / 4); const lines = [ArrayIM.slice(L4 * areaWidth, (L4 + 1) * areaWidth), ArrayIM.slice(2 * L4 * areaWidth, (2 * L4 + 1) * areaWidth), ArrayIM.slice(3 * L4 * areaWidth, (3 * L4 + 1) * areaWidth)]; const columns = []; const columnPositions = [C4, 2 * C4, 3 * C4]; for (const x of columnPositions) { const column = []; for (let y = 0; y < areaHeight; y++) { column.push(ArrayIM[y * areaWidth + x]); } columns.push(column); } const allPixels = [...lines, ...columns]; const normalizeArray = arr => { const minVal = Math.min(...arr); const maxVal = Math.max(...arr); const range = maxVal - minVal; return range === 0 ? arr.map(() => 0) : arr.map(val => (val - minVal) / range); }; const normalizedLines = await Promise.all(allPixels.map(normalizeArray)); const calculateGradient = arr => { return arr.map((_, i) => i === 0 ? 0 : i === arr.length - 1 ? 0 : (arr[i + 1] - arr[i - 1]) / 2); }; const gradients = normalizedLines.map(calculateGradient).map(grad => grad.map(Math.abs)); const calculateMean = arr => { return arr.reduce((sum, val) => sum + val, 0) / arr.length; }; const calculateStandardDeviation = arr => { const mean = calculateMean(arr); const variance = arr.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / arr.length; return Math.sqrt(variance); }; const calculateImageStatistics = pixels => { if (pixels.length === 0) return { variance: 0 }; if (pixels.length === 1) return { variance: 0 }; let sum = 0; let squaredSum = 0; for (const val of pixels) { sum += val; squaredSum += val * val; } const mean = sum / pixels.length; const variance = (squaredSum - pixels.length * mean * mean) / (pixels.length - 1); return { variance }; }; const means = gradients.map(calculateMean); const stds = gradients.map(calculateStandardDeviation); // Calcula os scores const meanScore = 1000 * calculateMean(means); const stdScore = 1000 * calculateMean(stds); const { variance: varScore } = calculateImageStatistics(ArrayIM); handleSharedValues({ meanScore, stdScore, varScore }); }); // frame.render(); // const rect = Skia.XYWHRect(startX, startY, areaWidth, areaHeight); // const paint = Skia.Paint(); // paint.setColor(Skia.Color("red")); // paint.setStyle(1); // paint.setStrokeWidth(10); // frame.drawRect(rect, paint); }, []); return { focusProcessor, focusScore, focusScoreRef }; }; //# sourceMappingURL=focusProcessor.js.map