first commit

This commit is contained in:
2025-07-18 16:20:14 +07:00
commit 98af45c018
16382 changed files with 3148096 additions and 0 deletions

View File

@@ -0,0 +1,185 @@
<?php
use Montala\ResourceSpace\CommandPlaceholderArg;
/**
* Initialize facial recognition functionality.
*
* IMPORTANT: only one field can be setup for the annotation side and it also MUST be a dynamic keywords list
*
* @uses ps_value()
*
* @return boolean
*/
function initFacialRecognition()
{
global $facial_recognition_tag_field, $facial_recognition_face_recognizer_models_location, $annotate_enabled,
$annotate_fields;
if (!is_numeric($facial_recognition_tag_field) || 0 >= $facial_recognition_tag_field) {
return false;
}
if (!is_dir($facial_recognition_face_recognizer_models_location)) {
if (strpos($facial_recognition_face_recognizer_models_location, $GLOBALS["storagedir"]) === 0) {
// Create the directory as it is in the configured filestore
mkdir($facial_recognition_face_recognizer_models_location, 0777, true);
} else {
// Folder needs to be created by server admin
$error = str_replace(
["%variable","%path"],
["\$facial_recognition_face_recognizer_models_location", $facial_recognition_face_recognizer_models_location],
$GLOBALS["lang"]["error_invalid_path"]
);
if (PHP_SAPI == "cli") {
echo $error . PHP_EOL;
} else {
debug($error);
}
return false;
}
}
$facial_recognition_rtf_type = ps_value(
"SELECT `type` AS `value`
FROM resource_type_field
WHERE ref = ?
",
array("i",$facial_recognition_tag_field),
null,
"schema"
);
if (FIELD_TYPE_DYNAMIC_KEYWORDS_LIST != $facial_recognition_rtf_type) {
$error = str_replace(
["%variable","%type"],
["\$facial_recognition_tag_field", $GLOBALS["lang"]["fieldtype-dynamic_keywords_list"]],
$GLOBALS["lang"]["error_invalid_field_type"]
);
if (PHP_SAPI == "cli") {
echo $error . PHP_EOL;
} else {
debug($error);
}
return false;
}
$annotate_enabled = true;
$annotate_fields[] = $facial_recognition_tag_field;
return true;
}
/**
* Crops out a selected area of an image and makes it ready to be used by FaceRecognizer.
*
* Note: The selected area should follow the normalized coordinate system.
*
* @uses get_utility_path()
* @uses debug()
*
* @param string $image_path Path of the source image
* @param string $prepared_image_path Path of the prepared image
* @param float $x X position
* @param float $y Y position
* @param float $width Width
* @param float $height Height
* @param boolean $overwrite_existing Set to TRUE to overwrite existing prepared image (if any exists)
*
* @return boolean
*/
function prepareFaceImage($image_path, $prepared_image_path, $x, $y, $width, $height, $overwrite_existing = false)
{
if (!file_exists($image_path)) {
debug("FACIAL_RECOGNITION: Could not find image at '{$image_path}'");
return false;
}
// Use existing prepared image if one is found
if (!$overwrite_existing && file_exists($prepared_image_path)) {
return true;
}
// X, Y, width and height MUST be numeric
if (!is_numeric($x) || !is_numeric($y) || !is_numeric($width) || !is_numeric($height)) {
return false;
}
$convert_fullpath = get_utility_path('im-convert');
if (false === $convert_fullpath) {
debug('FACIAL_RECOGNITION: Could not find ImageMagick "convert" utility!');
return false;
}
list($image_width, $image_height) = getimagesize($image_path);
$image_path_escaped = escapeshellarg($image_path);
$prepared_image_path_escaped = escapeshellarg($prepared_image_path);
$x = escapeshellarg(round($x * $image_width, 0));
$y = escapeshellarg(round($y * $image_height, 0));
$width = escapeshellarg(round($width * $image_width, 0));
$height = escapeshellarg(round($height * $image_height, 0));
$cmd = $convert_fullpath;
$cmd .= " {$image_path_escaped} -colorspace gray -depth 8";
$cmd .= " -crop {$width}x{$height}+{$x}+{$y}";
$cmd .= " -resize 90x90\>";
$cmd .= " +repage {$prepared_image_path_escaped}";
if ('' !== run_command($cmd)) {
return false;
}
return true;
}
/**
* Use FaceRecognizer to predict the association between a face and a label (i.e person name)
*
* @param string $model_file_path Path to the FaceRecognizer model state file
* @param string $test_image_path Path to the prepared image we are testing
*
* @return boolean|array Return the label ID and probability on successful prediction or FALSE on error
*/
function faceRecognizerPredict($model_file_path, $test_image_path)
{
if (!file_exists($model_file_path)) {
debug("FACIAL_RECOGNITION: Could not find model at '{$model_file_path}'");
return false;
}
if (!file_exists($test_image_path)) {
debug("FACIAL_RECOGNITION: Could not find the test image at '{$test_image_path}'");
return false;
}
$python_fullpath = get_utility_path('python');
if (false === $python_fullpath) {
debug('FACIAL_RECOGNITION: Could not find Python!');
return false;
}
$faceRecognizer_path = __DIR__ . '/../lib/facial_recognition/faceRecognizer.py';
$cmdparams = [
'[MODEL_PATH]' => new CommandPlaceholderArg(
$model_file_path,
fn($p) => is_valid_rs_path($p,
[
$GLOBALS['storagedir'],
$GLOBALS['facial_recognition_face_recognizer_models_location'],
])
),
'[IMAGE_PATH]' => new CommandPlaceholderArg($test_image_path, 'is_valid_rs_path'),
];
$command = "{$python_fullpath} {$faceRecognizer_path} [MODEL_PATH] [IMAGE_PATH]";
$prediction = run_command($command, false, $cmdparams, 300);
$prediction = json_decode($prediction);
if (null === $prediction || 2 > count($prediction)) {
return false;
}
return $prediction;
}