@moveris/shared 3.1.0 → 3.3.0
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/README.md +37 -23
- package/dist/index.d.mts +12 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +59 -1
- package/dist/index.mjs +54 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -530,26 +530,27 @@ const status = getStatusMessage('capturing', DEFAULT_LOCALE);
|
|
|
530
530
|
|
|
531
531
|
#### Feedback Keys
|
|
532
532
|
|
|
533
|
-
| Key | English | Description
|
|
534
|
-
| ------------------- | ------------------------------ |
|
|
535
|
-
| `no_face` | "No face detected" | Face detection failed
|
|
536
|
-
| `face_not_centered` | "Center your face in the oval" | Face outside guide
|
|
537
|
-
| `too_close` | "Move back a little" | Face too close to camera
|
|
538
|
-
| `too_far` | "Move closer" | Face too far from camera
|
|
539
|
-
| `poor_lighting` | "Improve lighting" | Insufficient light
|
|
540
|
-
| `hold_still` | "Hold still" | Movement detected
|
|
541
|
-
| `capturing` | "Capturing..." | Frame capture in progress
|
|
542
|
-
| `processing` | "Processing..." | API verification in progress
|
|
543
|
-
| `success` | "Verification complete" | Successful completion
|
|
544
|
-
| `failed` | "Verification failed" | Failed verification
|
|
545
|
-
| `eyes_not_visible` | "Eyes not clearly visible" | Eye region featureless
|
|
546
|
-
| `eyes_shadowed` | "Eyes are in shadow…" | Eye region too dark
|
|
547
|
-
| `eyes_overexposed` | "Eye region overexposed…" | Eye region too bright
|
|
548
|
-
| `glasses_glare` | "Glare detected…" | Specular highlights on eyes
|
|
549
|
-
| `eye_quality_poor` | "Eye region quality is poor" | Generic eye quality failure
|
|
550
|
-
| `camera_angle_low` | "Raise camera to eye level" | Camera below face (Y < 0.3)
|
|
551
|
-
| `camera_angle_high` | "Lower camera to eye level" | Camera above face (Y > 0.7)
|
|
552
|
-
| `camera_tilted` | "Hold camera level" |
|
|
533
|
+
| Key | English | Description |
|
|
534
|
+
| ------------------- | ------------------------------ | --------------------------------------------------------------------------------- |
|
|
535
|
+
| `no_face` | "No face detected" | Face detection failed |
|
|
536
|
+
| `face_not_centered` | "Center your face in the oval" | Face outside guide |
|
|
537
|
+
| `too_close` | "Move back a little" | Face too close to camera |
|
|
538
|
+
| `too_far` | "Move closer" | Face too far from camera |
|
|
539
|
+
| `poor_lighting` | "Improve lighting" | Insufficient light |
|
|
540
|
+
| `hold_still` | "Hold still" | Movement detected |
|
|
541
|
+
| `capturing` | "Capturing..." | Frame capture in progress |
|
|
542
|
+
| `processing` | "Processing..." | API verification in progress |
|
|
543
|
+
| `success` | "Verification complete" | Successful completion |
|
|
544
|
+
| `failed` | "Verification failed" | Failed verification |
|
|
545
|
+
| `eyes_not_visible` | "Eyes not clearly visible" | Eye region featureless |
|
|
546
|
+
| `eyes_shadowed` | "Eyes are in shadow…" | Eye region too dark |
|
|
547
|
+
| `eyes_overexposed` | "Eye region overexposed…" | Eye region too bright |
|
|
548
|
+
| `glasses_glare` | "Glare detected…" | Specular highlights on eyes |
|
|
549
|
+
| `eye_quality_poor` | "Eye region quality is poor" | Generic eye quality failure |
|
|
550
|
+
| `camera_angle_low` | "Raise camera to eye level" | Camera below face (Y < 0.3) |
|
|
551
|
+
| `camera_angle_high` | "Lower camera to eye level" | Camera above face (Y > 0.7) |
|
|
552
|
+
| `camera_tilted` | "Hold camera level" | Device tilt > 15° (via transformation matrix, falls back to eye-corner landmarks) |
|
|
553
|
+
| `flat_lighting` | "Find better lighting" | Face-region dynamic range < 180 L-units — soft warning, capture continues |
|
|
553
554
|
|
|
554
555
|
---
|
|
555
556
|
|
|
@@ -641,6 +642,7 @@ import {
|
|
|
641
642
|
isFaceInOval,
|
|
642
643
|
calculateFaceCropRegion,
|
|
643
644
|
detectFaceRoll,
|
|
645
|
+
detectFaceRollFromMatrix,
|
|
644
646
|
detectCameraAngle,
|
|
645
647
|
} from '@moveris/shared';
|
|
646
648
|
|
|
@@ -663,14 +665,26 @@ import { calculateAdaptiveCropMultiplier } from '@moveris/shared';
|
|
|
663
665
|
const multiplier = calculateAdaptiveCropMultiplier(faceBox, frameWidth, frameHeight);
|
|
664
666
|
// Returns 2.5–4.0x (matched to cognito-check for ~33% face coverage in 224×224 crop)
|
|
665
667
|
|
|
666
|
-
// Detect face roll (device tilt)
|
|
667
|
-
|
|
668
|
-
|
|
668
|
+
// Detect face roll (device tilt) — prefer matrix when available (more accurate under glasses/occlusion)
|
|
669
|
+
if (facialTransformationMatrix) {
|
|
670
|
+
const rollResult = detectFaceRollFromMatrix(facialTransformationMatrix); // 16-element column-major 4×4
|
|
671
|
+
// { roll: number (degrees), tooTilted: boolean }
|
|
672
|
+
} else {
|
|
673
|
+
const rollResult = detectFaceRoll(landmarks); // fallback: eye-corner landmarks, requires ≥364 points
|
|
674
|
+
// { roll: number (degrees), tooTilted: boolean }
|
|
675
|
+
}
|
|
669
676
|
|
|
670
677
|
// Detect camera vertical angle from forehead/nose/chin landmark ratio
|
|
671
678
|
const angleResult = detectCameraAngle(landmarks); // requires ≥153 landmarks
|
|
672
679
|
// { ratio: number, cameraAbove: boolean, cameraBelow: boolean }
|
|
673
680
|
// ratio ~1.0 at eye level; >1.35 = camera above user; <0.75 = camera below user
|
|
681
|
+
|
|
682
|
+
// Analyse face-region dynamic range (flat lighting detection, MOV-1280)
|
|
683
|
+
// Pass pre-sampled face-region pixels — use sampleFaceRegionPixels() in @moveris/react
|
|
684
|
+
import { analyzeDynamicRange } from '@moveris/shared';
|
|
685
|
+
const drResult = analyzeDynamicRange(rgbaPixels);
|
|
686
|
+
// { range: number (max L* − min L*), isLow: boolean (< 180) }
|
|
687
|
+
// Soft warning — do not use as a hard capture gate
|
|
674
688
|
```
|
|
675
689
|
|
|
676
690
|
#### Crop Constants (aligned with cognito-check)
|
package/dist/index.d.mts
CHANGED
|
@@ -341,6 +341,14 @@ declare const MAX_FACE_RATIO = 0.7;
|
|
|
341
341
|
declare const FACE_CROP_OUTPUT_SIZE = 224;
|
|
342
342
|
declare const MAX_FACE_PERCENTAGE_IN_CROP = 0.45;
|
|
343
343
|
declare const TARGET_FACE_PERCENTAGE_IN_CROP = 0.33;
|
|
344
|
+
declare const DYNAMIC_RANGE_WARNING_THRESHOLD = 180;
|
|
345
|
+
interface DynamicRangeAnalysis {
|
|
346
|
+
range: number;
|
|
347
|
+
isLow: boolean;
|
|
348
|
+
}
|
|
349
|
+
declare function srgbToLinear(c: number): number;
|
|
350
|
+
declare function linearRgbToLabL(rLin: number, gLin: number, bLin: number): number;
|
|
351
|
+
declare function analyzeDynamicRange(rgbaPixels: Uint8ClampedArray | number[]): DynamicRangeAnalysis;
|
|
344
352
|
declare function analyzeBlur(grayscalePixels: number[], width: number, height: number, threshold?: number): BlurAnalysis;
|
|
345
353
|
declare function rgbaToGrayscale(rgbaPixels: Uint8ClampedArray | number[]): number[];
|
|
346
354
|
declare function calculateBrightness(rgbaPixels: Uint8ClampedArray | number[]): number;
|
|
@@ -372,6 +380,7 @@ interface FaceRollResult {
|
|
|
372
380
|
}
|
|
373
381
|
declare const MAX_FACE_ROLL_DEGREES = 15;
|
|
374
382
|
declare function detectFaceRoll(landmarks: FaceLandmarkPoint[]): FaceRollResult;
|
|
383
|
+
declare function detectFaceRollFromMatrix(matrix: number[]): FaceRollResult;
|
|
375
384
|
interface CameraAngleResult {
|
|
376
385
|
ratio: number;
|
|
377
386
|
cameraAbove: boolean;
|
|
@@ -749,6 +758,7 @@ declare const FEEDBACK_MESSAGES: {
|
|
|
749
758
|
readonly poor_lighting: "Improve lighting";
|
|
750
759
|
readonly too_dark: "Low lighting - move to a brighter area";
|
|
751
760
|
readonly backlit: "Backlit - try facing the light source";
|
|
761
|
+
readonly flat_lighting: "Find better lighting";
|
|
752
762
|
readonly camera_angle_low: "Raise camera to eye level";
|
|
753
763
|
readonly camera_angle_high: "Lower camera to eye level";
|
|
754
764
|
readonly camera_tilted: "Hold camera level";
|
|
@@ -788,6 +798,7 @@ interface CaptureQualityState {
|
|
|
788
798
|
cameraAngleHigh?: boolean;
|
|
789
799
|
cameraTilted?: boolean;
|
|
790
800
|
faceAreaLow?: boolean;
|
|
801
|
+
dynamicRangeLow?: boolean;
|
|
791
802
|
}
|
|
792
803
|
declare function getCaptureQualityFeedback(state: CaptureQualityState): string;
|
|
793
804
|
declare function canCaptureFrame(state: Omit<CaptureQualityState, 'framesCaptured' | 'targetFrames' | 'isCapturing'>): boolean;
|
|
@@ -838,4 +849,4 @@ declare function analyzeEyeRegionContrast(pixels: Uint8Array | Uint8ClampedArray
|
|
|
838
849
|
declare function detectSpecularHighlights(pixels: Uint8Array | Uint8ClampedArray, relativeFactor?: number, meanBrightness?: number): number;
|
|
839
850
|
declare function checkEyeRegionQuality(pixels: Uint8Array | Uint8ClampedArray, thresholds?: EyeQualityThresholds): EyeRegionQuality;
|
|
840
851
|
|
|
841
|
-
export { ALIGNMENT_THRESHOLD_CAPTURE, ALIGNMENT_THRESHOLD_GOOD, ALIGNMENT_THRESHOLD_PERFECT, ALIGNMENT_THRESHOLD_POOR, API_ENDPOINTS, API_ERROR_CODES, API_PATHS, AUTH_CONFIG, type ApiErrorCode, BACKLIT_RATIO_THRESHOLD, BLUR_THRESHOLD_MOBILE, BaseFrameCollector, type BlurAnalysis, CAMERA_ANGLE_HIGH_RATIO, CAMERA_ANGLE_LOW_RATIO, type CameraAngleResult, type CaptureQualityState, type CapturedFrame, type CropData, DEFAULT_BLUR_THRESHOLD, DEFAULT_ENDPOINT, DEFAULT_FACE_DETECTION_TIERS, DEFAULT_GAZE_THRESHOLDS, DEFAULT_HAND_OCCLUSION_CONFIG, DEFAULT_LIVENESS_CONFIG, DEFAULT_LOCALE, DEFAULT_OVAL_REGION, DEFAULT_STABILIZER_CONFIG, DEFAULT_STATUS_MESSAGES, type DeprecationInfo, type DetectionResult, type DetectionSummary, type DetectorConfig, ERROR_MESSAGES, ERROR_MESSAGES_ES, ES_LOCALE, EYE_LANDMARK_INDICES, EYE_QUALITY_THRESHOLDS, type ErrorResponse, type EyeQualityThresholds, type EyeRegionBounds, type EyeRegionQuality, type EyeRegionsBounds, FACE_CENTER_VERTICAL_OFFSET, FACE_CROP_OUTPUT_SIZE, FEEDBACK_MESSAGES, FRAME_BUFFER_CONFIG, FRAME_CONFIG, type FaceAlignmentResult, type FaceBoundingBox, type FaceDetectionTiers, type FaceInOvalResult, type FaceLandmarkPoint, type FaceRollResult, type FaceVisibilityResult, type FastCheckCropsRequest, type FastCheckModel, type FastCheckRequest, type FastCheckResponse, type FastCheckStreamRequest, type FastCheckStreamResponse, type FeedbackLocale, type FeedbackMessageKey, type Frame, FrameBuffer, type FrameData, type FrameQualityResult, FrameQueue, type FrameSource, GOOD_ALIGNMENT, type GazeThresholds, HIGH_ALIGNMENT, HYBRID_MODEL_CONFIGS, type HandOcclusionConfig, type HeadPose, type HealthResponse, type Hybrid150CheckRequest, type Hybrid50CheckRequest, type HybridCheckRequest, type HybridCheckResponse, type HybridFrameData, type HybridModelConfig, IDEAL_CROP_MULTIPLIER, type JobStatus, type JobStatusResponse, LANDMARK_INDEX, LANDMARK_MAX_BOUND, LANDMARK_MIN_BOUND, LOW_LIGHT_THRESHOLD, type LandmarkValidationResult, type LightingAnalysis, LivenessApiError, type LivenessCallbacks, LivenessClient, type LivenessClientConfig, type LivenessConfig, type LivenessResult, type LivenessState, MAX_CROP_MULTIPLIER, MAX_FACE_PERCENTAGE_IN_CROP, MAX_FACE_RATIO, MAX_FACE_ROLL_DEGREES, MAX_IDEAL_FACE_RATIO, MIN_CAPTURE_ALIGNMENT, MIN_CROP_MULTIPLIER, MIN_FACE_AREA_RATIO, MIN_FACE_BOTTOM_MARGIN, MIN_FACE_RATIO, MIN_FACE_SIDE_MARGIN, MIN_FACE_TOP_MARGIN, MIN_IDEAL_FACE_RATIO, MIN_LANDMARK_COUNT, MODEL_CONFIGS, type ModelConfig, type ModelEntry, type ModelType, type ModelVersion, type ModelsResponse, OVAL_GUIDE_COLORS, OVAL_GUIDE_STYLES, OVAL_REGION_DESKTOP, OVAL_REGION_MOBILE, type OnErrorCallback, type OnFrameCapturedCallback, type OnProgressCallback, type OnResultCallback, type OnStateChangeCallback, type OvalGuideState, type OvalRegion, type QueueStatsResponse, RETRY_CONFIG, type RetryOptions, type StabilizationProgress, type StabilizationResult, type StabilizerConfig, type StatusMessageKey, type StreamingStatus, TARGET_FACE_PERCENTAGE_IN_CROP, VALID_FRAME_COUNTS, type Verdict, type VerifyRequest, type VerifyResponse, type VideoFrameMetadata, analyzeBlur, analyzeEyeRegionBrightness, analyzeEyeRegionContrast, analyzeLighting, calculateAdaptiveCropMultiplier, calculateBrightness, calculateFaceAlignment, calculateFaceCropRegion, canCaptureFrame, checkEyeRegionQuality, checkFrameQuality, decodeBase64, detectCameraAngle, detectFaceRoll, detectSpecularHighlights, encodeBase64, generateSessionId, getActiveModels, getApiErrorMessage, getCaptureQualityFeedback, getEyeRegionBounds, getFeedbackMessage, getMinFramesForModel, getOvalGuideState, getStatusMessage, hasEnoughFrames, isDeprecatedModel, isFaceCropFullyInFrame, isFaceFullyVisible, isFaceInOval, isRetryableError, retryWithBackoff, rgbaToGrayscale, sleep, toFrameData, toHybridFrameData, toLivenessResult, toLivenessResultFromStream, validateApiKey, validateFaceLandmarks, validateFrameCount, validateFrameData, validateFrameIndex, validateTimestamp, validateUUID, validateUrl };
|
|
852
|
+
export { ALIGNMENT_THRESHOLD_CAPTURE, ALIGNMENT_THRESHOLD_GOOD, ALIGNMENT_THRESHOLD_PERFECT, ALIGNMENT_THRESHOLD_POOR, API_ENDPOINTS, API_ERROR_CODES, API_PATHS, AUTH_CONFIG, type ApiErrorCode, BACKLIT_RATIO_THRESHOLD, BLUR_THRESHOLD_MOBILE, BaseFrameCollector, type BlurAnalysis, CAMERA_ANGLE_HIGH_RATIO, CAMERA_ANGLE_LOW_RATIO, type CameraAngleResult, type CaptureQualityState, type CapturedFrame, type CropData, DEFAULT_BLUR_THRESHOLD, DEFAULT_ENDPOINT, DEFAULT_FACE_DETECTION_TIERS, DEFAULT_GAZE_THRESHOLDS, DEFAULT_HAND_OCCLUSION_CONFIG, DEFAULT_LIVENESS_CONFIG, DEFAULT_LOCALE, DEFAULT_OVAL_REGION, DEFAULT_STABILIZER_CONFIG, DEFAULT_STATUS_MESSAGES, DYNAMIC_RANGE_WARNING_THRESHOLD, type DeprecationInfo, type DetectionResult, type DetectionSummary, type DetectorConfig, type DynamicRangeAnalysis, ERROR_MESSAGES, ERROR_MESSAGES_ES, ES_LOCALE, EYE_LANDMARK_INDICES, EYE_QUALITY_THRESHOLDS, type ErrorResponse, type EyeQualityThresholds, type EyeRegionBounds, type EyeRegionQuality, type EyeRegionsBounds, FACE_CENTER_VERTICAL_OFFSET, FACE_CROP_OUTPUT_SIZE, FEEDBACK_MESSAGES, FRAME_BUFFER_CONFIG, FRAME_CONFIG, type FaceAlignmentResult, type FaceBoundingBox, type FaceDetectionTiers, type FaceInOvalResult, type FaceLandmarkPoint, type FaceRollResult, type FaceVisibilityResult, type FastCheckCropsRequest, type FastCheckModel, type FastCheckRequest, type FastCheckResponse, type FastCheckStreamRequest, type FastCheckStreamResponse, type FeedbackLocale, type FeedbackMessageKey, type Frame, FrameBuffer, type FrameData, type FrameQualityResult, FrameQueue, type FrameSource, GOOD_ALIGNMENT, type GazeThresholds, HIGH_ALIGNMENT, HYBRID_MODEL_CONFIGS, type HandOcclusionConfig, type HeadPose, type HealthResponse, type Hybrid150CheckRequest, type Hybrid50CheckRequest, type HybridCheckRequest, type HybridCheckResponse, type HybridFrameData, type HybridModelConfig, IDEAL_CROP_MULTIPLIER, type JobStatus, type JobStatusResponse, LANDMARK_INDEX, LANDMARK_MAX_BOUND, LANDMARK_MIN_BOUND, LOW_LIGHT_THRESHOLD, type LandmarkValidationResult, type LightingAnalysis, LivenessApiError, type LivenessCallbacks, LivenessClient, type LivenessClientConfig, type LivenessConfig, type LivenessResult, type LivenessState, MAX_CROP_MULTIPLIER, MAX_FACE_PERCENTAGE_IN_CROP, MAX_FACE_RATIO, MAX_FACE_ROLL_DEGREES, MAX_IDEAL_FACE_RATIO, MIN_CAPTURE_ALIGNMENT, MIN_CROP_MULTIPLIER, MIN_FACE_AREA_RATIO, MIN_FACE_BOTTOM_MARGIN, MIN_FACE_RATIO, MIN_FACE_SIDE_MARGIN, MIN_FACE_TOP_MARGIN, MIN_IDEAL_FACE_RATIO, MIN_LANDMARK_COUNT, MODEL_CONFIGS, type ModelConfig, type ModelEntry, type ModelType, type ModelVersion, type ModelsResponse, OVAL_GUIDE_COLORS, OVAL_GUIDE_STYLES, OVAL_REGION_DESKTOP, OVAL_REGION_MOBILE, type OnErrorCallback, type OnFrameCapturedCallback, type OnProgressCallback, type OnResultCallback, type OnStateChangeCallback, type OvalGuideState, type OvalRegion, type QueueStatsResponse, RETRY_CONFIG, type RetryOptions, type StabilizationProgress, type StabilizationResult, type StabilizerConfig, type StatusMessageKey, type StreamingStatus, TARGET_FACE_PERCENTAGE_IN_CROP, VALID_FRAME_COUNTS, type Verdict, type VerifyRequest, type VerifyResponse, type VideoFrameMetadata, analyzeBlur, analyzeDynamicRange, analyzeEyeRegionBrightness, analyzeEyeRegionContrast, analyzeLighting, calculateAdaptiveCropMultiplier, calculateBrightness, calculateFaceAlignment, calculateFaceCropRegion, canCaptureFrame, checkEyeRegionQuality, checkFrameQuality, decodeBase64, detectCameraAngle, detectFaceRoll, detectFaceRollFromMatrix, detectSpecularHighlights, encodeBase64, generateSessionId, getActiveModels, getApiErrorMessage, getCaptureQualityFeedback, getEyeRegionBounds, getFeedbackMessage, getMinFramesForModel, getOvalGuideState, getStatusMessage, hasEnoughFrames, isDeprecatedModel, isFaceCropFullyInFrame, isFaceFullyVisible, isFaceInOval, isRetryableError, linearRgbToLabL, retryWithBackoff, rgbaToGrayscale, sleep, srgbToLinear, toFrameData, toHybridFrameData, toLivenessResult, toLivenessResultFromStream, validateApiKey, validateFaceLandmarks, validateFrameCount, validateFrameData, validateFrameIndex, validateTimestamp, validateUUID, validateUrl };
|
package/dist/index.d.ts
CHANGED
|
@@ -341,6 +341,14 @@ declare const MAX_FACE_RATIO = 0.7;
|
|
|
341
341
|
declare const FACE_CROP_OUTPUT_SIZE = 224;
|
|
342
342
|
declare const MAX_FACE_PERCENTAGE_IN_CROP = 0.45;
|
|
343
343
|
declare const TARGET_FACE_PERCENTAGE_IN_CROP = 0.33;
|
|
344
|
+
declare const DYNAMIC_RANGE_WARNING_THRESHOLD = 180;
|
|
345
|
+
interface DynamicRangeAnalysis {
|
|
346
|
+
range: number;
|
|
347
|
+
isLow: boolean;
|
|
348
|
+
}
|
|
349
|
+
declare function srgbToLinear(c: number): number;
|
|
350
|
+
declare function linearRgbToLabL(rLin: number, gLin: number, bLin: number): number;
|
|
351
|
+
declare function analyzeDynamicRange(rgbaPixels: Uint8ClampedArray | number[]): DynamicRangeAnalysis;
|
|
344
352
|
declare function analyzeBlur(grayscalePixels: number[], width: number, height: number, threshold?: number): BlurAnalysis;
|
|
345
353
|
declare function rgbaToGrayscale(rgbaPixels: Uint8ClampedArray | number[]): number[];
|
|
346
354
|
declare function calculateBrightness(rgbaPixels: Uint8ClampedArray | number[]): number;
|
|
@@ -372,6 +380,7 @@ interface FaceRollResult {
|
|
|
372
380
|
}
|
|
373
381
|
declare const MAX_FACE_ROLL_DEGREES = 15;
|
|
374
382
|
declare function detectFaceRoll(landmarks: FaceLandmarkPoint[]): FaceRollResult;
|
|
383
|
+
declare function detectFaceRollFromMatrix(matrix: number[]): FaceRollResult;
|
|
375
384
|
interface CameraAngleResult {
|
|
376
385
|
ratio: number;
|
|
377
386
|
cameraAbove: boolean;
|
|
@@ -749,6 +758,7 @@ declare const FEEDBACK_MESSAGES: {
|
|
|
749
758
|
readonly poor_lighting: "Improve lighting";
|
|
750
759
|
readonly too_dark: "Low lighting - move to a brighter area";
|
|
751
760
|
readonly backlit: "Backlit - try facing the light source";
|
|
761
|
+
readonly flat_lighting: "Find better lighting";
|
|
752
762
|
readonly camera_angle_low: "Raise camera to eye level";
|
|
753
763
|
readonly camera_angle_high: "Lower camera to eye level";
|
|
754
764
|
readonly camera_tilted: "Hold camera level";
|
|
@@ -788,6 +798,7 @@ interface CaptureQualityState {
|
|
|
788
798
|
cameraAngleHigh?: boolean;
|
|
789
799
|
cameraTilted?: boolean;
|
|
790
800
|
faceAreaLow?: boolean;
|
|
801
|
+
dynamicRangeLow?: boolean;
|
|
791
802
|
}
|
|
792
803
|
declare function getCaptureQualityFeedback(state: CaptureQualityState): string;
|
|
793
804
|
declare function canCaptureFrame(state: Omit<CaptureQualityState, 'framesCaptured' | 'targetFrames' | 'isCapturing'>): boolean;
|
|
@@ -838,4 +849,4 @@ declare function analyzeEyeRegionContrast(pixels: Uint8Array | Uint8ClampedArray
|
|
|
838
849
|
declare function detectSpecularHighlights(pixels: Uint8Array | Uint8ClampedArray, relativeFactor?: number, meanBrightness?: number): number;
|
|
839
850
|
declare function checkEyeRegionQuality(pixels: Uint8Array | Uint8ClampedArray, thresholds?: EyeQualityThresholds): EyeRegionQuality;
|
|
840
851
|
|
|
841
|
-
export { ALIGNMENT_THRESHOLD_CAPTURE, ALIGNMENT_THRESHOLD_GOOD, ALIGNMENT_THRESHOLD_PERFECT, ALIGNMENT_THRESHOLD_POOR, API_ENDPOINTS, API_ERROR_CODES, API_PATHS, AUTH_CONFIG, type ApiErrorCode, BACKLIT_RATIO_THRESHOLD, BLUR_THRESHOLD_MOBILE, BaseFrameCollector, type BlurAnalysis, CAMERA_ANGLE_HIGH_RATIO, CAMERA_ANGLE_LOW_RATIO, type CameraAngleResult, type CaptureQualityState, type CapturedFrame, type CropData, DEFAULT_BLUR_THRESHOLD, DEFAULT_ENDPOINT, DEFAULT_FACE_DETECTION_TIERS, DEFAULT_GAZE_THRESHOLDS, DEFAULT_HAND_OCCLUSION_CONFIG, DEFAULT_LIVENESS_CONFIG, DEFAULT_LOCALE, DEFAULT_OVAL_REGION, DEFAULT_STABILIZER_CONFIG, DEFAULT_STATUS_MESSAGES, type DeprecationInfo, type DetectionResult, type DetectionSummary, type DetectorConfig, ERROR_MESSAGES, ERROR_MESSAGES_ES, ES_LOCALE, EYE_LANDMARK_INDICES, EYE_QUALITY_THRESHOLDS, type ErrorResponse, type EyeQualityThresholds, type EyeRegionBounds, type EyeRegionQuality, type EyeRegionsBounds, FACE_CENTER_VERTICAL_OFFSET, FACE_CROP_OUTPUT_SIZE, FEEDBACK_MESSAGES, FRAME_BUFFER_CONFIG, FRAME_CONFIG, type FaceAlignmentResult, type FaceBoundingBox, type FaceDetectionTiers, type FaceInOvalResult, type FaceLandmarkPoint, type FaceRollResult, type FaceVisibilityResult, type FastCheckCropsRequest, type FastCheckModel, type FastCheckRequest, type FastCheckResponse, type FastCheckStreamRequest, type FastCheckStreamResponse, type FeedbackLocale, type FeedbackMessageKey, type Frame, FrameBuffer, type FrameData, type FrameQualityResult, FrameQueue, type FrameSource, GOOD_ALIGNMENT, type GazeThresholds, HIGH_ALIGNMENT, HYBRID_MODEL_CONFIGS, type HandOcclusionConfig, type HeadPose, type HealthResponse, type Hybrid150CheckRequest, type Hybrid50CheckRequest, type HybridCheckRequest, type HybridCheckResponse, type HybridFrameData, type HybridModelConfig, IDEAL_CROP_MULTIPLIER, type JobStatus, type JobStatusResponse, LANDMARK_INDEX, LANDMARK_MAX_BOUND, LANDMARK_MIN_BOUND, LOW_LIGHT_THRESHOLD, type LandmarkValidationResult, type LightingAnalysis, LivenessApiError, type LivenessCallbacks, LivenessClient, type LivenessClientConfig, type LivenessConfig, type LivenessResult, type LivenessState, MAX_CROP_MULTIPLIER, MAX_FACE_PERCENTAGE_IN_CROP, MAX_FACE_RATIO, MAX_FACE_ROLL_DEGREES, MAX_IDEAL_FACE_RATIO, MIN_CAPTURE_ALIGNMENT, MIN_CROP_MULTIPLIER, MIN_FACE_AREA_RATIO, MIN_FACE_BOTTOM_MARGIN, MIN_FACE_RATIO, MIN_FACE_SIDE_MARGIN, MIN_FACE_TOP_MARGIN, MIN_IDEAL_FACE_RATIO, MIN_LANDMARK_COUNT, MODEL_CONFIGS, type ModelConfig, type ModelEntry, type ModelType, type ModelVersion, type ModelsResponse, OVAL_GUIDE_COLORS, OVAL_GUIDE_STYLES, OVAL_REGION_DESKTOP, OVAL_REGION_MOBILE, type OnErrorCallback, type OnFrameCapturedCallback, type OnProgressCallback, type OnResultCallback, type OnStateChangeCallback, type OvalGuideState, type OvalRegion, type QueueStatsResponse, RETRY_CONFIG, type RetryOptions, type StabilizationProgress, type StabilizationResult, type StabilizerConfig, type StatusMessageKey, type StreamingStatus, TARGET_FACE_PERCENTAGE_IN_CROP, VALID_FRAME_COUNTS, type Verdict, type VerifyRequest, type VerifyResponse, type VideoFrameMetadata, analyzeBlur, analyzeEyeRegionBrightness, analyzeEyeRegionContrast, analyzeLighting, calculateAdaptiveCropMultiplier, calculateBrightness, calculateFaceAlignment, calculateFaceCropRegion, canCaptureFrame, checkEyeRegionQuality, checkFrameQuality, decodeBase64, detectCameraAngle, detectFaceRoll, detectSpecularHighlights, encodeBase64, generateSessionId, getActiveModels, getApiErrorMessage, getCaptureQualityFeedback, getEyeRegionBounds, getFeedbackMessage, getMinFramesForModel, getOvalGuideState, getStatusMessage, hasEnoughFrames, isDeprecatedModel, isFaceCropFullyInFrame, isFaceFullyVisible, isFaceInOval, isRetryableError, retryWithBackoff, rgbaToGrayscale, sleep, toFrameData, toHybridFrameData, toLivenessResult, toLivenessResultFromStream, validateApiKey, validateFaceLandmarks, validateFrameCount, validateFrameData, validateFrameIndex, validateTimestamp, validateUUID, validateUrl };
|
|
852
|
+
export { ALIGNMENT_THRESHOLD_CAPTURE, ALIGNMENT_THRESHOLD_GOOD, ALIGNMENT_THRESHOLD_PERFECT, ALIGNMENT_THRESHOLD_POOR, API_ENDPOINTS, API_ERROR_CODES, API_PATHS, AUTH_CONFIG, type ApiErrorCode, BACKLIT_RATIO_THRESHOLD, BLUR_THRESHOLD_MOBILE, BaseFrameCollector, type BlurAnalysis, CAMERA_ANGLE_HIGH_RATIO, CAMERA_ANGLE_LOW_RATIO, type CameraAngleResult, type CaptureQualityState, type CapturedFrame, type CropData, DEFAULT_BLUR_THRESHOLD, DEFAULT_ENDPOINT, DEFAULT_FACE_DETECTION_TIERS, DEFAULT_GAZE_THRESHOLDS, DEFAULT_HAND_OCCLUSION_CONFIG, DEFAULT_LIVENESS_CONFIG, DEFAULT_LOCALE, DEFAULT_OVAL_REGION, DEFAULT_STABILIZER_CONFIG, DEFAULT_STATUS_MESSAGES, DYNAMIC_RANGE_WARNING_THRESHOLD, type DeprecationInfo, type DetectionResult, type DetectionSummary, type DetectorConfig, type DynamicRangeAnalysis, ERROR_MESSAGES, ERROR_MESSAGES_ES, ES_LOCALE, EYE_LANDMARK_INDICES, EYE_QUALITY_THRESHOLDS, type ErrorResponse, type EyeQualityThresholds, type EyeRegionBounds, type EyeRegionQuality, type EyeRegionsBounds, FACE_CENTER_VERTICAL_OFFSET, FACE_CROP_OUTPUT_SIZE, FEEDBACK_MESSAGES, FRAME_BUFFER_CONFIG, FRAME_CONFIG, type FaceAlignmentResult, type FaceBoundingBox, type FaceDetectionTiers, type FaceInOvalResult, type FaceLandmarkPoint, type FaceRollResult, type FaceVisibilityResult, type FastCheckCropsRequest, type FastCheckModel, type FastCheckRequest, type FastCheckResponse, type FastCheckStreamRequest, type FastCheckStreamResponse, type FeedbackLocale, type FeedbackMessageKey, type Frame, FrameBuffer, type FrameData, type FrameQualityResult, FrameQueue, type FrameSource, GOOD_ALIGNMENT, type GazeThresholds, HIGH_ALIGNMENT, HYBRID_MODEL_CONFIGS, type HandOcclusionConfig, type HeadPose, type HealthResponse, type Hybrid150CheckRequest, type Hybrid50CheckRequest, type HybridCheckRequest, type HybridCheckResponse, type HybridFrameData, type HybridModelConfig, IDEAL_CROP_MULTIPLIER, type JobStatus, type JobStatusResponse, LANDMARK_INDEX, LANDMARK_MAX_BOUND, LANDMARK_MIN_BOUND, LOW_LIGHT_THRESHOLD, type LandmarkValidationResult, type LightingAnalysis, LivenessApiError, type LivenessCallbacks, LivenessClient, type LivenessClientConfig, type LivenessConfig, type LivenessResult, type LivenessState, MAX_CROP_MULTIPLIER, MAX_FACE_PERCENTAGE_IN_CROP, MAX_FACE_RATIO, MAX_FACE_ROLL_DEGREES, MAX_IDEAL_FACE_RATIO, MIN_CAPTURE_ALIGNMENT, MIN_CROP_MULTIPLIER, MIN_FACE_AREA_RATIO, MIN_FACE_BOTTOM_MARGIN, MIN_FACE_RATIO, MIN_FACE_SIDE_MARGIN, MIN_FACE_TOP_MARGIN, MIN_IDEAL_FACE_RATIO, MIN_LANDMARK_COUNT, MODEL_CONFIGS, type ModelConfig, type ModelEntry, type ModelType, type ModelVersion, type ModelsResponse, OVAL_GUIDE_COLORS, OVAL_GUIDE_STYLES, OVAL_REGION_DESKTOP, OVAL_REGION_MOBILE, type OnErrorCallback, type OnFrameCapturedCallback, type OnProgressCallback, type OnResultCallback, type OnStateChangeCallback, type OvalGuideState, type OvalRegion, type QueueStatsResponse, RETRY_CONFIG, type RetryOptions, type StabilizationProgress, type StabilizationResult, type StabilizerConfig, type StatusMessageKey, type StreamingStatus, TARGET_FACE_PERCENTAGE_IN_CROP, VALID_FRAME_COUNTS, type Verdict, type VerifyRequest, type VerifyResponse, type VideoFrameMetadata, analyzeBlur, analyzeDynamicRange, analyzeEyeRegionBrightness, analyzeEyeRegionContrast, analyzeLighting, calculateAdaptiveCropMultiplier, calculateBrightness, calculateFaceAlignment, calculateFaceCropRegion, canCaptureFrame, checkEyeRegionQuality, checkFrameQuality, decodeBase64, detectCameraAngle, detectFaceRoll, detectFaceRollFromMatrix, detectSpecularHighlights, encodeBase64, generateSessionId, getActiveModels, getApiErrorMessage, getCaptureQualityFeedback, getEyeRegionBounds, getFeedbackMessage, getMinFramesForModel, getOvalGuideState, getStatusMessage, hasEnoughFrames, isDeprecatedModel, isFaceCropFullyInFrame, isFaceFullyVisible, isFaceInOval, isRetryableError, linearRgbToLabL, retryWithBackoff, rgbaToGrayscale, sleep, srgbToLinear, toFrameData, toHybridFrameData, toLivenessResult, toLivenessResultFromStream, validateApiKey, validateFaceLandmarks, validateFrameCount, validateFrameData, validateFrameIndex, validateTimestamp, validateUUID, validateUrl };
|
package/dist/index.js
CHANGED
|
@@ -43,6 +43,7 @@ __export(index_exports, {
|
|
|
43
43
|
DEFAULT_OVAL_REGION: () => DEFAULT_OVAL_REGION,
|
|
44
44
|
DEFAULT_STABILIZER_CONFIG: () => DEFAULT_STABILIZER_CONFIG,
|
|
45
45
|
DEFAULT_STATUS_MESSAGES: () => DEFAULT_STATUS_MESSAGES,
|
|
46
|
+
DYNAMIC_RANGE_WARNING_THRESHOLD: () => DYNAMIC_RANGE_WARNING_THRESHOLD,
|
|
46
47
|
ERROR_MESSAGES: () => ERROR_MESSAGES,
|
|
47
48
|
ERROR_MESSAGES_ES: () => ERROR_MESSAGES_ES,
|
|
48
49
|
ES_LOCALE: () => ES_LOCALE,
|
|
@@ -88,6 +89,7 @@ __export(index_exports, {
|
|
|
88
89
|
TARGET_FACE_PERCENTAGE_IN_CROP: () => TARGET_FACE_PERCENTAGE_IN_CROP,
|
|
89
90
|
VALID_FRAME_COUNTS: () => VALID_FRAME_COUNTS,
|
|
90
91
|
analyzeBlur: () => analyzeBlur,
|
|
92
|
+
analyzeDynamicRange: () => analyzeDynamicRange,
|
|
91
93
|
analyzeEyeRegionBrightness: () => analyzeEyeRegionBrightness,
|
|
92
94
|
analyzeEyeRegionContrast: () => analyzeEyeRegionContrast,
|
|
93
95
|
analyzeLighting: () => analyzeLighting,
|
|
@@ -101,6 +103,7 @@ __export(index_exports, {
|
|
|
101
103
|
decodeBase64: () => decodeBase64,
|
|
102
104
|
detectCameraAngle: () => detectCameraAngle,
|
|
103
105
|
detectFaceRoll: () => detectFaceRoll,
|
|
106
|
+
detectFaceRollFromMatrix: () => detectFaceRollFromMatrix,
|
|
104
107
|
detectSpecularHighlights: () => detectSpecularHighlights,
|
|
105
108
|
encodeBase64: () => encodeBase64,
|
|
106
109
|
generateSessionId: () => generateSessionId,
|
|
@@ -118,9 +121,11 @@ __export(index_exports, {
|
|
|
118
121
|
isFaceFullyVisible: () => isFaceFullyVisible,
|
|
119
122
|
isFaceInOval: () => isFaceInOval,
|
|
120
123
|
isRetryableError: () => isRetryableError,
|
|
124
|
+
linearRgbToLabL: () => linearRgbToLabL,
|
|
121
125
|
retryWithBackoff: () => retryWithBackoff,
|
|
122
126
|
rgbaToGrayscale: () => rgbaToGrayscale,
|
|
123
127
|
sleep: () => sleep,
|
|
128
|
+
srgbToLinear: () => srgbToLinear,
|
|
124
129
|
toFrameData: () => toFrameData,
|
|
125
130
|
toHybridFrameData: () => toHybridFrameData,
|
|
126
131
|
toLivenessResult: () => toLivenessResult,
|
|
@@ -1376,6 +1381,7 @@ var FEEDBACK_MESSAGES = {
|
|
|
1376
1381
|
poor_lighting: "Improve lighting",
|
|
1377
1382
|
too_dark: "Low lighting - move to a brighter area",
|
|
1378
1383
|
backlit: "Backlit - try facing the light source",
|
|
1384
|
+
flat_lighting: "Find better lighting",
|
|
1379
1385
|
// Camera angle (platform-agnostic)
|
|
1380
1386
|
camera_angle_low: "Raise camera to eye level",
|
|
1381
1387
|
camera_angle_high: "Lower camera to eye level",
|
|
@@ -1439,6 +1445,7 @@ var ES_LOCALE = {
|
|
|
1439
1445
|
poor_lighting: "Mejora la iluminaci\xF3n",
|
|
1440
1446
|
too_dark: "Poca luz - mu\xE9vete a un \xE1rea m\xE1s iluminada",
|
|
1441
1447
|
backlit: "Contraluz - intenta mirar hacia la fuente de luz",
|
|
1448
|
+
flat_lighting: "Busca mejor iluminaci\xF3n",
|
|
1442
1449
|
// Camera angle (platform-agnostic)
|
|
1443
1450
|
camera_angle_low: "Levanta la c\xE1mara a la altura de los ojos",
|
|
1444
1451
|
camera_angle_high: "Baja la c\xE1mara a la altura de los ojos",
|
|
@@ -1481,7 +1488,8 @@ function getCaptureQualityFeedback(state) {
|
|
|
1481
1488
|
cameraAngleLow,
|
|
1482
1489
|
cameraAngleHigh,
|
|
1483
1490
|
cameraTilted,
|
|
1484
|
-
faceAreaLow
|
|
1491
|
+
faceAreaLow,
|
|
1492
|
+
dynamicRangeLow
|
|
1485
1493
|
} = state;
|
|
1486
1494
|
if (!hasFace) {
|
|
1487
1495
|
return FEEDBACK_MESSAGES.no_face;
|
|
@@ -1507,6 +1515,9 @@ function getCaptureQualityFeedback(state) {
|
|
|
1507
1515
|
if (isBlurry) {
|
|
1508
1516
|
return FEEDBACK_MESSAGES.blurry;
|
|
1509
1517
|
}
|
|
1518
|
+
if (dynamicRangeLow) {
|
|
1519
|
+
return FEEDBACK_MESSAGES.flat_lighting;
|
|
1520
|
+
}
|
|
1510
1521
|
if (tooFarFromIdeal) {
|
|
1511
1522
|
return FEEDBACK_MESSAGES.move_closer_ideal;
|
|
1512
1523
|
}
|
|
@@ -1631,6 +1642,33 @@ var MAX_FACE_RATIO = 0.7;
|
|
|
1631
1642
|
var FACE_CROP_OUTPUT_SIZE = 224;
|
|
1632
1643
|
var MAX_FACE_PERCENTAGE_IN_CROP = 0.45;
|
|
1633
1644
|
var TARGET_FACE_PERCENTAGE_IN_CROP = 0.33;
|
|
1645
|
+
var DYNAMIC_RANGE_WARNING_THRESHOLD = 180;
|
|
1646
|
+
function srgbToLinear(c) {
|
|
1647
|
+
const n = c / 255;
|
|
1648
|
+
return n <= 0.04045 ? n / 12.92 : Math.pow((n + 0.055) / 1.055, 2.4);
|
|
1649
|
+
}
|
|
1650
|
+
function linearRgbToLabL(rLin, gLin, bLin) {
|
|
1651
|
+
const Y = 0.2126 * rLin + 0.7152 * gLin + 0.0722 * bLin;
|
|
1652
|
+
const f = Y > 8856e-6 ? Math.cbrt(Y) : 7.787 * Y + 16 / 116;
|
|
1653
|
+
return 116 * f - 16;
|
|
1654
|
+
}
|
|
1655
|
+
function analyzeDynamicRange(rgbaPixels) {
|
|
1656
|
+
let minL = Infinity;
|
|
1657
|
+
let maxL = -Infinity;
|
|
1658
|
+
for (let i = 0; i < rgbaPixels.length; i += 4) {
|
|
1659
|
+
const r = rgbaPixels[i] ?? 0;
|
|
1660
|
+
const g = rgbaPixels[i + 1] ?? 0;
|
|
1661
|
+
const b = rgbaPixels[i + 2] ?? 0;
|
|
1662
|
+
const L = linearRgbToLabL(srgbToLinear(r), srgbToLinear(g), srgbToLinear(b));
|
|
1663
|
+
if (L < minL) minL = L;
|
|
1664
|
+
if (L > maxL) maxL = L;
|
|
1665
|
+
}
|
|
1666
|
+
if (!isFinite(minL) || !isFinite(maxL)) {
|
|
1667
|
+
return { range: 0, isLow: false };
|
|
1668
|
+
}
|
|
1669
|
+
const range = maxL - minL;
|
|
1670
|
+
return { range, isLow: range < DYNAMIC_RANGE_WARNING_THRESHOLD };
|
|
1671
|
+
}
|
|
1634
1672
|
function analyzeBlur(grayscalePixels, width, height, threshold = DEFAULT_BLUR_THRESHOLD) {
|
|
1635
1673
|
const laplacian = [];
|
|
1636
1674
|
for (let y = 1; y < height - 1; y++) {
|
|
@@ -1911,6 +1949,21 @@ function detectFaceRoll(landmarks) {
|
|
|
1911
1949
|
tooTilted: roll > MAX_FACE_ROLL_DEGREES
|
|
1912
1950
|
};
|
|
1913
1951
|
}
|
|
1952
|
+
function detectFaceRollFromMatrix(matrix) {
|
|
1953
|
+
if (matrix.length < 9) {
|
|
1954
|
+
return { roll: 0, tooTilted: false };
|
|
1955
|
+
}
|
|
1956
|
+
const m4 = matrix[4];
|
|
1957
|
+
const m5 = matrix[5];
|
|
1958
|
+
if (m4 === void 0 || m5 === void 0) {
|
|
1959
|
+
return { roll: 0, tooTilted: false };
|
|
1960
|
+
}
|
|
1961
|
+
const roll = Math.abs(Math.atan2(m4, m5) * (180 / Math.PI));
|
|
1962
|
+
return {
|
|
1963
|
+
roll,
|
|
1964
|
+
tooTilted: roll > MAX_FACE_ROLL_DEGREES
|
|
1965
|
+
};
|
|
1966
|
+
}
|
|
1914
1967
|
var CAMERA_ANGLE_HIGH_RATIO = 1.35;
|
|
1915
1968
|
var CAMERA_ANGLE_LOW_RATIO = 0.75;
|
|
1916
1969
|
function detectCameraAngle(landmarks) {
|
|
@@ -2164,6 +2217,7 @@ function checkEyeRegionQuality(pixels, thresholds = EYE_QUALITY_THRESHOLDS) {
|
|
|
2164
2217
|
DEFAULT_OVAL_REGION,
|
|
2165
2218
|
DEFAULT_STABILIZER_CONFIG,
|
|
2166
2219
|
DEFAULT_STATUS_MESSAGES,
|
|
2220
|
+
DYNAMIC_RANGE_WARNING_THRESHOLD,
|
|
2167
2221
|
ERROR_MESSAGES,
|
|
2168
2222
|
ERROR_MESSAGES_ES,
|
|
2169
2223
|
ES_LOCALE,
|
|
@@ -2209,6 +2263,7 @@ function checkEyeRegionQuality(pixels, thresholds = EYE_QUALITY_THRESHOLDS) {
|
|
|
2209
2263
|
TARGET_FACE_PERCENTAGE_IN_CROP,
|
|
2210
2264
|
VALID_FRAME_COUNTS,
|
|
2211
2265
|
analyzeBlur,
|
|
2266
|
+
analyzeDynamicRange,
|
|
2212
2267
|
analyzeEyeRegionBrightness,
|
|
2213
2268
|
analyzeEyeRegionContrast,
|
|
2214
2269
|
analyzeLighting,
|
|
@@ -2222,6 +2277,7 @@ function checkEyeRegionQuality(pixels, thresholds = EYE_QUALITY_THRESHOLDS) {
|
|
|
2222
2277
|
decodeBase64,
|
|
2223
2278
|
detectCameraAngle,
|
|
2224
2279
|
detectFaceRoll,
|
|
2280
|
+
detectFaceRollFromMatrix,
|
|
2225
2281
|
detectSpecularHighlights,
|
|
2226
2282
|
encodeBase64,
|
|
2227
2283
|
generateSessionId,
|
|
@@ -2239,9 +2295,11 @@ function checkEyeRegionQuality(pixels, thresholds = EYE_QUALITY_THRESHOLDS) {
|
|
|
2239
2295
|
isFaceFullyVisible,
|
|
2240
2296
|
isFaceInOval,
|
|
2241
2297
|
isRetryableError,
|
|
2298
|
+
linearRgbToLabL,
|
|
2242
2299
|
retryWithBackoff,
|
|
2243
2300
|
rgbaToGrayscale,
|
|
2244
2301
|
sleep,
|
|
2302
|
+
srgbToLinear,
|
|
2245
2303
|
toFrameData,
|
|
2246
2304
|
toHybridFrameData,
|
|
2247
2305
|
toLivenessResult,
|
package/dist/index.mjs
CHANGED
|
@@ -1238,6 +1238,7 @@ var FEEDBACK_MESSAGES = {
|
|
|
1238
1238
|
poor_lighting: "Improve lighting",
|
|
1239
1239
|
too_dark: "Low lighting - move to a brighter area",
|
|
1240
1240
|
backlit: "Backlit - try facing the light source",
|
|
1241
|
+
flat_lighting: "Find better lighting",
|
|
1241
1242
|
// Camera angle (platform-agnostic)
|
|
1242
1243
|
camera_angle_low: "Raise camera to eye level",
|
|
1243
1244
|
camera_angle_high: "Lower camera to eye level",
|
|
@@ -1301,6 +1302,7 @@ var ES_LOCALE = {
|
|
|
1301
1302
|
poor_lighting: "Mejora la iluminaci\xF3n",
|
|
1302
1303
|
too_dark: "Poca luz - mu\xE9vete a un \xE1rea m\xE1s iluminada",
|
|
1303
1304
|
backlit: "Contraluz - intenta mirar hacia la fuente de luz",
|
|
1305
|
+
flat_lighting: "Busca mejor iluminaci\xF3n",
|
|
1304
1306
|
// Camera angle (platform-agnostic)
|
|
1305
1307
|
camera_angle_low: "Levanta la c\xE1mara a la altura de los ojos",
|
|
1306
1308
|
camera_angle_high: "Baja la c\xE1mara a la altura de los ojos",
|
|
@@ -1343,7 +1345,8 @@ function getCaptureQualityFeedback(state) {
|
|
|
1343
1345
|
cameraAngleLow,
|
|
1344
1346
|
cameraAngleHigh,
|
|
1345
1347
|
cameraTilted,
|
|
1346
|
-
faceAreaLow
|
|
1348
|
+
faceAreaLow,
|
|
1349
|
+
dynamicRangeLow
|
|
1347
1350
|
} = state;
|
|
1348
1351
|
if (!hasFace) {
|
|
1349
1352
|
return FEEDBACK_MESSAGES.no_face;
|
|
@@ -1369,6 +1372,9 @@ function getCaptureQualityFeedback(state) {
|
|
|
1369
1372
|
if (isBlurry) {
|
|
1370
1373
|
return FEEDBACK_MESSAGES.blurry;
|
|
1371
1374
|
}
|
|
1375
|
+
if (dynamicRangeLow) {
|
|
1376
|
+
return FEEDBACK_MESSAGES.flat_lighting;
|
|
1377
|
+
}
|
|
1372
1378
|
if (tooFarFromIdeal) {
|
|
1373
1379
|
return FEEDBACK_MESSAGES.move_closer_ideal;
|
|
1374
1380
|
}
|
|
@@ -1493,6 +1499,33 @@ var MAX_FACE_RATIO = 0.7;
|
|
|
1493
1499
|
var FACE_CROP_OUTPUT_SIZE = 224;
|
|
1494
1500
|
var MAX_FACE_PERCENTAGE_IN_CROP = 0.45;
|
|
1495
1501
|
var TARGET_FACE_PERCENTAGE_IN_CROP = 0.33;
|
|
1502
|
+
var DYNAMIC_RANGE_WARNING_THRESHOLD = 180;
|
|
1503
|
+
function srgbToLinear(c) {
|
|
1504
|
+
const n = c / 255;
|
|
1505
|
+
return n <= 0.04045 ? n / 12.92 : Math.pow((n + 0.055) / 1.055, 2.4);
|
|
1506
|
+
}
|
|
1507
|
+
function linearRgbToLabL(rLin, gLin, bLin) {
|
|
1508
|
+
const Y = 0.2126 * rLin + 0.7152 * gLin + 0.0722 * bLin;
|
|
1509
|
+
const f = Y > 8856e-6 ? Math.cbrt(Y) : 7.787 * Y + 16 / 116;
|
|
1510
|
+
return 116 * f - 16;
|
|
1511
|
+
}
|
|
1512
|
+
function analyzeDynamicRange(rgbaPixels) {
|
|
1513
|
+
let minL = Infinity;
|
|
1514
|
+
let maxL = -Infinity;
|
|
1515
|
+
for (let i = 0; i < rgbaPixels.length; i += 4) {
|
|
1516
|
+
const r = rgbaPixels[i] ?? 0;
|
|
1517
|
+
const g = rgbaPixels[i + 1] ?? 0;
|
|
1518
|
+
const b = rgbaPixels[i + 2] ?? 0;
|
|
1519
|
+
const L = linearRgbToLabL(srgbToLinear(r), srgbToLinear(g), srgbToLinear(b));
|
|
1520
|
+
if (L < minL) minL = L;
|
|
1521
|
+
if (L > maxL) maxL = L;
|
|
1522
|
+
}
|
|
1523
|
+
if (!isFinite(minL) || !isFinite(maxL)) {
|
|
1524
|
+
return { range: 0, isLow: false };
|
|
1525
|
+
}
|
|
1526
|
+
const range = maxL - minL;
|
|
1527
|
+
return { range, isLow: range < DYNAMIC_RANGE_WARNING_THRESHOLD };
|
|
1528
|
+
}
|
|
1496
1529
|
function analyzeBlur(grayscalePixels, width, height, threshold = DEFAULT_BLUR_THRESHOLD) {
|
|
1497
1530
|
const laplacian = [];
|
|
1498
1531
|
for (let y = 1; y < height - 1; y++) {
|
|
@@ -1773,6 +1806,21 @@ function detectFaceRoll(landmarks) {
|
|
|
1773
1806
|
tooTilted: roll > MAX_FACE_ROLL_DEGREES
|
|
1774
1807
|
};
|
|
1775
1808
|
}
|
|
1809
|
+
function detectFaceRollFromMatrix(matrix) {
|
|
1810
|
+
if (matrix.length < 9) {
|
|
1811
|
+
return { roll: 0, tooTilted: false };
|
|
1812
|
+
}
|
|
1813
|
+
const m4 = matrix[4];
|
|
1814
|
+
const m5 = matrix[5];
|
|
1815
|
+
if (m4 === void 0 || m5 === void 0) {
|
|
1816
|
+
return { roll: 0, tooTilted: false };
|
|
1817
|
+
}
|
|
1818
|
+
const roll = Math.abs(Math.atan2(m4, m5) * (180 / Math.PI));
|
|
1819
|
+
return {
|
|
1820
|
+
roll,
|
|
1821
|
+
tooTilted: roll > MAX_FACE_ROLL_DEGREES
|
|
1822
|
+
};
|
|
1823
|
+
}
|
|
1776
1824
|
var CAMERA_ANGLE_HIGH_RATIO = 1.35;
|
|
1777
1825
|
var CAMERA_ANGLE_LOW_RATIO = 0.75;
|
|
1778
1826
|
function detectCameraAngle(landmarks) {
|
|
@@ -2025,6 +2073,7 @@ export {
|
|
|
2025
2073
|
DEFAULT_OVAL_REGION,
|
|
2026
2074
|
DEFAULT_STABILIZER_CONFIG,
|
|
2027
2075
|
DEFAULT_STATUS_MESSAGES,
|
|
2076
|
+
DYNAMIC_RANGE_WARNING_THRESHOLD,
|
|
2028
2077
|
ERROR_MESSAGES,
|
|
2029
2078
|
ERROR_MESSAGES_ES,
|
|
2030
2079
|
ES_LOCALE,
|
|
@@ -2070,6 +2119,7 @@ export {
|
|
|
2070
2119
|
TARGET_FACE_PERCENTAGE_IN_CROP,
|
|
2071
2120
|
VALID_FRAME_COUNTS,
|
|
2072
2121
|
analyzeBlur,
|
|
2122
|
+
analyzeDynamicRange,
|
|
2073
2123
|
analyzeEyeRegionBrightness,
|
|
2074
2124
|
analyzeEyeRegionContrast,
|
|
2075
2125
|
analyzeLighting,
|
|
@@ -2083,6 +2133,7 @@ export {
|
|
|
2083
2133
|
decodeBase64,
|
|
2084
2134
|
detectCameraAngle,
|
|
2085
2135
|
detectFaceRoll,
|
|
2136
|
+
detectFaceRollFromMatrix,
|
|
2086
2137
|
detectSpecularHighlights,
|
|
2087
2138
|
encodeBase64,
|
|
2088
2139
|
generateSessionId,
|
|
@@ -2100,9 +2151,11 @@ export {
|
|
|
2100
2151
|
isFaceFullyVisible,
|
|
2101
2152
|
isFaceInOval,
|
|
2102
2153
|
isRetryableError,
|
|
2154
|
+
linearRgbToLabL,
|
|
2103
2155
|
retryWithBackoff,
|
|
2104
2156
|
rgbaToGrayscale,
|
|
2105
2157
|
sleep,
|
|
2158
|
+
srgbToLinear,
|
|
2106
2159
|
toFrameData,
|
|
2107
2160
|
toHybridFrameData,
|
|
2108
2161
|
toLivenessResult,
|