Please bookmark this page to avoid losing your image tool!

Image Facial Recognition Filter Effect Tool

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
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!

Description

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.

Leave a Reply

Your email address will not be published. Required fields are marked *