Please bookmark this page to avoid losing your image tool!

Image Skin Smoothing 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.
/**
 * Applies a skin smoothing effect to an image using a bilateral filter.
 * This filter smooths the image while preserving edges, which is effective for reducing
 * skin blemishes and wrinkles without blurring important features like eyes and hair.
 *
 * @param {Image} originalImg The original JavaScript Image object.
 * @param {number} smoothing A number from 0-100 that controls the color-based smoothing. Higher values mean more colors are considered similar, leading to a stronger blur effect. A good starting range is 20-50.
 * @param {number} detail A number from 0-10 that controls the spatial influence, essentially the radius of the filter in pixels. Higher values consider a larger area, which can smooth larger features but is much slower. A good starting range is 2-5.
 * @returns {HTMLCanvasElement} A new canvas element with the smoothed image.
 */
async function processImage(originalImg, smoothing = 20, detail = 3) {
    const width = originalImg.naturalWidth;
    const height = originalImg.naturalHeight;

    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;

    // Use { willReadFrequently: true } for performance optimization with getImageData
    const ctx = canvas.getContext('2d', {
        willReadFrequently: true
    });
    ctx.drawImage(originalImg, 0, 0, width, height);

    // If parameters result in no effect, return the original drawn canvas
    if (smoothing <= 0 || detail < 1) {
        return canvas;
    }

    const originalImageData = ctx.getImageData(0, 0, width, height);
    const newImageData = ctx.createImageData(width, height);
    const originalData = originalImageData.data;
    const newData = newImageData.data;

    // Bilateral filter parameters
    const sigmaR = smoothing; // Range sigma (color similarity)
    const kernelRadius = Math.floor(detail); // Spatial sigma (distance)
    const sigmaS = kernelRadius;

    // Pre-calculate constants for efficiency
    const twoSigmaRSquared = 2 * sigmaR * sigmaR;
    const twoSigmaSSquared = 2 * sigmaS * sigmaS;
    const kernelDim = 2 * kernelRadius + 1;

    // Pre-calculate the spatial falloff (Gaussian) for the kernel
    // This avoids recalculating Math.exp for spatial distance in the main loop
    const spatialWeights = new Float32Array(kernelDim * kernelDim);
    let weightIndex = 0;
    for (let dy = -kernelRadius; dy <= kernelRadius; dy++) {
        for (let dx = -kernelRadius; dx <= kernelRadius; dx++) {
            const distSq = dx * dx + dy * dy;
            spatialWeights[weightIndex++] = Math.exp(-distSq / twoSigmaSSquared);
        }
    }

    // Main loop: iterate over each pixel of the image
    for (let y = 0; y < height; y++) {
        for (let x = 0; x < width; x++) {
            const centerIndex = (y * width + x) * 4;

            // Get the color of the center pixel
            const centerR = originalData[centerIndex];
            const centerG = originalData[centerIndex + 1];
            const centerB = originalData[centerIndex + 2];
            const centerA = originalData[centerIndex + 3];

            let totalR = 0;
            let totalG = 0;
            let totalB = 0;
            let totalWeight = 0;

            weightIndex = 0;

            // Iterate over the kernel (neighborhood of the center pixel)
            for (let dy = -kernelRadius; dy <= kernelRadius; dy++) {
                for (let dx = -kernelRadius; dx <= kernelRadius; dx++) {
                    const nx = x + dx;
                    const ny = y + dy;

                    // Check if the neighbor pixel is within image bounds
                    if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
                        const neighborIndex = (ny * width + nx) * 4;
                        const neighborR = originalData[neighborIndex];
                        const neighborG = originalData[neighborIndex + 1];
                        const neighborB = originalData[neighborIndex + 2];

                        // Get the pre-calculated spatial weight
                        const spatialWeight = spatialWeights[weightIndex];

                        // Calculate the color/range weight on the fly
                        const colorDistSq =
                            (centerR - neighborR) ** 2 +
                            (centerG - neighborG) ** 2 +
                            (centerB - neighborB) ** 2;
                        const colorWeight = Math.exp(-colorDistSq / twoSigmaRSquared);

                        // The final weight is the product of spatial and color weights
                        const weight = spatialWeight * colorWeight;

                        totalR += neighborR * weight;
                        totalG += neighborG * weight;
                        totalB += neighborB * weight;
                        totalWeight += weight;
                    }
                    weightIndex++;
                }
            }

            // Normalize the weighted sum to get the new pixel color
            newData[centerIndex] = totalR / totalWeight;
            newData[centerIndex + 1] = totalG / totalWeight;
            newData[centerIndex + 2] = totalB / totalWeight;
            newData[centerIndex + 3] = centerA; // Preserve original alpha
        }
    }

    // Put the processed image data back onto the canvas
    ctx.putImageData(newImageData, 0, 0);

    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 Skin Smoothing Tool allows users to enhance their images by applying a skin smoothing effect using a bilateral filter. This tool effectively reduces skin blemishes and wrinkles while preserving important facial features such as eyes and hair. It is useful for enhancing personal photos, professional portraits, or any images where skin appearance is a concern. Users can adjust the levels of smoothing and detail to achieve their desired results, making it ideal for personal use, social media content, or beauty-related applications.

Leave a Reply

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