@ha_tecno/react-native-sdk
Version:
React Native SDK for biometric authentication, liveness detection, and fingerprint recognition
152 lines (147 loc) • 5.33 kB
JavaScript
;
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