fellow devs!
I am trying to dither a 8-bit grayscale image to a 2-bit / 4 color image with an ordered dithering based on a Bayer 8×8 matrix. My result is somewhat there, but not quite. I kept banging my head at the problem but can't figure out where I went wrong so any help would be greatly appreciated.
Here's my code:
// image_array_2d is a 2d array of grayscale values from 0-255
// matrix is a 2d array with values normalized to be between 0.0 and 1.0
// LUT is an array of 8-bit values, in this case [0, 85, 170, 255]
const MAX = 255
const image_height = image_array_2d.length
const image_width = image_array_2d[0].length
for (let y = 0; y < image_height; y++)
{
for (let x = 0; x < image_width; x++)
{
const threshold = (matrix[y % 8][x % 8]) * MAX
let pixel_value = image_array_2d[y][x];
//pixel_value = gamma_correct(pixel_value)
// find closest value to pixel in LUT
let value_current, value_prev
let closest = lut[0]
for (let i = 0; i < lut.length; i++)
{
const closestDifference = Math.abs(closest - pixel_value);
const currentDifference = Math.abs(lut[i] - pixel_value);
if (currentDifference < closestDifference)
{
value_prev = lut[i-1]
value_current = lut[i]
closest = value_current
}
}
let new_value = 0
new_value = pixel_value > threshold ? value_current : value_prev
new_value = pixel_value >= MAX ? MAX : new_value
image_array_2d[y][x] = new_value
}
}
Just for safety, that's my Bayer matrix before its values get normalized to 0.0 - 1.0
[ 0, 32, 8, 40, 2, 34, 10, 42],
[48, 16, 56, 24, 50, 18, 58, 26],
[12, 44, 4, 36, 14, 46, 6, 38],
[60, 28, 52, 20, 62, 30, 54, 22],
[ 3, 35, 11, 43, 1, 33, 9, 41],
[51, 19, 59, 27, 49, 17, 57, 25],
[15, 47, 7, 39, 13, 45, 5, 37],
[63, 31, 55, 23, 61, 29, 53, 21]
(The following images have been scaled up by 400% for convenience)
This is the image I test my algorithm with:
And this is the intended target:
However, this is the result of the above code with the LUT array being [0, 85, 170, 255]
EDIT: Here's the code pen link:
► https://codepen.io/PixelProphet/pen/JjxLejZ
The function in question is ordered_dither()
I noticed a few issues with your code. The general theme is: you think of color values instead of color ranges.
lut
, instead of searching for an interval your pixel falls into. Remember, you need two colors to dither, not just one.I fixed these issues in your code and it is now working.