【问题标题】:monochrome dithering in JavaScript (Bayer, Atkinson, Floyd–Steinberg)JavaScript 中的单色抖动(Bayer、Atkinson、Floyd–Steinberg)
【发布时间】:2012-09-14 10:09:29
【问题描述】:

我正在使用 HTML5 中的网络摄像头过滤器。有一个Atkinson dither 非常适合那种老式的 Mac 感觉。


Live | Code

现在我正在尝试为 1989 年 Gameboy 的感觉制作一个拜耳订购的抖动选项。

read up on the algorithm,但我无法将此伪代码转换为 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;
}

我会很感激优化提示。

【问题讨论】:

    标签: javascript image-processing canvas matrix dithering


    【解决方案1】:

    这是我所有的单色抖动功能,可用作网络工作者:https://github.com/meemoo/meemooapp/blob/master/src/nodes/image-monochrome-worker.js

    带网络摄像头的现场演示:http://meemoo.org/iframework/#gist/3721129

    【讨论】:

    • @500-InternalServerError :) 已修复。
    【解决方案2】:

    我将其作为调试代码:

    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);
    

    而且它似乎工作正常,你可以改变深度变量来改变分色。

    【讨论】:

    • 因为它是单色的,你可以把它改成:pixel[ a ] = pixel[ a + 1 ] = pixel[ a + 2 ] = ( (pixel[ a ]+ b) / depth | 0 ) * depth;
    • 检查控制台,我的跨域图像有问题(我使用的是旧浏览器...)。所以我转到图片网址,打开控制台并复制粘贴代码,它工作正常(tof.canardpc.com/view/f47567dc-d06b-4fea-8b9f-ac7c23e9ceb8.jpg)或者你想要另一个结果?
    • 是的,我想要单色输出。我将我的算法放在原始问题中,并制作了这个现场演示:meemoo.org/iframework/#gist/3721129
    猜你喜欢
    • 2021-11-13
    • 2022-01-22
    • 1970-01-01
    • 2019-09-16
    • 2011-08-21
    • 2014-10-13
    • 2014-06-01
    • 2021-02-01
    • 1970-01-01
    相关资源
    最近更新 更多