You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, distanceThreshold = 0.5) {
/**
* Dynamically loads a script into the document head.
* @param {string} url The URL of the script to load.
* @returns {Promise<void>} A promise that resolves when the script has loaded.
*/
const loadScript = (url) => {
return new Promise((resolve, reject) => {
if (document.querySelector(`script[src="${url}"]`)) {
return resolve();
}
const script = document.createElement('script');
script.src = url;
script.onload = () => resolve();
script.onerror = (err) => reject(new Error(`Script load error for ${url}: ${err}`));
document.head.appendChild(script);
});
};
/**
* Loads the required face-api.js models.
* Uses a global promise to ensure models are only loaded once.
* @param {string} modelUrl The base URL where the models are located.
* @returns {Promise<void>} A promise that resolves when all models are loaded.
*/
const loadModels = (modelUrl) => {
if (!window.faceApiModelPromise) {
window.faceApiModelPromise = Promise.all([
faceapi.nets.ssdMobilenetv1.loadFromUri(modelUrl),
faceapi.nets.faceLandmark68Net.loadFromUri(modelUrl),
faceapi.nets.faceRecognitionNet.loadFromUri(modelUrl)
]);
}
return window.faceApiModelPromise;
};
/**
* Provides pre-computed face descriptors for a small set of known actresses.
* @returns {Array<faceapi.LabeledFaceDescriptors>}
*/
const getKnownActressesData = () => {
// NOTE: The following descriptor data is for demonstration purposes only.
// It is randomly generated and does not represent real biometric data of the individuals named.
// To build a real recognizer, you would need to generate these descriptors
// from multiple, high-quality, authorized images of each person using face-api.js.
const descriptors = {
"Emma Watson": [new Float32Array([-0.11, 0.05, 0.03, -0.07, -0.01, -0.05, -0.01, -0.13, 0.16, -0.07, 0.21, -0.06, -0.19, -0.1, -0.23, -0.02, -0.21, -0.28, -0.01, -0.09, 0.15, 0.08, -0.21, 0.03, -0.38, -0.25, -0.01, -0.01, 0.01, 0.04, -0.04, 0.04, 0.11, 0.06, 0.17, 0.03, 0.03, -0.03, -0.14, 0.07, -0.03, -0.05, 0.35, -0.11, -0.03, 0.17, -0.1, 0.05, 0.02, 0.1, 0.09, -0.05, -0.13, 0.08, -0.22, -0.03, 0.4, -0.03, -0.03, -0.02, -0.01, 0.12, 0.13, 0.02, -0.08, 0.09, -0.01, 0.02, -0.23, 0.08, -0.1, 0.18, 0.09, -0.02, 0.05, 0.03, -0.02, -0.04, -0.06, -0.13, 0.18, 0.17, 0.02, 0.08, -0.1, -0.1, 0.04, 0.19, -0.13, -0.16, 0.01, -0.05, 0.02, 0.09, 0.01, 0.1, 0.03, -0.11, 0.09, -0.08, 0.06, 0.13, -0.13, 0.16, 0.04, 0.17, 0.08, 0.02, -0.01, 0.02, -0.02, 0.03, 0.01, -0.19, 0.13, -0.03, -0.11, -0.03, -0.11, -0.05, -0.02, -0.07, 0.01, -0.03, 0.05, -0.08])],
"Scarlett Johansson": [new Float32Array([0.01, 0.08, 0.06, -0.03, -0.08, -0.02, -0.02, -0.08, 0.12, -0.18, 0.24, 0.03, -0.2, -0.01, -0.25, 0.12, -0.19, -0.28, 0.02, -0.12, 0.13, 0.01, -0.24, -0.09, -0.36, -0.23, 0.14, 0.05, -0.03, -0.05, -0.01, 0.03, 0.08, 0.01, 0.11, -0.03, 0.05, -0.06, -0.21, 0.03, 0.02, -0.01, 0.35, -0.15, -0.01, 0.11, -0.12, 0.01, -0.01, 0.12, 0.15, -0.03, -0.11, 0.01, -0.23, -0.08, 0.44, 0.01, -0.01, -0.1, -0.01, 0.11, 0.15, 0.02, -0.06, 0.12, -0.05, 0.01, -0.2, 0.01, -0.13, 0.15, 0.05, 0.02, 0.01, 0.01, -0.05, -0.01, -0.05, -0.15, 0.15, 0.15, -0.01, 0.05, -0.15, -0.08, 0.01, 0.15, -0.11, -0.15, -0.02, -0.03, 0.01, 0.15, 0.03, 0.09, 0.05, -0.15, 0.12, -0.05, 0.03, 0.11, -0.15, 0.13, 0.01, 0.15, 0.05, -0.02, 0.02, -0.01, -0.01, 0.05, 0.03, -0.16, 0.15, -0.01, -0.13, -0.05, -0.13, -0.03, 0.01, -0.05, 0.03, -0.01, 0.01, -0.05])],
"Natalie Portman": [new Float32Array([-0.01, 0.09, 0.07, -0.01, -0.03, -0.04, 0.01, -0.11, 0.14, -0.11, 0.22, -0.01, -0.22, -0.05, -0.24, 0.03, -0.2, -0.29, 0.01, -0.11, 0.14, 0.05, -0.23, 0.01, -0.39, -0.24, 0.04, -0.01, -0.01, 0.01, -0.03, 0.04, 0.1, 0.04, 0.14, 0.01, 0.04, -0.05, -0.16, 0.05, -0.01, -0.03, 0.36, -0.13, -0.02, 0.14, -0.11, 0.03, 0.01, 0.11, 0.12, -0.04, -0.12, 0.05, -0.23, -0.05, 0.41, -0.01, -0.02, -0.05, 0, 0.12, 0.14, 0.02, -0.07, 0.11, -0.03, 0.02, -0.22, 0.05, -0.11, 0.17, 0.07, 0, 0.03, 0.02, -0.03, -0.03, -0.06, -0.14, 0.17, 0.16, 0.01, 0.07, -0.12, -0.09, 0.03, 0.17, -0.12, -0.16, 0, -0.04, 0.02, 0.12, 0.02, 0.1, 0.04, -0.12, 0.1, -0.07, 0.05, 0.12, -0.14, 0.15, 0.03, 0.16, 0.07, 0, 0.01, 0.01, -0.01, 0.04, 0.02, -0.18, 0.14, -0.02, -0.12, -0.04, -0.12, -0.04, -0.01, -0.06, 0.02, -0.02, 0.03, -0.07])]
};
return Object.keys(descriptors).map(label => {
return new faceapi.LabeledFaceDescriptors(label, descriptors[label]);
});
};
try {
// Load face-api.js library
await loadScript('https://cdn.jsdelivr.net/npm/face-api.js');
// Load the models
const MODEL_URL = 'https://cdn.jsdelivr.net/npm/@vladmandic/face-api/model/';
await loadModels(MODEL_URL);
// Create a canvas to draw on
const canvas = document.createElement('canvas');
const displaySize = { width: originalImg.width, height: originalImg.height };
faceapi.matchDimensions(canvas, displaySize);
const ctx = canvas.getContext('2d');
ctx.drawImage(originalImg, 0, 0, displaySize.width, displaySize.height);
// Get known faces and create a matcher
const labeledFaceDescriptors = getKnownActressesData();
const faceMatcher = new faceapi.FaceMatcher(labeledFaceDescriptors, distanceThreshold);
// Detect all faces in the input image and compute their descriptors
const detections = await faceapi.detectAllFaces(originalImg)
.withFaceLandmarks()
.withFaceDescriptors();
if (!detections.length) {
ctx.font = "bold 20px Arial";
ctx.fillStyle = "red";
ctx.textAlign = "center";
ctx.fillText("No faces detected.", canvas.width / 2, canvas.height / 2);
return canvas;
}
// Resize the detection results to match the image dimensions
const resizedDetections = faceapi.resizeResults(detections, displaySize);
// Find the best match for each detected face and draw it on the canvas
resizedDetections.forEach(detection => {
const bestMatch = faceMatcher.findBestMatch(detection.descriptor);
const box = detection.detection.box;
const drawBox = new faceapi.draw.DrawBox(box, {
label: bestMatch.toString(),
boxColor: 'rgba(0, 255, 0, 1)',
drawLabelOptions: {
backgroundColor: 'rgba(0, 255, 0, 1)',
fontColor: 'white'
}
});
drawBox.draw(canvas);
});
// Return the canvas with the results
return canvas;
} catch (error) {
console.error("Error in processImage:", error);
// Return an element with an error message
const errorDiv = document.createElement('div');
errorDiv.style.color = 'red';
errorDiv.style.padding = '20px';
errorDiv.style.fontFamily = 'Arial, sans-serif';
errorDiv.innerText = `An error occurred during image processing: ${error.message}`;
return errorDiv;
}
}
Apply Changes