我正在尝试实现一个简单的模糊算法,对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过后完全灰度图像。 提前谢谢!
答案 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>