block by veltman 1298cabd1ffd10c9c15d99a8395c6957

Quadtree pixelation

Full Screen

Inspired by Koalas to the max.

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
</head>
<body>
  <canvas width="960" height="500"></canvas>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>

let width = 960,
    height = 500,
    canvas = document.querySelector("canvas"),
    context = canvas.getContext("2d"),
    active = width * height,
    img = new Image(),
    tree = d3.quadtree()
      .extent([[0, 0], [width, height]]);

img.onload = draw;
img.src = "neon.jpg";

function draw() {
  context.drawImage(img, 0, 0);
  let data = context.getImageData(0, 0, width, height).data;
  for (let x = 0; x < width; x++) {
    for (let y = 0; y < height; y++) {
      tree.add(colorAt(data, x, y));
    }
  }

  setAverageColor(tree.root());
  depixelate(tree.root());
}


function depixelate(node, x=0, y=0, w=(tree._x1 - tree._x0), h=(tree._y1 - tree._y0), depth=1) {

  context.fillStyle = "rgb(" + node.color.map(d => Math.round(d)) + ")";
  context.fillRect(x, y, w, h);

  if (node.length) {
    node.forEach((child, i) => {

      let cw = w / 2,
          ch = h / 2,
          cx = i % 2 ? x + cw : x,
          cy = i > 1 ? y + ch : y;

      setTimeout(() => depixelate(child, cx, cy, cw, ch, depth + 1), depth > 7 ? 0 : d3.randomExponential(1 / 1000)());
    });
  } else {
    active--;
    if (!active) {
      active = width * height;
      setTimeout(() => depixelate(tree.root()), 500);
    }
  }
}

function setAverageColor(node) {
  if (!node.length) {
    return node.color = node.data.slice(2);
  }
  return node.color = arrayMean(node.filter(d => d).map(setAverageColor));
}

function arrayMean(arrays) {

  let mean = new Array(3).fill(0);

  for (let i = 0, l = arrays.length; i < l; i++) {
    for (let j = 0; j < 3; j++) {
      mean[j] += arrays[i][j] / l;
    }
  }

  return mean;

}

function colorAt(data, x, y) {
  let index = y * width + x;

  return [x, y, data[index * 4], data[index * 4 + 1], data[index * 4 + 2]];
}

</script>