Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I got better results just dithering the rgb channels separately (so effectively an 8 colour palette, black, white, rgb, yellow, cyan, magenta). In p5js:

    var img
    var pixel
    var threshold
    var error = [0, 0, 0]
    var a0

    function preload() {
      img = loadImage("https://upload.wikimedia.org/wikipedia/commons/thumb/4/44/Albrecht_D%C3%BCrer_-_Hare%2C_1502_-_Google_Art_Project.jpg/1920px-Albrecht_D%C3%BCrer_-_Hare%2C_1502_-_Google_Art_Project.jpg")
    }

    function setup() {
      // I'm just using a low discrepancy sequence for a quasirandom
      // dither and diffusing the error to the right, because it's
      // trivial to implement
      a0 = 1/sqrt(5)
      pixelDensity(2)
      createCanvas(400, 400);
      image(img, 0, 0, 400, 400)
      loadPixels()
      pixel = 0
      threshold = 0
    }

    function draw() {
      if (pixel > 400*400*16) {
        return
      }
      for (var i = 0; i < 2000; i++) {
        threshold = (threshold + a0)%1
        for(var j=0; j< 3; j++) {
          var c = pixels[pixel + j]
          pixels[pixel + j] = c + error[j] > threshold * 255 ? 255 : 0
          error[j] += c - pixels[pixel + j]
        }
        pixel += 4
      }
      updatePixels()
    }
Of course this isn't trying to pick the closest colour in the palette as you're doing - it's just trying to end up with the same intensity of rgb as the original image. It does make me wonder if you should be using the manhattan distance instead of euclidean, to get the errors to add correctly.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: