|
We where mainly (maybe only) loading images with a palette. So we where dithering one palette to another, meaning there was a max of 256 colors in the source image (and often less than that). I This allowed us to quickly calculate the total number of a given color, and for each color calculate how close it as to existing colors in our palette.
I guess it is pretty useless these days as no one works with palettes (I think we had a jpg decoder for fun, but probably was sticking to gif and various other formats for images we really needed).
Once the palette was locked in for an image, we could just run the Floyd-Steinberg. It only requires finding the nearest color per pixel as "blending" is done by pushing the error ahead of the calculations (at the cost of one scanline extra memory consumed - though I guess you could stamp it into the bitmap data directly). No problem on a 500KB system with relative small images.
We had the advantage advantage that low CPU spec systems where typically also running lower colors (so we only had to search for nearest color in 16 or 32 target colors), while systems running 256 colors typically also had more CPU power.
|
|
|
|
|
Actually palettes are very useful these days for e-paper displays, which are either monochrome, or have a *fixed palette* of a handful of colors.
That's primarily why my GFX library supports it.
Real programmers use butterflies
|
|
|
|
|
A N^2-level grey scale dithering for a 2-colour screen (B&W) may be performed with an NxN integer matrix. If N is a power of 2, the most expensive operation would be masking the X, Y ordinates to the range 0 .. N-1, and reading the dither threshold value.
Unless you are dealing with giant pictures, how would the dithering take that long?
(You could even speed the rendering by dithering a partial block of the picture in memory, and then bitblt-ing the block to the screen. The size of the block would depend on the memory available.)
As for colour dithering, assuming that you have an 8-colour screen (on/off for each of R,G,B), perhaps you could use a B&W dithering algorithm on each level - R, G, B, and then combine them. I do not know about the quality of the colours, though...
Freedom is the freedom to say that two plus two make four. If that is granted, all else follows.
-- 6079 Smith W.
|
|
|
|
|
Grayscale dithering is not color dithering. Also it's much faster to dither when you have a palette where the colors are evenly distributed/gradiated.
When you're doing color matching to dither between, say 7 available colors while loading a 24-bit color JPEG, that's a different story.
You can't color dither like you suggest. You have to mix two colors, not just one color and a fixed color like black
This is what finding the two colors to mix looks like - or at least one of the ways I use:
template<typename PaletteType>
gfx_result dither_mixing_plan_fast(const PaletteType* palette, typename PaletteType::mapped_pixel_type color, dither_mixing_plan_data_fast* plan) {
gfx_result rr ;
if(nullptr==plan || nullptr==palette) {
return gfx_result::invalid_argument;
}
rgb_pixel<24> rgb888;
rr = convert(color,&rgb888);
if(gfx_result::success!=rr) {
return rr;
}
const unsigned r= rgb888.template channel<channel_name::R>(),
g=rgb888.template channel<channel_name::G>(),
b=rgb888.template channel<channel_name::B>();
*plan = { {0,0}, 0.5 };
double least_penalty = 1e99;
for(unsigned index1 = 0; index1 < PaletteType::size; ++index1)
for(unsigned index2 = index1; index2 < PaletteType::size; ++index2)
{
typename PaletteType::mapped_pixel_type mpx1;
rr=palette->map(typename PaletteType::pixel_type(index1),&mpx1);
if(gfx_result::success!=rr) {
return rr;
}
typename PaletteType::mapped_pixel_type mpx2;
rr=palette->map(typename PaletteType::pixel_type(index2),&mpx1);
if(gfx_result::success!=rr) {
return rr;
}
rr = convert(mpx1,&rgb888);
if(gfx_result::success!=rr) {
return rr;
}
unsigned r1= rgb888.template channel<channel_name::R>(),
g1=rgb888.template channel<channel_name::G>(),
b1=rgb888.template channel<channel_name::B>();
rr = convert(mpx2,&rgb888);
if(gfx_result::success!=rr) {
return rr;
}
unsigned r2= rgb888.template channel<channel_name::R>(),
g2=rgb888.template channel<channel_name::G>(),
b2=rgb888.template channel<channel_name::B>();
int ratio = 32;
if(mpx1.native_value != mpx2.native_value)
{
ratio = ((r2 != r1 ? 299*64 * int(r - r1) / int(r2-r1) : 0)
+ (g2 != g1 ? 587*64 * int(g - g1) / int(g2-g1) : 0)
+ (b1 != b2 ? 114*64 * int(b - b1) / int(b2-b1) : 0))
/ ((r2 != r1 ? 299 : 0)
+ (g2 != g1 ? 587 : 0)
+ (b2 != b1 ? 114 : 0));
if(ratio < 0) ratio = 0; else if(ratio > 63) ratio = 63;
}
unsigned r0 = r1 + ratio * int(r2-r1) / 64;
unsigned g0 = g1 + ratio * int(g2-g1) / 64;
unsigned b0 = b1 + ratio * int(b2-b1) / 64;
double penalty = dither_mixing_error(
r,g,b, r0,g0,b0, r1,g1,b1, r2,g2,b2,
ratio / double(64));
if(penalty < least_penalty)
{
least_penalty = penalty;
plan->colors[0] = index1;
plan->colors[1] = index2;
plan->ratio = ratio / double(64);
}
}
return gfx_result::success;
}
Edit: Thanks! I found a bug in the above code when I pasted it to you, I fixed the bug and now it's fast-ish and usable.
Real programmers use butterflies
modified 18-Jun-21 9:49am.
|
|
|
|
|
Was the word "algorithm" created to honour Al Gore's contribution to computer science?
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
OriginalGriff wrote: Was the word "algorithm" created to honour Al Gore's contributions to computer science dancing and speling?
FTFY
EDIT: added speling to his accomplishments.
Freedom is the freedom to say that two plus two make four. If that is granted, all else follows.
-- 6079 Smith W.
|
|
|
|
|
Daniel Pfeffer wrote: added speling to his accomplishments. A bit too late. They already misspelled his name when naming those decorative melons "Gourds".
(I can hear you vine after you read that all the way over here)
Ravings en masse^ |
---|
"The difference between genius and stupidity is that genius has its limits." - Albert Einstein | "If you are searching for perfection in others, then you seek disappointment. If you seek perfection in yourself, then you will find failure." - Balboos HaGadol Mar 2010 |
|
|
|
|
|
W∴ Balboos, GHB wrote: I can hear you vine
oy vey-ing, not vining.
Freedom is the freedom to say that two plus two make four. If that is granted, all else follows.
-- 6079 Smith W.
|
|
|
|
|
When a bullfighter is gored, does that mean he sat through one of Al's speeches?
Ravings en masse^ |
---|
"The difference between genius and stupidity is that genius has its limits." - Albert Einstein | "If you are searching for perfection in others, then you seek disappointment. If you seek perfection in yourself, then you will find failure." - Balboos HaGadol Mar 2010 |
|
|
|
|
|
Or is it more effective than the Vatican's method?
|
|
|
|
|
That depends on your definition of effectiveness.
Freedom is the freedom to say that two plus two make four. If that is granted, all else follows.
-- 6079 Smith W.
|
|
|
|
|
Woman goes into a pharmacy and asks the pharmacist for poison.
What for?
I want to kill my husband.
Why I can't give you poison that is not only illegal but I would be an accomplice.
She reaches in her purse and takes out a picture of her husband and his wife in an intimate embrace and hands it to the pharmacist.
You didn't tell me you had a prescription!
OK I 'm bored and tired, I'll get my coat.
|
|
|
|
|
I'm pretty sure that this is a Leslie, but I can't find it. Maybe it was originally in the Soapbox?
Freedom is the freedom to say that two plus two make four. If that is granted, all else follows.
-- 6079 Smith W.
|
|
|
|
|
|
Damn and I even posted it and didn't remember.
Guess I'm getting Oldtimers
|
|
|
|
|
In your defense, that was 14 years ago.
I’ve given up trying to be calm. However, I am open to feeling slightly less agitated.
|
|
|
|
|
ouch!
Charlie Gilley
<italic>Stuck in a dysfunctional matrix from which I must escape...
"Where liberty dwells, there is my country." B. Franklin, 1783
“They who can give up essential liberty to obtain a little temporary safety deserve neither liberty nor safety.” BF, 1759
|
|
|
|
|
Mike Hankey wrote: a picture of her husband and his wife in an intimate embrace
Something doesn't seem right with this statement...
|
|
|
|
|
Quote: "Cockroaches can live for several weeks with their heads cut off, because their brains are located inside their body. They would eventually die from being unable to eat."
Ravings en masse^ |
---|
"The difference between genius and stupidity is that genius has its limits." - Albert Einstein | "If you are searching for perfection in others, then you seek disappointment. If you seek perfection in yourself, then you will find failure." - Balboos HaGadol Mar 2010 |
|
|
|
|
|
Their body can live without head. Their head can live without body. Both never die, even if unable to eat.
|
|
|
|
|
11917640 Member wrote: Both never die,
I suppose that's true for certain values of never
|
|
|
|
|
What's so special about that? I know quite a few people who keep their brains up their arse / ass!
Freedom is the freedom to say that two plus two make four. If that is granted, all else follows.
-- 6079 Smith W.
|
|
|
|
|
They die when you cut off their heads though... Or so I've heard people say
|
|
|
|
|
|
Sander Rossel wrote: Or so I've heard people say
You must know some very odd people!
Freedom is the freedom to say that two plus two make four. If that is granted, all else follows.
-- 6079 Smith W.
|
|
|
|