Please bookmark this page to avoid losing your image tool!

Image Smoothing Algorithm Integration 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, algorithm = 'Laplacian', strength = 5) {

    /**
     * Applies a convolution kernel to image data.
     * Used for the Laplacian filter.
     * @param {Uint8ClampedArray} src - Source pixel data.
     * @param {Uint8ClampedArray} dst - Destination pixel data array.
     * @param {number} width - Image width.
     * @param {number} height - Image height.
     * @param {number[]} kernel - The convolution kernel (e.g., a 3x3 matrix as a 9-element array).
     */
    const applyLaplacianConvolution = (src, dst, width, height, kernel) => {
        const kernelSize = Math.sqrt(kernel.length);
        const halfKernelSize = Math.floor(kernelSize / 2);

        for (let y = 0; y < height; y++) {
            for (let x = 0; x < width; x++) {
                let r = 0, g = 0, b = 0;

                for (let ky = 0; ky < kernelSize; ky++) {
                    for (let kx = 0; kx < kernelSize; kx++) {
                        const imgY = y + ky - halfKernelSize;
                        const imgX = x + kx - halfKernelSize;

                        // Clamp to edge
                        const clampedY = Math.max(0, Math.min(height - 1, imgY));
                        const clampedX = Math.max(0, Math.min(width - 1, imgX));
                        
                        const offset = (clampedY * width + clampedX) * 4;
                        const weight = kernel[ky * kernelSize + kx];
                        r += src[offset] * weight;
                        g += src[offset + 1] * weight;
                        b += src[offset + 2] * weight;
                    }
                }

                const dstOffset = (y * width + x) * 4;
                // The result of a Laplacian can be negative, so we take the absolute
                // value and convert to grayscale to create a visible edge map.
                const gray = Math.abs(r * 0.299 + g * 0.587 + b * 0.114);
                dst[dstOffset] = gray;
                dst[dstOffset + 1] = gray;
                dst[dstOffset + 2] = gray;
                dst[dstOffset + 3] = 255; // Opaque
            }
        }
    };

    /**
     * Applies a Bilateral Filter for edge-preserving smoothing.
     * @param {Uint8ClampedArray} src - Source pixel data.
     * @param {Uint8ClampedArray} dst - Destination pixel data array.
     * @param {number} width - Image width.
     * @param {number} height - Image height.
     * @param {number} sigmaSpace - The spatial Gaussian standard deviation. Controls blur radius.
     * @param {number} sigmaColor - The color/intensity Gaussian standard deviation. Controls edge preservation.
     */
    const applyBilateralFilter = (src, dst, width, height, sigmaSpace, sigmaColor) => {
        const radius = Math.floor(Math.max(1, strength));
        const twoSigmaSpaceSq = 2 * sigmaSpace * sigmaSpace;
        const twoSigmaColorSq = 2 * sigmaColor * sigmaColor;

        for (let y = 0; y < height; y++) {
            for (let x = 0; x < width; x++) {
                const centerIndex = (y * width + x) * 4;
                const cr = src[centerIndex];
                const cg = src[centerIndex + 1];
                const cb = src[centerIndex + 2];

                let sumR = 0, sumG = 0, sumB = 0;
                let totalWeight = 0;

                for (let ky = -radius; ky <= radius; ky++) {
                    for (let kx = -radius; kx <= radius; kx++) {
                        const ny = y + ky;
                        const nx = x + kx;

                        if (ny >= 0 && ny < height && nx >= 0 && nx < width) {
                            const spatialDistSq = kx * kx + ky * ky;
                            if (spatialDistSq > radius * radius) continue;

                            const neighborIndex = (ny * width + nx) * 4;
                            const nr = src[neighborIndex];
                            const ng = src[neighborIndex + 1];
                            const nb = src[neighborIndex + 2];

                            const colorDistSq = (cr - nr)**2 + (cg - ng)**2 + (cb - nb)**2;

                            const wSpace = Math.exp(-spatialDistSq / twoSigmaSpaceSq);
                            const wColor = Math.exp(-colorDistSq / twoSigmaColorSq);
                            const weight = wSpace * wColor;

                            sumR += nr * weight;
                            sumG += ng * weight;
                            sumB += nb * weight;
                            totalWeight += weight;
                        }
                    }
                }
                
                dst[centerIndex] = sumR / totalWeight;
                dst[centerIndex + 1] = sumG / totalWeight;
                dst[centerIndex + 2] = sumB / totalWeight;
                dst[centerIndex + 3] = src[centerIndex + 3]; // Preserve alpha
            }
        }
    };

    const canvas = document.createElement('canvas');
    // Using { willReadFrequently: true } is a performance hint for the browser
    const ctx = canvas.getContext('2d', { willReadFrequently: true });
    canvas.width = originalImg.naturalWidth;
    canvas.height = originalImg.naturalHeight;
    ctx.drawImage(originalImg, 0, 0);

    const nonApplicableAlgos = ['yape06', 'fastcorners', 'lloyd', 'polygon vertex'];
    const algoKey = algorithm.toLowerCase();

    if (nonApplicableAlgos.includes(algoKey)) {
        console.warn(`Algorithm "${algorithm}" is not a raster image smoothing filter. It likely relates to mesh or vector graphics processing and is not implemented. Returning the original image.`);
        return canvas;
    }

    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    const srcData = imageData.data;
    const dstData = new Uint8ClampedArray(srcData.length);

    switch (algoKey) {
        case 'laplacian':
            const laplacianKernel = [
                0, -1, 0,
               -1,  4, -1,
                0, -1, 0
            ];
            applyLaplacianConvolution(srcData, dstData, canvas.width, canvas.height, laplacianKernel);
            break;

        case 'contrast weighted':
            const sigma = Math.max(1, strength);
             // The second parameter (sigmaColor) is scaled for a more intuitive "strength" effect.
            applyBilateralFilter(srcData, dstData, canvas.width, canvas.height, sigma, sigma * 10);
            break;

        default:
            console.warn(`Unknown or unimplemented algorithm: "${algorithm}". Returning original image.`);
            dstData.set(srcData); // Copy original data to destination
            break;
    }

    const newImageData = new ImageData(dstData, canvas.width, canvas.height);
    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 Smoothing Algorithm Integration Tool enables users to enhance image quality by applying various smoothing algorithms. This tool can be particularly useful for photographers and graphic designers looking to reduce noise, enhance edges, or achieve smoother gradients in images. By using advanced filtering techniques such as Laplacian and Bilateral filters, users can refine their images while maintaining important details and edge integrity. The tool is suitable for applications in digital image processing, photo editing, and preparation of images for print or online use.

Leave a Reply

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