Search code examples
javascripthtmlcanvasfilterpixel

JavaScript Sharpen Image and Edge Detection not working


I made a simple web application of Image Manipulation/filters with HTML5 and JavaScript. Every filters are working fine like Brightness, Grayscale, Negative etc. Except Sharpen Image, Edge-detection all kinds of Neighbourhood operation are not working.

I have tried every possible way, tried to google, looked for references but failed. The references that I found shows the Matrix system, I know the concept of the Matrix System, but don't know how to apply. It would be kind if I can get a solution of my problem. Please see my codes below, for the time being, I am posting my Sharp an image codes.

I Found Something like this to sharp an Image ( [ 0, -1, 0, -1, 5, -1, 0, -1, 0 ]), but how to apply I dont know. So I tried to apply it like the codes below

<script>
function pic() {
var c = document.getElementById('myCanvas');
            var ctx = c.getContext('2d');
var btnsharpen = document.getElementById('btnsharpen');
var img = new Image();

            img.onload = function () {
                ctx.drawImage(img, 0, 0);
            }

//sharp the image
btnsharpen.onclick = function(){
        ctx.drawImage(img, 0, 0);
        var imgData = ctx.getImageData(0,0, c.width, c.height);

        var pixels = imgData.data;
        var numPixels = ((imgData.width-1) *(imgData*4)+ ((imgData.height)*4)); 
        for (var i = 0, n = numPixels; i < n; i +=4) {
            var sharpen = (pixels[i] * 0 + pixels[i + 1] * 0 + pixels[i + 2] * 0) +
              (pixels[i] * -1 + pixels[i + 1] * -1 + pixels[i + 2] * -1) +
              (pixels[i] * 0 + pixels[i + 1] * 0 + pixels[i + 2] * 0) +
              (pixels[i] * -1 + pixels[i + 1] * -1 + pixels[i + 2] * -1) +
              (pixels[i] * 5 + pixels[i + 1] * 5 + pixels[i + 2] * 5) +
              (pixels[i] * -1 + pixels[i + 1] * -1 + pixels[i + 2] * -1) +
              (pixels[i] * 0 + pixels[i + 1] * 0 + pixels[i + 2] * 0) +
              (pixels[i] * -1 + pixels[i + 1] * -1 + pixels[i + 2] * -1) +
              (pixels[i] * 0 + pixels[i + 1] * 0 + pixels[i + 2] * 0);

            pixels[i] = sharpen; // red
            pixels[i + 1] = sharpen; // green
            pixels[i + 2] = sharpen; // blue
            }

            ctx.putImageData(imgData, 0, 0);
            img.src = "image/Angelina_Jolie.jpg";
        }
</script>

<body onLoad="pic()">
<canvas id='myCanvas' width='500' height='375' style='border:solid 1px #000000'></canvas>
<input type="button" value="Sharpen" class="buttons" id="btnsharpen" /><br />
</body>

Solution

  • Old question (hopefully you found your answer, @bleach64), but for anyone that's interested, here's a fiddle for image sharpening that I found:

    Step-down downsample + sharpen convolution

    var canvas = document.getElementById("canvas"),
        ctx = canvas.getContext("2d"),
        offScreen = document.createElement('canvas'),
        offctx = offScreen.getContext('2d'),
        img = new Image();
    
    /// as we need pixel access to apply convolution we
    /// need to get around CORS:
    img.crossOrigin = 'anonymous';
    
    /// when image is loaded step-down the downscaling
    img.onload = resize;
    img.src = "http://i.imgur.com/DR94LKg.jpg";
    
    /// sharpen image:
    /// USAGE:
    ///    sharpen(context, width, height, mixFactor)
    ///  mixFactor: [0.0, 1.0]
    function sharpen(ctx, w, h, mix) {
    
        var weights = [0, -1, 0, -1, 5, -1, 0, -1, 0],
            katet = Math.round(Math.sqrt(weights.length)),
            half = (katet * 0.5) | 0,
            dstData = ctx.createImageData(w, h),
            dstBuff = dstData.data,
            srcBuff = ctx.getImageData(0, 0, w, h).data,
            y = h;
    
        while (y--) {
    
            x = w;
    
            while (x--) {
    
                var sy = y,
                    sx = x,
                    dstOff = (y * w + x) * 4,
                    r = 0,
                    g = 0,
                    b = 0,
                    a = 0;
    
                for (var cy = 0; cy < katet; cy++) {
                    for (var cx = 0; cx < katet; cx++) {
    
                        var scy = sy + cy - half;
                        var scx = sx + cx - half;
    
                        if (scy >= 0 && scy < h && scx >= 0 && scx < w) {
    
                            var srcOff = (scy * w + scx) * 4;
                            var wt = weights[cy * katet + cx];
    
                            r += srcBuff[srcOff] * wt;
                            g += srcBuff[srcOff + 1] * wt;
                            b += srcBuff[srcOff + 2] * wt;
                            a += srcBuff[srcOff + 3] * wt;
                        }
                    }
                }
    
                dstBuff[dstOff] = r * mix + srcBuff[dstOff] * (1 - mix);
                dstBuff[dstOff + 1] = g * mix + srcBuff[dstOff + 1] * (1 - mix);
                dstBuff[dstOff + 2] = b * mix + srcBuff[dstOff + 2] * (1 - mix)
                dstBuff[dstOff + 3] = srcBuff[dstOff + 3];
            }
        }
    
        ctx.putImageData(dstData, 0, 0);
    }
    
    /// naive and non-efficient implementation of update, but
    /// do illustrate the impact of sharpen after a downsample
    function resize() {
    
        /// set canvas size proportional to original image
        canvas.height = canvas.width * (img.height / img.width);
    
        /// set off-screen canvas/sharpening source to same size
        offScreen.width = canvas.width;
        offScreen.height = canvas.height;
    
        /// step 1 in down-scaling
        var oc = document.createElement('canvas'),
            octx = oc.getContext('2d');
    
        oc.width = img.width * 0.5;
        oc.height = img.height * 0.5;
        octx.drawImage(img, 0, 0, oc.width, oc.height);
    
        /// step 2
        octx.drawImage(oc, 0, 0, oc.width * 0.5, oc.height * 0.5);
    
        /// draw final result to screen canvas
        ctx.drawImage(oc, 0, 0, oc.width * 0.5, oc.height * 0.5,
        0, 0, canvas.width, canvas.height);
    
        /// copy to off-screen to use as source for shapening
        offctx.drawImage(canvas, 0, 0);
    
        /// apply sharpening convolution
        update();
    }
    
    /// adjustable sharpening - update cached source
    function update() {
        ctx.drawImage(offScreen, 0, 0);
        sharpen(ctx, canvas.width, canvas.height, parseInt(mix.value) * 0.01);
    }