模糊算法画布不工作JS

时间:2017-09-23 06:28:06

标签: javascript algorithm canvas

我正在尝试实现一个简单的模糊算法,对3x3区域内周围像素的颜色进行平均。

我循环遍历像素数组,增量为4.然后我有一个函数,它有6个参数:

r -> red value [0-255] int
g -> green value [0-255] int
b -> blue value [0-255] int
a -> alpha value(opacity) [0-255] int
d -> pixel array [r0,g0,b0,a0,r1,g1,b1,a1,r2... etc] array
i -> current index

我生成4个新值,新红色,新绿色,新蓝色和新alpha并将它们返回到对象中。

这是整个代码:

//canvas setup
var width = 400;
var height = 400;

var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');

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

//create image
var img = new Image();
img.src = 'images/input.jpg';

var pixels;

img.onload = function(){
    ctx.drawImage(img, 0, 0);
    pixels = ctx.getImageData(0, 0, width, height);
}

function action(pixels, callback){
    var newData = ctx.createImageData(width, height);

    for(var i = 0; i < pixels.data.length; i+=4){
        var r = pixels.data[i];
        var g = pixels.data[i+1];
        var b = pixels.data[i+2];
        var a = pixels.data[i+3];

        var channels = callback(r, g, b, a, pixels.data, i);

        newData.data[i] = channels.r;
        newData.data[i+1] = channels.g;
        newData.data[i+2] = channels.b;
        newData.data[i+3] = channels.a;

        pixels.data[i] = channels.r;
        pixels.data[i+1] = channels.g;
        pixels.data[i+2] = channels.b;
        pixels.data[i+3] = channels.a;
    }

    ctx.putImageData(newData, 0, 0);
}

function run(){
    action(pixels, function(r,g,b,a,d,i){

        var nr = (r
            + (d[i - 4] || r)
            + (d[i + 4] || r)
            + (d[i - 4 * width] || r)
            + (d[i + 4 * width] || r)
            + (d[i - 4 * width - 4] || r)
            + (d[i + 4 * width + 4] || r)
            + (d[i - 4 * width + 4] || r)
            + (d[i + 4 * width - 4] || r)
        ) / 9;

        var ng = (g
            + (d[i - 4] || g)
            + (d[i + 4] || g)
            + (d[i - 4 * width] || g)
            + (d[i + 4 * width] || g)
            + (d[i - 4 * width - 4] || g)
            + (d[i + 4 * width + 4] || g)
            + (d[i - 4 * width + 4] || g)
            + (d[i + 4 * width - 4] || g)
        ) / 9;

        var nb = (b
            + (d[i - 4] || b)
            + (d[i + 4] || b)
            + (d[i - 4 * width] || b)
            + (d[i + 4 * width] || b)
            + (d[i - 4 * width - 4] || b)
            + (d[i + 4 * width + 4] || b)
            + (d[i - 4 * width + 4] || b)
            + (d[i + 4 * width - 4] || b)
        ) / 9;

        return {r: nr, g: ng, b: nb, a: 255};
    });
}

如您所见,周围像素值是硬编码的。 你可以在这里测试一下:

https://codepen.io/tyrellrummage/pen/Ewgzzx

如果运行按钮什么都不做,请重新加载并重试(codepen cross-origin有些问题)。尝试多次按下运行按钮以增加算法的传递。

你会注意到它会在2/3过后完全灰度图像。 提前谢谢!

1 个答案:

答案 0 :(得分:0)

您正在索引回调中的错误频道。并且不确定为什么要执行||

在回调中的每个颜色通道后添加i++

同样,平均值应该是每个通道值的平方的平均值,因为每个通道的值是亮度的~sqrt。不平均值会产生比它应该更暗的平均值。

function run(){
    const w = width * 4;
    // the offset index for each pixel excluding the center pixel
    const grid = [-w - 4, -w, -w + 4, -4, 4, w - 4, w, w + 4];

    action(pixels,(r,g,b,a,dat,i) => {
        var idx, count;         
        r *= r;
        g *= g;
        b *= b;
        count = 1;
        for(idx = 0; idx < grid.length; idx ++){
            const off = grid[idx];
            if(i + off >= 0 && i + off < w * height){
                r += dat[i + off] * dat[i + off];
                g += dat[i + 1 + off] * dat[i + 1 + off];
                b += dat[i + 2 + off] * dat[i + 2 + off];
                a += dat[i + 3 + off];
                count ++;
            }
        }
        r = Math.sqrt(r / count);
        g = Math.sqrt(g / count);
        b = Math.sqrt(b / count);
        a = a / count;
        return {r,g,b,a};
     });
}

BTW将行img.crossOrigin = "Anonymous";移动到您设置img.src的行之上,就像图像处于缓存状态时一样,它会在下一行之前加载,并且anon标头不会附加到请求。< / p>