Please bookmark this page to avoid losing your image tool!

Image Action Detector

(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.
/**
 * Processes an image to either detect a point of action (saliency) or apply an "action"
 * zoom-blur effect, based on the provided mode. This function interprets the name
 * "Image Action Detector" by providing two distinct modes: 'detect' and 'action'.
 *
 * @param {Image} originalImg The original javascript Image object.
 * @param {string} [mode='action'] The operation mode. Can be 'detect' or 'action'.
 * @param {number} [strength=0.2] For 'action' mode: the intensity of the zoom blur, from 0 (none) to 1 (max).
 * @param {number|string} [centerX=0.5] For 'action' mode: the horizontal center of the blur (0 to 1), or 'auto' to detect it.
 * @param {number|string} [centerY=0.5] For 'action' mode: the vertical center of the blur (0 to 1), or 'auto' to detect it.
 * @param {string} [markerColor='rgba(255, 0, 0, 0.8)'] For 'detect' mode: the color of the detector marker.
 * @param {number} [markerSize=25] For 'detect' mode: the radius of the detector marker circle.
 * @returns {HTMLCanvasElement} A canvas element with the processed image.
 */
async function processImage(originalImg, mode = 'action', strength = 0.2, centerX = 0.5, centerY = 0.5, markerColor = 'rgba(255, 0, 0, 0.8)', markerSize = 25) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    const width = originalImg.naturalWidth || originalImg.width;
    const height = originalImg.naturalHeight || originalImg.height;
    canvas.width = width;
    canvas.height = height;

    const lowerCaseMode = String(mode).toLowerCase();

    // --- DETECTOR MODE ---
    // Detects the most salient point in the image (based on color saturation) and marks it.
    if (lowerCaseMode === 'detect') {
        // For performance, analyze a scaled-down version of the image.
        const thumbWidth = 100;
        const thumbHeight = Math.round((height / width) * thumbWidth);
        const thumbCanvas = document.createElement('canvas');
        const thumbCtx = thumbCanvas.getContext('2d');
        thumbCanvas.width = thumbWidth;
        thumbCanvas.height = thumbHeight;
        thumbCtx.drawImage(originalImg, 0, 0, thumbWidth, thumbHeight);

        const imageData = thumbCtx.getImageData(0, 0, thumbWidth, thumbHeight);
        const data = imageData.data;
        let maxScore = -1;
        let salientX = 0;
        let salientY = 0;

        // Find the pixel with the highest saturation (a simple proxy for saliency).
        for (let i = 0; i < data.length; i += 4) {
            const r = data[i];
            const g = data[i + 1];
            const b = data[i + 2];
            const score = Math.max(r, g, b) - Math.min(r, g, b);

            if (score > maxScore) {
                maxScore = score;
                const pixelIndex = i / 4;
                salientX = pixelIndex % thumbWidth;
                salientY = Math.floor(pixelIndex / thumbWidth);
            }
        }

        // Scale the found coordinates back to the original image size.
        const originalX = (salientX / thumbWidth) * width;
        const originalY = (salientY / thumbHeight) * height;

        // Draw the original image on the main canvas.
        ctx.drawImage(originalImg, 0, 0, width, height);

        // Draw a crosshair marker on the detected point.
        const size = Number(markerSize);
        ctx.strokeStyle = markerColor;
        ctx.lineWidth = Math.max(2, size * 0.1);
        ctx.beginPath();
        // Circle
        ctx.arc(originalX, originalY, size, 0, 2 * Math.PI);
        // Horizontal line
        ctx.moveTo(originalX - size * 1.5, originalY);
        ctx.lineTo(originalX + size * 1.5, originalY);
        // Vertical line
        ctx.moveTo(originalX, originalY - size * 1.5);
        ctx.lineTo(originalX, originalY + size * 1.5);
        ctx.stroke();

        return canvas;
    }

    // --- ACTION MODE ---
    // Applies a zoom-blur effect centered on a specific point.
    if (lowerCaseMode === 'action') {
        let finalCenterX = centerX;
        let finalCenterY = centerY;

        // If 'auto' is specified, run the detection logic to find the center.
        if (String(centerX).toLowerCase() === 'auto' || String(centerY).toLowerCase() === 'auto') {
            const thumbWidth = 100;
            const thumbHeight = Math.round((height / width) * thumbWidth);
            const thumbCanvas = document.createElement('canvas');
            const thumbCtx = thumbCanvas.getContext('2d');
            thumbCanvas.width = thumbWidth;
            thumbCanvas.height = thumbHeight;
            thumbCtx.drawImage(originalImg, 0, 0, thumbWidth, thumbHeight);
            const imageData = thumbCtx.getImageData(0, 0, thumbWidth, thumbHeight);
            const data = imageData.data;
            let maxScore = -1;
            let salientX = 0;
            let salientY = 0;
            for (let i = 0; i < data.length; i += 4) {
                const r = data[i], g = data[i + 1], b = data[i + 2];
                const score = Math.max(r, g, b) - Math.min(r, g, b);
                if (score > maxScore) {
                    maxScore = score;
                    const pixelIndex = i / 4;
                    salientX = pixelIndex % thumbWidth;
                    salientY = Math.floor(pixelIndex / thumbWidth);
                }
            }
            finalCenterX = salientX / thumbWidth;
            finalCenterY = salientY / thumbHeight;
        }

        // Sanitize and clamp numeric parameters.
        const numStrength = Math.max(0, Math.min(1, Number(strength)));
        const numCenterX = Math.max(0, Math.min(1, Number(finalCenterX)));
        const numCenterY = Math.max(0, Math.min(1, Number(finalCenterY)));

        if (numStrength < 0.01) {
            ctx.drawImage(originalImg, 0, 0, width, height);
            return canvas;
        }

        const absCenterX = width * numCenterX;
        const absCenterY = height * numCenterY;
        const samples = 30; // More samples create a smoother blur.

        // Create the blur effect by layering semi-transparent, scaled copies of the image.
        ctx.globalAlpha = 0.7 / samples;
        for (let i = 0; i < samples; i++) {
            const scale = 1.0 + (i / samples) * numStrength;
            const scaledWidth = width * scale;
            const scaledHeight = height * scale;
            const drawX = absCenterX - (scaledWidth * numCenterX);
            const drawY = absCenterY - (scaledHeight * numCenterY);
            ctx.drawImage(originalImg, drawX, drawY, scaledWidth, scaledHeight);
        }

        // Draw the original image on top to ensure the focal point remains sharp and vibrant.
        ctx.globalAlpha = 1.0;
        ctx.drawImage(originalImg, 0, 0, width, height);

        return canvas;
    }

    // Fallback for unrecognized modes.
    ctx.drawImage(originalImg, 0, 0, width, height);
    ctx.font = "bold 24px sans-serif";
    ctx.fillStyle = "rgba(255, 0, 0, 0.8)";
    ctx.textAlign = "center";
    ctx.strokeStyle = "white";
    ctx.lineWidth = 4;
    const text = `Unknown mode: '${mode}'`;
    ctx.strokeText(text, width / 2, height / 2);
    ctx.fillText(text, width / 2, height / 2);
    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 Action Detector is a versatile online tool that processes images to either identify a salient point of action or to create a dynamic zoom-blur effect. Users can choose between two modes: ‘detect’ mode highlights the most visually prominent area in the image, making it ideal for photo analysis or enhancement, while ‘action’ mode applies a zoom-blur effect, perfect for emphasizing motion or creating artistic effects. This tool is useful for photographers, graphic designers, and anyone looking to enhance their images with visual effects or to analyze the focus of interest within a picture.

Leave a Reply

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