Please bookmark this page to avoid losing your image tool!

Image Noise Reduction Filter

(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 median filter to an image for noise reduction.
 * Each pixel's color is replaced by the median color of its neighboring pixels
 * within a square window defined by kernelSize.
 *
 * @param {Image} originalImg The original JavaScript Image object.
 * @param {number} [kernelSize=3] The size of the median filter window (e.g., 3 for 3x3, 5 for 5x5). Must be an odd integer >= 3.
 * @returns {HTMLCanvasElement} A canvas element displaying the noise-reduced image.
 */
function processImage(originalImg, kernelSize = 3) {
    // Validate kernelSize
    if (typeof kernelSize !== 'number' || isNaN(kernelSize) || kernelSize < 3 || kernelSize % 2 === 0) {
        console.warn(`Invalid kernelSize "${kernelSize}" provided. Defaulting to 3.`);
        kernelSize = 3;
    }

    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d', { willReadFrequently: true }); // willReadFrequently for performance with getImageData

    const width = originalImg.naturalWidth;
    const height = originalImg.naturalHeight;

    // Check for valid image dimensions
    if (width === 0 || height === 0) {
        console.warn("Image has zero width or height. Ensure image is loaded and valid.");
        // Create a small canvas with an error message
        canvas.width = 200;
        canvas.height = 50;
        ctx.font = "12px Arial";
        ctx.fillStyle = "red";
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.fillText("Invalid image: zero dimensions.", canvas.width / 2, canvas.height / 2);
        return canvas;
    }

    canvas.width = width;
    canvas.height = height;

    // Draw the original image to the canvas
    try {
        ctx.drawImage(originalImg, 0, 0, width, height);
    } catch (e) {
        console.error("Error drawing original image: ", e);
        // Fill canvas with an error message if drawing fails
        ctx.clearRect(0, 0, width, height); // Clear any partial drawing
        ctx.font = "16px Arial";
        ctx.fillStyle = "red";
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.fillText("Error: Could not draw original image.", width / 2, height / 2);
        return canvas;
    }

    // Get image data
    let imageData;
    try {
        imageData = ctx.getImageData(0, 0, width, height);
    } catch (e) {
        console.warn("Could not get ImageData (e.g., cross-origin issue). Returning original image. Error: ", e);
        // If getImageData fails (e.g. tainted canvas), the canvas currently holds the original image.
        // We can return it as is. Optionally add a warning text on canvas.
        ctx.font = "12px Arial";
        ctx.fillStyle = "rgba(255,0,0,0.7)";
        ctx.textAlign = "center";
        ctx.fillText("Processing failed (cross-origin?)", width/2, height/2);
        return canvas;
    }

    const data = imageData.data;
    const outputData = new Uint8ClampedArray(data.length);
    const halfKernel = Math.floor(kernelSize / 2);

    // Iterate over each pixel
    for (let y = 0; y < height; y++) {
        for (let x = 0; x < width; x++) {
            const rValues = [];
            const gValues = [];
            const bValues = [];
            // Alpha is typically preserved from the original central pixel or averaged.
            // For simplicity, we preserve the original alpha.

            // Iterate over the kernel window
            for (let ky = -halfKernel; ky <= halfKernel; ky++) {
                for (let kx = -halfKernel; kx <= halfKernel; kx++) {
                    const neighborX = x + kx;
                    const neighborY = y + ky;

                    // Check if the neighbor pixel is within image bounds
                    if (neighborX >= 0 && neighborX < width && neighborY >= 0 && neighborY < height) {
                        const pixelIndex = (neighborY * width + neighborX) * 4;
                        rValues.push(data[pixelIndex]);
                        gValues.push(data[pixelIndex + 1]);
                        bValues.push(data[pixelIndex + 2]);
                    }
                }
            }

            // Sort color values to find the median
            rValues.sort((a, b) => a - b);
            gValues.sort((a, b) => a - b);
            bValues.sort((a, b) => a - b);

            const medianIndex = Math.floor(rValues.length / 2);
            const outputPixelIndex = (y * width + x) * 4;

            // Set median color values to the output data
            outputData[outputPixelIndex] = rValues[medianIndex];
            outputData[outputPixelIndex + 1] = gValues[medianIndex];
            outputData[outputPixelIndex + 2] = bValues[medianIndex];
            outputData[outputPixelIndex + 3] = data[outputPixelIndex + 3]; // Preserve original alpha
        }
    }

    // Create new ImageData from the processed data and put it onto the canvas
    const outputImageData = new ImageData(outputData, width, height);
    ctx.putImageData(outputImageData, 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 Noise Reduction Filter is a tool designed to enhance the quality of images by reducing noise through the application of a median filter. This process involves replacing each pixel’s color with the median color of its neighboring pixels within a defined square area, which can be adjusted by setting the kernel size. This tool is useful in various scenarios, such as cleaning up images taken in low light conditions, improving photos for digital art, or enhancing the clarity of scanned documents. By reducing visual distortion and artifacts in images, users can achieve cleaner and more professional-looking results.

Leave a Reply

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