JavaScript中的单色抖动(拜耳、阿特金森、弗洛伊德和斯坦伯格)
我在玩HTML5中的网络摄像头过滤器。对于那种老派Mac的感觉,我有一个很好的工作机会JavaScript中的单色抖动(拜耳、阿特金森、弗洛伊德和斯坦伯格),javascript,image-processing,canvas,matrix,dithering,Javascript,Image Processing,Canvas,Matrix,Dithering,我在玩HTML5中的网络摄像头过滤器。对于那种老派Mac的感觉,我有一个很好的工作机会 | 现在我正试图为1989年的《游戏小子》制作一个拜耳订购的抖动选项 我知道,但我在将此伪代码转换为JavaScript时遇到问题: for each y for each x oldpixel := pixel[x][y] + threshold_map_4x4[x mod 4][y mod 4] newpixel := find_closest_palette_color(oldpi
| 现在我正试图为1989年的《游戏小子》制作一个拜耳订购的抖动选项 我知道,但我在将此伪代码转换为JavaScript时遇到问题:
for each y
for each x
oldpixel := pixel[x][y] + threshold_map_4x4[x mod 4][y mod 4]
newpixel := find_closest_palette_color(oldpixel)
pixel[x][y] := newpixel
在AS3、PHP或JS中有什么例子吗?你能解释一下阈值映射发生了什么吗
(由制造商制造) 我明白了。在维基百科中,它说“例如,在单色渲染中,如果像素值(缩放到0-9范围)小于矩阵对应单元格中的数字,则将该像素绘制为黑色,否则绘制为白色。”在js中,我通过平均当前像素(0-255)和贴图值(15-240)得到了很好的结果并将其与阈值(通常为129)进行比较:
var-map=(imageData.data[currentPixel]+bayerThresholdMap[x%4][y%4])/2;
imageData.data[currentPixel]=(映射<阈值)?0 : 255;
这是我的整个单色功能,使用不同的算法:
var bayerThresholdMap = [
[ 15, 135, 45, 165 ],
[ 195, 75, 225, 105 ],
[ 60, 180, 30, 150 ],
[ 240, 120, 210, 90 ]
];
var lumR = [];
var lumG = [];
var lumB = [];
for (var i=0; i<256; i++) {
lumR[i] = i*0.299;
lumG[i] = i*0.587;
lumB[i] = i*0.114;
}
function monochrome(imageData, threshold, type){
var imageDataLength = imageData.data.length;
// Greyscale luminance (sets r pixels to luminance of rgb)
for (var i = 0; i <= imageDataLength; i += 4) {
imageData.data[i] = Math.floor(lumR[imageData.data[i]] + lumG[imageData.data[i+1]] + lumB[imageData.data[i+2]]);
}
var w = imageData.width;
var newPixel, err;
for (var currentPixel = 0; currentPixel <= imageDataLength; currentPixel+=4) {
if (type === "none") {
// No dithering
imageData.data[currentPixel] = imageData.data[currentPixel] < threshold ? 0 : 255;
} else if (type === "bayer") {
// 4x4 Bayer ordered dithering algorithm
var x = currentPixel/4 % w;
var y = Math.floor(currentPixel/4 / w);
var map = Math.floor( (imageData.data[currentPixel] + bayerThresholdMap[x%4][y%4]) / 2 );
imageData.data[currentPixel] = (map < threshold) ? 0 : 255;
} else if (type === "floydsteinberg") {
// Floyd–Steinberg dithering algorithm
newPixel = imageData.data[currentPixel] < 129 ? 0 : 255;
err = Math.floor((imageData.data[currentPixel] - newPixel) / 16);
imageData.data[currentPixel] = newPixel;
imageData.data[currentPixel + 4 ] += err*7;
imageData.data[currentPixel + 4*w - 4 ] += err*3;
imageData.data[currentPixel + 4*w ] += err*5;
imageData.data[currentPixel + 4*w + 4 ] += err*1;
} else {
// Bill Atkinson's dithering algorithm
newPixel = imageData.data[currentPixel] < threshold ? 0 : 255;
err = Math.floor((imageData.data[currentPixel] - newPixel) / 8);
imageData.data[currentPixel] = newPixel;
imageData.data[currentPixel + 4 ] += err;
imageData.data[currentPixel + 8 ] += err;
imageData.data[currentPixel + 4*w - 4 ] += err;
imageData.data[currentPixel + 4*w ] += err;
imageData.data[currentPixel + 4*w + 4 ] += err;
imageData.data[currentPixel + 8*w ] += err;
}
// Set g and b pixels equal to r
imageData.data[currentPixel + 1] = imageData.data[currentPixel + 2] = imageData.data[currentPixel];
}
return imageData;
}
var阈值映射=[
[ 15, 135, 45, 165 ],
[ 195, 75, 225, 105 ],
[ 60, 180, 30, 150 ],
[ 240, 120, 210, 90 ]
];
var-lumR=[];
var-lumG=[];
var lumB=[];
对于(var i=0;i我将此作为调试代码:
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var img = new Image();
img.src = "http://i.stack.imgur.com/tHDY8.png";
img.onload = function() {
canvas.width = this.width;
canvas.height = this.height;
ctx.drawImage( this, 0, 0, this.width, this.height );
var imageData = ctx.getImageData( 0, 0, this.width, this.height);
var depth = 32;
// Matrix
var threshold_map_4x4 = [
[ 1, 9, 3, 11 ],
[ 13, 5, 15, 7 ],
[ 4, 12, 2, 10 ],
[ 16, 8, 14, 6 ]
];
// imageData
var width = imageData.width;
var height = imageData.height;
var pixel = imageData.data;
var x, y, a, b;
// filter
for ( x=0; x<width; x++ )
{
for ( y=0; y<height; y++ )
{
a = ( x * height + y ) * 4;
b = threshold_map_4x4[ x%4 ][ y%4 ];
pixel[ a + 0 ] = ( (pixel[ a + 0 ]+ b) / depth | 0 ) * depth;
pixel[ a + 1 ] = ( (pixel[ a + 1 ]+ b) / depth | 0 ) * depth;
pixel[ a + 2 ] = ( (pixel[ a + 2 ]+ b) / depth | 0 ) * depth;
//pixel[ a + 3 ] = ( (pixel[ a + 3 ]+ b) / depth | 3 ) * depth;
}
}
ctx.putImageData( imageData, 0, 0);
};
document.body.appendChild(canvas);
var canvas=document.createElement('canvas');
var ctx=canvas.getContext('2d');
var img=新图像();
img.src=”http://i.stack.imgur.com/tHDY8.png";
img.onload=函数(){
canvas.width=this.width;
canvas.height=this.height;
ctx.drawImage(this,0,0,this.width,this.height);
var imageData=ctx.getImageData(0,0,this.width,this.height);
var深度=32;
//母体
var阈值\u映射\u 4x4=[
[ 1, 9, 3, 11 ],
[ 13, 5, 15, 7 ],
[ 4, 12, 2, 10 ],
[ 16, 8, 14, 6 ]
];
//图像数据
var width=imageData.width;
var height=imageData.height;
var pixel=imageData.data;
变量x,y,a,b;
//滤器
对于(x=0;x,以下是我的所有单色抖动功能,可作为web工作者使用:
带有网络摄像头的实时演示:由于它是单色的,您可以将其更改为:pixel[a]=pixel[a+1]=pixel[a+2]=((pixel[a]+b)/depth | 0)*depth;
检查控制台,我的跨域图像有问题(我使用的是旧浏览器…)。因此,我转到图像url,打开控制台并复制粘贴代码,它工作正常(),或者你想要另一个结果?是的,我想要单色输出。我将我的算法放在原始问题中,并制作了此实时演示:@500 InternalServerError:)修复。
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var img = new Image();
img.src = "http://i.stack.imgur.com/tHDY8.png";
img.onload = function() {
canvas.width = this.width;
canvas.height = this.height;
ctx.drawImage( this, 0, 0, this.width, this.height );
var imageData = ctx.getImageData( 0, 0, this.width, this.height);
var depth = 32;
// Matrix
var threshold_map_4x4 = [
[ 1, 9, 3, 11 ],
[ 13, 5, 15, 7 ],
[ 4, 12, 2, 10 ],
[ 16, 8, 14, 6 ]
];
// imageData
var width = imageData.width;
var height = imageData.height;
var pixel = imageData.data;
var x, y, a, b;
// filter
for ( x=0; x<width; x++ )
{
for ( y=0; y<height; y++ )
{
a = ( x * height + y ) * 4;
b = threshold_map_4x4[ x%4 ][ y%4 ];
pixel[ a + 0 ] = ( (pixel[ a + 0 ]+ b) / depth | 0 ) * depth;
pixel[ a + 1 ] = ( (pixel[ a + 1 ]+ b) / depth | 0 ) * depth;
pixel[ a + 2 ] = ( (pixel[ a + 2 ]+ b) / depth | 0 ) * depth;
//pixel[ a + 3 ] = ( (pixel[ a + 3 ]+ b) / depth | 3 ) * depth;
}
}
ctx.putImageData( imageData, 0, 0);
};
document.body.appendChild(canvas);