みさご解体新書

ハーフトーン

実行例

ソースコード

TypeScript

0.jpg / app.ts

解説/アルゴリズム

ハーフトーンは画像内の範囲ピクセル、たとえば 10x10 ピクセルのような範囲の明るさ平均を算出し、その値をもとに特定の形で描画し直す処理。

上記画像では明るさが大きいほど、大きい白円を描く仕組みになっている。

少ない色で多くの色があるように見えるディザリングの一種でもある。

ハーフトーンのアルゴリズムは、原理的にはモザイクとほぼ同じになる。

コード例

import * as p5 from "p5";

new p5((p: p5) => {
  let image: p5.Image;

  // ハーフトーンの範囲
  const range = 10;

  p.preload = () => {
    image = p.loadImage("./0.jpg");
  };

  p.setup = () => {
    p.createCanvas(p.windowWidth, p.windowHeight);
    image.loadPixels();

    // 画像のピクセルを縦横rangeおきに走査
    for (let y = 0; y < image.height; y += range) {
      for (let x = 0; x < image.width; x += range) {
        // 明るさの合計
        let v = 0;

        // ピクセルを取り出す
        let count = 0;

        // range * rangeの範囲を走査
        for (let yy = 0; yy < range; yy++) {
          for (let xx = 0; xx < range; xx++) {
            const ty = y + yy;
            const tx = x + xx;
            if (ty < image.height && tx < image.width) {
              const color = getPixel(tx, ty);
              const r = p.red(color);
              const g = p.green(color);
              const b = p.blue(color);
              const gray = 0.299 * r + 0.587 * g + 0.114 * b;
              v += gray;
              count++;
            }
          }
        }

        // 明るさの平均を取る
        v /= count;

        // 明るいほど円を大きくする
        const d = p.map(v, 0, 255, 0, range);
        p.circle(x + range / 2, y + range / 2, d);
      }
    }
  };

  function getPixel(x: number, y: number): number[] {
    const i = (y * image.width + x) * 4;
    return [
      image.pixels[i],
      image.pixels[i + 1],
      image.pixels[i + 2],
      image.pixels[i + 3],
    ];
  }
});

内部で利用しているアルゴリズム

グレースケール, 範囲変更による値のマッピング