# 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.

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