João Costa @JD557@blog.joaocosta.eu Follow

Portuguese software engineer at Kevel.

My instance is running on a small server so please #nobot

Web

https://www.joaocosta.eu/

GitHub

https://github.com/JD557

Twitter

https://twitter.com/JD557

Itch.io

https://jd557.itch.io

  • Notes
  • Articles 6
  • Followers 43
  • Following 59
João Costa's avatar
João Costa
@JD557@blog.joaocosta.eu

Playing around with Ordered Dithering and Bayer Matrices.

Interactive demo with multiple dithering sizes (2x2, 4x4, 8x8 and 16x16): https://joaocosta.eu/Demos/Dither/

This was much simpler than I thought. The whole dithering logic is just:

def buildBayerMatrix(n: Int): Vector[Vector[Int]] =
  if (n <= 1) Vector(Vector(0))
  else {
    val mn2 = buildBayerMatrix(n / 2) // M_(n/2)

    val q1 = mn2.map(_.map(_ * 4)) // 4*M_(n/2)
    val q2 = q1.map(_.map(_ + 2)) // 4*M_(n/2) + 2*J_(n/2)
    val q3 = q1.map(_.map(_ + 3)) // 4*M_(n/2) + 3*J_(n/2)
    val q4 = q1.map(_.map(_ + 1)) // 4*M_(n/2) + 1*J_(n/2)

    q1.zip(q2).map(_ ++ _) ++ q3.zip(q4).map(_ ++ _)
  }

def buildDitherSurface(n: Int): RamSurface = {
  val mask = buildBayerMatrix(n)
  val max  = n * n
  RamSurface(mask.map(_.map(x => Color.grayscale((x * 255) / max))))
}

def ditherImage(image: Surface, ditherMask: Surface): Surface =
  image.view.zipWith(
    ditherMask.view.repeating,
    (color, mask) =>
      Color(
        if (color.r >= mask.r) 255 else 0,
        if (color.g >= mask.g) 255 else 0,
        if (color.b >= mask.b) 255 else 0
      )
  )
Ordered Dithering Demo joaocosta.eu
Half dithered/half normal image of Palácio Nacional da Pena
  • permalink
  • interact from your instance
  • 14 days ago
Powered by microblog.pub 2.0.0+dev (source code) and the ActivityPub protocol. Admin.