You can edit the below JavaScript code to customize the image tool.
async function processImage(originalImg, pixelationBlockSize = 10, detectionConfidence = 0.5) {
// Helper to load scripts dynamically.
// Uses window properties to manage loading promises, ensuring scripts/models are fetched once.
function loadScript(src) {
window._scriptLoadingPromises = window._scriptLoadingPromises || {};
if (!window._scriptLoadingPromises[src]) {
window._scriptLoadingPromises[src] = new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = src;
script.async = true;
script.onload = resolve;
script.onerror = () => {
console.error(`Failed to load script: ${src}`);
delete window._scriptLoadingPromises[src]; // Allow retry on subsequent calls if needed
reject(new Error(`Failed to load script: ${src}`));
};
document.head.appendChild(script);
});
}
return window._scriptLoadingPromises[src];
}
async function loadFaceApiModel(modelName, weightsUrl) {
window._faceApiModelPromises = window._faceApiModelPromises || {};
if (!window._faceApiModelPromises[modelName]) {
console.log(`Loading face-api.js ${modelName} model...`);
if (!faceapi.nets[modelName]) {
console.error(`face-api.js model ${modelName} does not exist on faceapi.nets.`);
throw new Error(`face-api.js model ${modelName} does not exist on faceapi.nets.`);
}
window._faceApiModelPromises[modelName] = faceapi.nets[modelName]
.loadFromUri(weightsUrl)
.then(() => console.log(`face-api.js ${modelName} model loaded.`))
.catch(err => {
console.error(`Failed to load face-api.js ${modelName} model:`, err);
delete window._faceApiModelPromises[modelName]; // Allow retry
throw err; // Propagate error to be caught by caller
});
}
return window._faceApiModelPromises[modelName];
}
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Ensure originalImg is loaded before getting its dimensions
if (!originalImg.complete && originalImg.naturalWidth === 0) {
// If the image is not loaded, wait for it.
// This typically shouldn't happen if `originalImg` is from an `<img>` tag that has loaded,
// but is a safeguard.
await new Promise(resolve => {
originalImg.onload = resolve;
originalImg.onerror = () => {
console.error("Original image failed to load.");
resolve(); // Resolve anyway to return an empty/error canvas
};
});
}
canvas.width = originalImg.naturalWidth || originalImg.width;
canvas.height = originalImg.naturalHeight || originalImg.height;
if (canvas.width === 0 || canvas.height === 0) {
console.warn("Image has zero dimensions. Cannot process.");
return canvas; // Return empty canvas
}
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
let faces = [];
let useFallbackDetector = true; // Assume fallback unless built-in works
// Option 1: Use built-in FaceDetector API if available
if ('FaceDetector' in window) {
try {
console.log('Attempting to use built-in FaceDetector API.');
const faceDetector = new FaceDetector({ fastMode: true }); // fastMode for performance
const detectedBuiltInFaces = await faceDetector.detect(originalImg);
faces = detectedBuiltInFaces
.filter(face => face.boundingBox) // Ensure boundingBox exists
.map(face => ({ // Make a plain object copy
x: face.boundingBox.x,
y: face.boundingBox.y,
width: face.boundingBox.width,
height: face.boundingBox.height,
}));
console.log(`Built-in FaceDetector found ${faces.length} faces.`);
useFallbackDetector = false; // Built-in detector succeeded (even if 0 faces found)
} catch (error) {
console.warn('Built-in FaceDetector API failed. Error:', error);
// Fallback will be used as useFallbackDetector remains true
}
} else {
console.log('Built-in FaceDetector API not available.');
// Fallback will be used
}
// Option 2: Fallback to face-api.js if built-in FaceDetector is not available or errored
if (useFallbackDetector) {
console.log('Using face-api.js as fallback or primary detector.');
try {
const FACEAPI_SCRIPT_URL = 'https://cdn.jsdelivr.net/npm/face-api.js@0.22.2/dist/face-api.min.js';
const FACEAPI_WEIGHTS_URL = 'https://cdn.jsdelivr.net/npm/face-api.js@0.22.2/weights';
if (typeof faceapi === 'undefined') { // Load script only if faceapi is not global
await loadScript(FACEAPI_SCRIPT_URL);
}
// Load TinyFaceDetector model (fastest)
await loadFaceApiModel('tinyFaceDetector', FACEAPI_WEIGHTS_URL);
const options = new faceapi.TinyFaceDetectorOptions({
scoreThreshold: Math.max(0.01, Math.min(1.0, detectionConfidence)) // Clamp confidence to [0.01, 1.0]
});
const detectionsExternal = await faceapi.detectAllFaces(originalImg, options);
faces = detectionsExternal.map(det => {
const box = det.detection.box;
return { x: box.x, y: box.y, width: box.width, height: box.height };
});
console.log(`face-api.js found ${faces.length} faces.`);
} catch (libError) {
console.error('Error loading or using face-api.js:', libError);
// If face-api also fails, return canvas with original image (already drawn)
return canvas;
}
}
if (!faces || faces.length === 0) {
console.log('No faces detected by any method.');
return canvas; // Original image is already on the canvas
}
console.log(`Applying pixelation to ${faces.length} detected faces.`);
for (const face of faces) {
let { x, y, width, height } = face; // These are from detector, can be floats
// Normalize coordinates and dimensions
let fX = Math.max(0, Math.floor(x));
let fY = Math.max(0, Math.floor(y));
let fWidth = Math.max(1, Math.floor(width));
let fHeight = Math.max(1, Math.floor(height));
// Ensure face region is within canvas bounds
if (fX >= canvas.width || fY >= canvas.height) continue; // Face starts outside canvas
if (fX + fWidth > canvas.width) {
fWidth = canvas.width - fX;
}
if (fY + fHeight > canvas.height) {
fHeight = canvas.height - fY;
}
if (fWidth <= 0 || fHeight <= 0) continue; // Face has no valid area on canvas
const pBlockSize = Math.max(1, Math.floor(pixelationBlockSize));
// Calculate scaled dimensions for the pixelated version
const scaledWidth = Math.max(1, Math.ceil(fWidth / pBlockSize));
const scaledHeight = Math.max(1, Math.ceil(fHeight / pBlockSize));
// Use a temporary canvas for the pixelation effect
const tempPixelCanvas = document.createElement('canvas');
const tempPixelCtx = tempPixelCanvas.getContext('2d');
tempPixelCanvas.width = scaledWidth;
tempPixelCanvas.height = scaledHeight;
// Draw the face region from the main canvas onto the tiny_old temporary canvas
// Disabling image smoothing crucial for "pixel look" when downscaling.
tempPixelCtx.imageSmoothingEnabled = false;
tempPixelCtx.drawImage(
canvas, // Source: the main canvas which has the original image
fX, fY, fWidth, fHeight, // Source rectangle (face region on main canvas)
0, 0, scaledWidth, scaledHeight // Destination rectangle (entire tiny_old canvas)
);
// Now, draw the tiny_old, pixelated image from tempPixelCanvas back to the main canvas,
// scaling it up to the original face size.
// Disabling image smoothing is crucial for nearest-neighbor scaling (blocky look).
ctx.imageSmoothingEnabled = false;
ctx.drawImage(
tempPixelCanvas, // Source: the tiny_old pixelated canvas
0, 0, scaledWidth, scaledHeight, // Source rectangle (entire tiny_old canvas)
fX, fY, fWidth, fHeight // Destination rectangle (face region on main canvas)
);
// Reset image smoothing for any subsequent drawing operations (good practice)
ctx.imageSmoothingEnabled = true;
}
return canvas;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Image Facial Recognition Filter Effect Tool allows users to automatically detect faces in an image and apply a pixelation effect to the detected faces. This tool can be useful for preserving privacy in photos by obfuscating the faces, making it perfect for use cases such as sharing sensitive images on social media, presenting images in a public forum, or complying with privacy regulations when displaying images of individuals. The tool employs advanced facial recognition technology to accurately identify faces, ensuring effective application of the filter.