# Ordered dithering between “discrete” colors?

I want to achieve color dithering between discrete colors like this:

As you can see, there is no gradient, or technically there is, but very discrete as it's only a 3 color image (right bar).

So I want the same results applying ordered dither (or at least try it and see if it works).

I have this test sample:

And this is teh function where i do the dithering:

// OrderedDither applies a Bayer matrix to dither.
func OrderedDither(img image.Image, palette []color.Color) image.Image {

rImage := image.NewRGBA(img.Bounds())

matrix := [][]float64{
{0, 4, 1, 5},
{8, 12, 9, 13},
{2, 6, 3, 7},
{10, 6, 11, 15}}

for j := 0; j < img.Bounds().Max.Y; j++ {
for i := 0; i < img.Bounds().Max.X; i++ {
m := matrix[i%4][j%4] / 16
oldPixel, _ := colorful.MakeColor(img.At(i, j))
oldPixel.R = oldPixel.R*m + oldPixel.R
oldPixel.G = oldPixel.G*m + oldPixel.G
oldPixel.B = oldPixel.B*m + oldPixel.B
newPixel := GetClosestColor(palette, oldPixel)
r, g, b, _ := newPixel.RGBA()

rImage.Set(i, j, color.RGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: 255})
}
}
return rImage

}

I get this:

As you can see, there is not dithering in the borders and the dithering inside the boxes is awful.

Any recommendations?

Edit: I implemented the average distance in the 16 color palette:

r := AverageColorDistance(palette)

for j := 0; j < img.Bounds().Max.Y; j++ {
for i := 0; i < img.Bounds().Max.X; i++ {
m := matrix[i%4][j%4]/16 - 0.5
oldPixel, _ := colorful.MakeColor(img.At(i, j))
oldPixel.R = oldPixel.R + r*m
oldPixel.G = oldPixel.G + r*m
oldPixel.B = oldPixel.B + r*m
newPixel := GetClosestColor(palette, oldPixel)
r, g, b, _ := newPixel.RGBA()

rImage.Set(i, j, color.RGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: 255})
}
}

And the result was not satisfactory neither:

The average color was 0.4792891. (got 256 values in a 16 color palette).

But in either case i still got no blur between the boxes. Should i stop trying to make Ordered work and go Floyd-Steinberg? I want to get some blur between the hard edges.

You have a small mistake in there. First of all, you have to subtract 1/2 from m to make it centered around 8 in this case. Secondly, instead of multiplying m with the r, g and b components of the original color, you have to multiply it by the average distance between the colors. For instance if you have three colors, (0,0,0), (100,0,0) and (255,0,0), then the average distance is

r = ((100 - 0) + (255 - 100) + (255 - 0)) / 3 = 170

For different r, g and b valies, use the 3d extension of the pythagorean theorem to calculate distance.

So basically, instead of

oldPixel.R = oldPixel.R * m + oldPixel.R

do

oldPixel.R = oldPixel.R + r * m
• Thanks. But the average distance between what colors? All in my palette? All in the original image? – Gabriel A. Zorrilla Jul 16 '18 at 2:50
• @Gabriel All your palette – Bálint Jul 16 '18 at 11:00
• did your suggestions, check my edit please! – Gabriel A. Zorrilla Jul 16 '18 at 16:13

This is a very late reply to this, you've likely sorted it out by now but for anyone else who wants an answer to your question.

dithering doesn't do what you are expecting - it breaks the colours up into a limited palette, it doesn't blend between hard edges as you are expecting it to. The outputs you have got are as expected from an ordered dither;

All you need to do to achieve the effect you want is to apply a vertical blur before you dither the image.

• Welcome to the site. As per custom, I invite you to visite the site tour. – Theraot Jun 2 at 4:55
• @ben-jack thanks a lot for the tip. I actually ended making a checkered pattern on N pixels on the edges to "blend" the colors. Making a blur is a nice idea but on the other hand, I may lose the pixel art feel I like to add to the game because the color of the pixels would not be discrete enough. – Gabriel A. Zorrilla Jun 4 at 20:04