HTML5 でウェブカメラ フィルターを使用しています。その古い学校の Mac の感覚のためにかなりうまく機能するAtkinson ディザを手に入れました。
今、私は 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 の例はありますか? で何が起こっているのか説明していただけますthreshold_map_4x4[x mod 4][y mod 4]
か?
( Meemoo Gameboy GIFerizerで作成)
理解した。ウィキペディアでは、「たとえば、モノクロ レンダリングでは、ピクセルの値 (0 ~ 9 の範囲にスケーリング) がマトリックスの対応するセルの数値よりも小さい場合は、そのピクセルを黒でプロットし、そうでない場合は白でプロットします。 ." js では、現在のピクセル (0 ~ 255) とマップの値 (15 ~ 240) を平均し、それをしきい値 (通常は 129) と比較することで、良い結果が得られました。
var map = (imageData.data[currentPixel] + bayerThresholdMap[x%4][y%4]) / 2;
imageData.data[currentPixel] = (map < threshold) ? 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;
}
最適化のヒントをいただければ幸いです。