Please bookmark this page to avoid losing your image tool!

Image Face Recognition And Automatic Sorting By Person 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, distanceThreshold = "0.6") {
    // 1. Create the container element to return
    const container = document.createElement('div');
    container.style.fontFamily = 'system-ui, -apple-system, sans-serif';
    container.style.maxWidth = '800px';
    container.style.margin = '0 auto';
    container.style.padding = '20px';
    
    // Status display
    const statusDiv = document.createElement('div');
    statusDiv.style.padding = '15px';
    statusDiv.style.backgroundColor = '#e3f2fd';
    statusDiv.style.color = '#0d47a1';
    statusDiv.style.borderRadius = '5px';
    statusDiv.style.fontWeight = 'bold';
    statusDiv.innerText = 'Loading AI models... this might take a few moments on the first run.';
    container.appendChild(statusDiv);

    try {
        // 2. Load face-api.js dynamically if not present
        if (!window.faceapi) {
            const script = document.createElement('script');
            // Using the established face-api.js version
            script.src = 'https://cdn.jsdelivr.net/npm/face-api.js@0.22.2/dist/face-api.min.js';
            document.head.appendChild(script);
            await new Promise((resolve, reject) => {
                script.onload = resolve;
                script.onerror = () => reject(new Error("Failed to load face-api.js from CDN"));
            });
        }

        // 3. Load AI weights from an open CDN repository
        const MODEL_URL = 'https://cdn.jsdelivr.net/gh/justadudewhohacks/face-api.js@master/weights';
        
        await Promise.all([
            faceapi.nets.ssdMobilenetv1.loadFromUri(MODEL_URL),
            faceapi.nets.faceLandmark68Net.loadFromUri(MODEL_URL),
            faceapi.nets.faceRecognitionNet.loadFromUri(MODEL_URL)
        ]);

        statusDiv.innerText = 'Models loaded! Detecting and recognizing faces...';

        // 4. Perform face detection, landmark determination, and feature extraction (descriptors)
        const detections = await faceapi.detectAllFaces(originalImg)
            .withFaceLandmarks()
            .withFaceDescriptors();

        if (detections.length === 0) {
            statusDiv.style.backgroundColor = '#fff3cd';
            statusDiv.style.color = '#856404';
            statusDiv.innerText = 'No faces were detected in this image. Please try a different photo.';
            return container;
        }

        // 5. Cluster (Sort) faces by person using Euclidean distance
        const threshold = parseFloat(distanceThreshold) || 0.6;
        // Output array representing "folders" of people
        const personFolders = []; 

        for (const det of detections) {
            const box = det.detection.box;
            const descriptor = det.descriptor;

            // Crop face to its own canvas
            const faceCanvas = document.createElement('canvas');
            // Ensure crop respects image boundaries
            const startX = Math.max(0, box.x);
            const startY = Math.max(0, box.y);
            const width = Math.min(originalImg.width - startX, box.width);
            const height = Math.min(originalImg.height - startY, box.height);

            faceCanvas.width = width;
            faceCanvas.height = height;
            const ctx = faceCanvas.getContext('2d');
            ctx.drawImage(originalImg, startX, startY, width, height, 0, 0, width, height);

            // Check if this face matches an existing person group
            let matched = false;
            for (const folder of personFolders) {
                const distance = faceapi.euclideanDistance(descriptor, folder.descriptor);
                if (distance < threshold) {
                    folder.faces.push(faceCanvas);
                    matched = true;
                    break;
                }
            }

            // If no match found, create a new person folder
            if (!matched) {
                personFolders.push({
                    descriptor: descriptor, 
                    faces: [faceCanvas]
                });
            }
        }

        // 6. Build the UI representing automatic sorting and folder grouping
        statusDiv.style.display = 'none'; // Hide loading state
        
        const header = document.createElement('div');
        header.style.marginBottom = '20px';
        header.innerHTML = `<h2 style="margin-bottom:5px;">Sorting Results</h2>
                            <p style="color:#555; margin-top:0;">Detected <strong>${detections.length}</strong> total faces, classified into <strong>${personFolders.length}</strong> unique people.</p>`;
        container.appendChild(header);

        personFolders.forEach((folder, index) => {
            const folderDiv = document.createElement('div');
            folderDiv.style.border = '1px solid #d1d5db';
            folderDiv.style.borderRadius = '8px';
            folderDiv.style.padding = '15px';
            folderDiv.style.marginBottom = '20px';
            folderDiv.style.backgroundColor = '#f9fafb';
            folderDiv.style.boxShadow = '0 1px 3px rgba(0,0,0,0.05)';

            const title = document.createElement('h3');
            title.style.margin = '0 0 15px 0';
            title.style.paddingBottom = '10px';
            title.style.borderBottom = '1px solid #e5e7eb';
            title.style.color = '#374151';
            // SVG File icon included next to Title
            title.innerHTML = `<span style="font-size:20px; margin-right:5px;">📁</span> Person #${index + 1} <span style="font-size:0.8em; color:#6b7280; font-weight:normal;">(${folder.faces.length} items)</span>`;
            folderDiv.appendChild(title);

            const grid = document.createElement('div');
            grid.style.display = 'flex';
            grid.style.flexWrap = 'wrap';
            grid.style.gap = '15px';

            folder.faces.forEach(canvasItem => {
                canvasItem.style.borderRadius = '5px';
                canvasItem.style.border = '1px solid #e5e7eb';
                canvasItem.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)';
                canvasItem.style.cursor = 'pointer';
                canvasItem.style.maxWidth = '100px';
                canvasItem.style.maxHeight = '100px';
                canvasItem.style.objectFit = 'contain';
                canvasItem.style.backgroundColor = '#ffffff';
                grid.appendChild(canvasItem);
            });

            folderDiv.appendChild(grid);
            container.appendChild(folderDiv);
        });

    } catch (error) {
        statusDiv.style.backgroundColor = '#f8d7da';
        statusDiv.style.color = '#721c24';
        statusDiv.innerText = `Error: ${error.message}`;
        console.error(error);
    }

    return container;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

This tool uses AI to automatically detect and recognize faces within an image, grouping them into distinct categories based on the individual person. It identifies all faces present, extracts their unique facial features, and sorts them into virtual ‘folders’ to show how many times each person appears. This tool is useful for organizing large batches of photos, managing event photography, or quickly identifying recurring individuals in a single image.

Leave a Reply

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