diff --git a/scripts/analyze.py b/scripts/analyze.py index d857345..02d3964 100644 --- a/scripts/analyze.py +++ b/scripts/analyze.py @@ -1,13 +1,17 @@ import json; +import sys; from deepface import DeepFace; -result = DeepFace.analyze( - img_path = "{{img_path}}", - actions={{actions}}, - enforce_detection={{enforce_detection}}, - detector_backend="{{detector_backend}}", - align={{align}}, - silent={{silent}}, -); - -print(json.dumps(result, default=str)) +try: + result = DeepFace.analyze( + img_path = "{{img_path}}", + actions={{actions}}, + enforce_detection={{enforce_detection}}, + anti_spoofing={{anti_spoofing}}, + detector_backend="{{detector_backend}}", + align={{align}}, + silent={{silent}}, + ); + print(json.dumps(result, default=str)) +except ValueError as e: + print(json.dumps({"error": str(e)}), file=sys.stderr) diff --git a/scripts/extract_faces.py b/scripts/extract_faces.py index 1b6eeba..e4fad15 100644 --- a/scripts/extract_faces.py +++ b/scripts/extract_faces.py @@ -1,13 +1,18 @@ import json; +import sys; from deepface import DeepFace; -result = DeepFace.extract_faces( - img_path = "{{img_path}}", - target_size={{target_size}}, - enforce_detection={{enforce_detection}}, - detector_backend="{{detector_backend}}", - align={{align}}, - grayscale={{grayscale}}, -); +try: + result = DeepFace.extract_faces( + img_path = "{{img_path}}", + target_size={{target_size}}, + enforce_detection={{enforce_detection}}, + anti_spoofing={{anti_spoofing}}, + detector_backend="{{detector_backend}}", + align={{align}}, + grayscale={{grayscale}}, + ); -print(json.dumps(result, default=str)) + print(json.dumps(result, default=str)) +except ValueError as e: + print(json.dumps({"error": str(e)}), file=sys.stderr) diff --git a/scripts/find.py b/scripts/find.py index 9b86f81..1dbf89d 100644 --- a/scripts/find.py +++ b/scripts/find.py @@ -1,15 +1,20 @@ from deepface import DeepFace; +import sys; -result = DeepFace.find( - img_path = "{{img_path}}", - db_path = "{{db_path}}", - model_name = "{{model_name}}", - distance_metric = "{{distance_metric}}", - enforce_detection = {{enforce_detection}}, - detector_backend = "{{detector_backend}}", - align = {{align}}, - normalization = "{{normalization}}", - silent = {{silent}} -); +try: + result = DeepFace.find( + img_path = "{{img_path}}", + db_path = "{{db_path}}", + model_name = "{{model_name}}", + distance_metric = "{{distance_metric}}", + enforce_detection = {{enforce_detection}}, + anti_spoofing={{anti_spoofing}}, + detector_backend = "{{detector_backend}}", + align = {{align}}, + normalization = "{{normalization}}", + silent = {{silent}} + ); -print(result[0].to_json()) + print(result[0].to_json()) +except ValueError as e: + print(json.dumps({"error": str(e)}), file=sys.stderr) diff --git a/scripts/represent.py b/scripts/represent.py index 06fa8a7..18855dc 100644 --- a/scripts/represent.py +++ b/scripts/represent.py @@ -1,13 +1,19 @@ import json; +import sys; from deepface import DeepFace; -result = DeepFace.represent( - img_path = "{{img_path}}", - model_name = "{{model_name}}", - enforce_detection = {{enforce_detection}}, - detector_backend = "{{detector_backend}}", - align = {{align}}, - normalization = "{{normalization}}" -); +try: + result = DeepFace.represent( + img_path = "{{img_path}}", + model_name = "{{model_name}}", + enforce_detection = {{enforce_detection}}, + anti_spoofing = "{{anti_spoofing}}", + detector_backend = "{{detector_backend}}", + align = {{align}}, + normalization = "{{normalization}}" + ); + + print(json.dumps(result, default=str)) +except ValueError as e: + print(json.dumps({"error": str(e)}), file=sys.stderr) -print(json.dumps(result, default=str)) diff --git a/scripts/verify.py b/scripts/verify.py index a674fbf..cd6d9ec 100644 --- a/scripts/verify.py +++ b/scripts/verify.py @@ -1,15 +1,20 @@ import json; +import sys; from deepface import DeepFace; -result = DeepFace.verify( - img1_path = "{{img1_path}}", - img2_path = "{{img2_path}}", - enforce_detection = {{enforce_detection}}, - align = {{align}}, - model_name = "{{model_name}}", - detector_backend = "{{detector_backend}}", - distance_metric = "{{distance_metric}}", - normalization = "{{normalization}}" -); +try: + result = DeepFace.verify( + img1_path = "{{img1_path}}", + img2_path = "{{img2_path}}", + enforce_detection = {{enforce_detection}}, + anti_spoofing={{anti_spoofing}}, + align = {{align}}, + model_name = "{{model_name}}", + detector_backend = "{{detector_backend}}", + distance_metric = "{{distance_metric}}", + normalization = "{{normalization}}" + ); -print(json.dumps(result, default=str)) + print(json.dumps(result, default=str)) +except ValueError as e: + print(json.dumps({"error": str(e)}), file=sys.stderr) diff --git a/src/Data/FacialArea.php b/src/Data/FacialArea.php index 523816c..8ef2c56 100644 --- a/src/Data/FacialArea.php +++ b/src/Data/FacialArea.php @@ -11,8 +11,8 @@ public function __construct( public readonly int $y, public readonly int $w, public readonly int $h, - public readonly ?int $left_eye, - public readonly ?int $right_eye, + public readonly int|array|null $left_eye, + public readonly int|array|null $right_eye, ) { } diff --git a/src/DeepFace.php b/src/DeepFace.php index 8b22204..265ada3 100644 --- a/src/DeepFace.php +++ b/src/DeepFace.php @@ -17,6 +17,7 @@ use Astrotomic\DeepFace\Enums\Gender; use Astrotomic\DeepFace\Enums\Normalization; use Astrotomic\DeepFace\Enums\Race; +use Astrotomic\DeepFace\Exceptions\DeepFaceException; use BadMethodCallException; use InvalidArgumentException; use SplFileInfo; @@ -54,6 +55,7 @@ public function verify( bool $enforce_detection = true, bool $align = true, Normalization $normalization = Normalization::BASE, + bool $anti_spoofing = false, ): VerifyResult { $img1 = new SplFileInfo($img1_path); $img2 = new SplFileInfo($img2_path); @@ -68,9 +70,10 @@ public function verify( $output = $this->run( filepath: __DIR__.'/../scripts/verify.py', data: [ - '{{img1_path}}' => $img1->getRealPath(), - '{{img2_path}}' => $img2->getRealPath(), + '{{img1_path}}' => str_replace('\\', '/', $img1->getRealPath()), + '{{img2_path}}' => str_replace('\\', '/', $img2->getRealPath()), '{{enforce_detection}}' => $enforce_detection ? 'True' : 'False', + '{{anti_spoofing}}' => $anti_spoofing ? 'True' : 'False', '{{align}}' => $align ? 'True' : 'False', '{{model_name}}' => $model_name->value, '{{detector_backend}}' => $detector_backend->value, @@ -80,7 +83,7 @@ public function verify( ); return new VerifyResult( - verified: $output['verified'] === 'True', + verified: $output['verified'], distance: $output['distance'], threshold: $output['threshold'], model: FaceRecognitionModel::from($output['model']), @@ -104,6 +107,7 @@ public function analyze( Detector $detector_backend = Detector::OPENCV, bool $align = true, bool $silent = false, + bool $anti_spoofing = false, ): array { $img = new SplFileInfo($img_path); @@ -123,9 +127,10 @@ public function analyze( $output = $this->run( filepath: __DIR__.'/../scripts/analyze.py', data: [ - '{{img_path}}' => $img->getRealPath(), + '{{img_path}}' => str_replace('\\', '/', $img->getRealPath()), '{{actions}}' => '['.implode(',', array_map(fn (AnalyzeAction $action) => "'{$action->value}'", $actions)).']', '{{enforce_detection}}' => $enforce_detection ? 'True' : 'False', + '{{anti_spoofing}}' => $anti_spoofing ? 'True' : 'False', '{{detector_backend}}' => $detector_backend->value, '{{align}}' => $align ? 'True' : 'False', '{{silent}}' => $silent ? 'True' : 'False', @@ -159,6 +164,7 @@ public function extractFaces( bool $enforce_detection = true, bool $align = true, bool $grayscale = false, + bool $anti_spoofing = false, ): array { $img = new SplFileInfo($img_path); @@ -169,9 +175,10 @@ public function extractFaces( $output = $this->run( filepath: __DIR__.'/../scripts/extract_faces.py', data: [ - '{{img_path}}' => $img->getRealPath(), + '{{img_path}}' => str_replace('\\', '/', $img->getRealPath()), '{{target_size}}' => '['.implode(',', $target_size).']', '{{enforce_detection}}' => $enforce_detection ? 'True' : 'False', + '{{anti_spoofing}}' => $anti_spoofing ? 'True' : 'False', '{{detector_backend}}' => $detector_backend->value, '{{align}}' => $align ? 'True' : 'False', '{{grayscale}}' => $grayscale ? 'True' : 'False', @@ -202,6 +209,7 @@ public function find( bool $align = true, Normalization $normalization = Normalization::BASE, bool $silent = false, + bool $anti_spoofing = false, ): array { $img = new SplFileInfo($img_path); $db = new SplFileInfo($db_path); @@ -217,11 +225,12 @@ public function find( $output = $this->run( filepath: __DIR__.'/../scripts/find.py', data: [ - '{{img_path}}' => $img->getRealPath(), + '{{img_path}}' => str_replace('\\', '/', $img->getRealPath()), '{{db_path}}' => $db->getRealPath(), '{{model_name}}' => $model_name->value, '{{distance_metric}}' => $distance_metric->value, '{{enforce_detection}}' => $enforce_detection ? 'True' : 'False', + '{{anti_spoofing}}' => $anti_spoofing ? 'True' : 'False', '{{detector_backend}}' => $detector_backend->value, '{{align}}' => $align ? 'True' : 'False', '{{normalization}}' => $normalization->value, @@ -239,6 +248,8 @@ public function find( y: $output['source_y'][$i], w: $output['source_w'][$i], h: $output['source_h'][$i], + left_eye: null, + right_eye: null ), model: $model_name, detector_backend: $detector_backend, @@ -260,6 +271,7 @@ public function represent( Detector $detector_backend = Detector::OPENCV, bool $align = true, Normalization $normalization = Normalization::BASE, + bool $anti_spoofing = false, ): array { $img = new SplFileInfo($img_path); @@ -270,9 +282,10 @@ public function represent( $output = $this->run( filepath: __DIR__.'/../scripts/represent.py', data: [ - '{{img_path}}' => $img->getRealPath(), + '{{img_path}}' => str_replace('\\', '/', $img->getRealPath()), '{{model_name}}' => $model_name->value, '{{enforce_detection}}' => $enforce_detection ? 'True' : 'False', + '{{anti_spoofing}}' => $anti_spoofing ? 'True' : 'False', '{{detector_backend}}' => $detector_backend->value, '{{align}}' => $align ? 'True' : 'False', '{{normalization}}' => $normalization->value, @@ -300,6 +313,21 @@ protected function run(string $filepath, array $data): array|bool ->mustRun() ->getOutput(); + $errorOutput = $process->getErrorOutput(); + + if(!empty($errorOutput)) { + if (preg_match_all('/\{(?:[^{}]|(?R))*\}/', $errorOutput, $matches)) { + $lastJson = end($matches[0]); + $errorResult = json_decode($lastJson, true); + + if ($errorResult !== null && isset($errorResult['error'])) { + throw new DeepFaceException($errorResult['error']); + } else { + throw new DeepFaceException("Failed to parse error message: " . $lastJson); + } + } + } + $lines = array_values(array_filter(explode(PHP_EOL, $output), function (string $line): bool { json_decode($line, true); diff --git a/src/Exceptions/DeepFaceException.php b/src/Exceptions/DeepFaceException.php new file mode 100644 index 0000000..ac34bb5 --- /dev/null +++ b/src/Exceptions/DeepFaceException.php @@ -0,0 +1,9 @@ +