Brute Force Colors
arnaud-carre.github.io
arnaud-carre.github.io
As an analogy. Suppose we have a simple gradient from black to white (and that we already have those two shades locked down). Now we're tasked with finding a third shade. This type of algo should find the shade at 50% as the one that reduces error the most. If we then find another, it'll be one either at 25% or 75%. An algo that goes through all the combinations of two entries should find that picking 33% and 66% might reduce the overall error.
I feel like I'm missing something.
One other obvious optimization is to use a more sophisticated metric for "closeness" based on human color perception, not just simple pixel value delta- that could make a huge difference for the skin tones in the final example image.
Without careful analysis it is really hard to tell, at least for me, how a greedy approach compares to the optimal solution, but I would guess that one gets pretty close but I do not think that one is guaranteed to find the optimal solution. I would also guess that one could create pathological cases where the greedy approach produces surprisingly bad results.
I was thinking the same thing: what if we looked at the next two pixels and tried to find the values that minimized total error. If done right that should essentially give horizontal 2x1 dithering for free.
The thing is of course that the errors propagate with HAM as you can always only adjust one channel and so any change to a pixel will or at least might also affect errors of subsequent pixels. On top of that you might have error propagation from a dithering algorithm. But I think here I have reached the limit of my reasoning capability without having to pull out pen and paper and really digging into it. Final note, I would probably try to find a iterative algorithm that tries to reduces the error in several iterations as I think jumping directly to the best solution is probably pretty hard.
My current local code has new strategies and also does dynamic hires, but it's an uncommitted mess.
https://trixter.oldskool.org/2015/04/07/8088-mph-we-break-al...
PS. Have you compared HAM-6 to HAM-8 modes?
I was playing around with 68K assembler to test this out: cleared one screen buffer to white, drew a diagonal black line — cleared the other screen buffer to white and also drew a diagonal black line ... a mirror of the first one though.
Watching it page flip between the two screen buffers for every screen refresh caused me to notice something interesting: you could actually get a pseudo 50% gray where a black pixel and white pixel shared the same row and column on the two buffers.
It might have made an interesting demo, but eating another 22K on a computer that was struggling (not the lower config models) with 128K seemed like a bad design decision. I suspect too, at 30 FPS, the gray would have been a bit "strobish"?
I tried it on Playdate but the screen (Sharp Memory LCD) is so good that refresh needs to be 100Hz for the switching to blur into grey.
There are many hacks that can be used to improve this method I just outlined. Eg instead of picking a new buffer every frame, you can decide "switch or stay" from the current buffer. Or even just change which ones are displayed in some predetermined repeating sequence.
E.g. see:
https://www.godbolt.org/z/sYPd4onfT
...any reasonably "modern" C compiler should generate the same code for both functions.
(also I wonder if an even better image quality could be achieved by generating a copper list next to the image data which updates the color palette mid-image?)
> It means 64 color distances to compute
Isn't it unnecessary to test all 16 R, G, and B values? I know the title of the post says "brute force", but you already know the desired R, G, or B value, and any other value seems guaranteed to have a larger color distance. (The distance function is subtracts actual R from desired R, right?)
Seems like you could compute only 19 color distance instead of 64: the closest R, G, and B plus the 16 palette entries.
Then, on Hacker News, 35+ years later… :D