开发者

Bayer Ordered Dithering

I'm updating a plugin for Paint.net which i made some months ago, it's called Simulate Color Depth and it reduces the number of colors in the image to the chosen BPP and for a long time it have had dithering included but NEVER ordered dithering and i thought it would be a nice addition to have that in so i started to search on the internet for something useful, i ended up on this wiki page here http://en.wikipedia.org/wiki/Ordered_dithering, and tried to do as written in the pseudo code

for (int y = 0; x < image.Height; y++)
{  
    for (int x = 0; x < image.Width; x++)
    {
        Color color = image.GetPixel(x, y);  
        color.R = color.R + bayer8x8[x % 8, y % 8];  
        color.G = color.G + bayer8x8[x % 8, y % 8];  
        color.B = color.B + bayer8x8[x % 开发者_StackOverflow社区8, y % 8];  
        image.SetPixel(x, y, GetClosestColor(color, bitdepth);  
    }  
}

but the result is way too bright so i decided to check the wiki page again and then i see that there's a "1/65" to the right of the threshold map which got me thinking of both error diffusing (yes i know, weird huh?) and dividing the value i get from bayer8x8[x % 8, y % 8] with 65 and then multiply the value with the color channels, but either the results were messy or else still too bright (as i remember it) but the results were nothing like i have seen elsewhere, either too bright, too high contrast or too messy and i haven't found anything really useful searching through the internet, so do anyone know how i can get this bayer dithering working properly?

Thanks in advance, Cookies


I don't think there's anything wrong with your original algorithm (from Wikipedia). The brightness disparity is probably an artifact of monitor gamma. Check Joel Yliluoma's Positional Dithering Algorithm, the appendix about gamma correction from this article about a dithering algorithm invented by Joel Yliluoma (http://bisqwit.iki.fi/story/howto/dither/jy/#Appendix%201GammaCorrection) to see an explanation of the effect (NB: page is quite graphics-heavy).

Incidentally, perhaps the (apparently public-domain) algorithm detailed in that article may be the solution to your problem...


Try this:

color.R = color.R + bayer8x8[x % 8, y % 8] * GAP / 65;

Here GAP should be the distance between the two nearest color thresholds. This depends on the bits per pixel.

For example, if you are converting the image to use 4 bits for the red component of each pixel, there are 16 levels of red total. They are: R=0, R=17, R=34, ... R=255. So GAP would be 17.


Found a solution, levels is the amount of colors the destination images should have and d is the divisor (this is normalized from my code (which uses paint.net classes) to simple bitmap editting with GetPixel and SetPixel)

    private void ProcessDither(int levels, int d, Bitmap image)
    {
        levels -= 1;
        double scale = (1.0 / 255d);
        int t, l;

        for ( int y = rect.Top; y < rect.Bottom; y++ )
        {
            for ( int x = rect.Left; x < rect.Right; x++)
            {
                Color cp = image.GetPixel(x, y);

                int threshold = matrix[y % rows][x % cols];

                t = (int)(scale * cp.R * (levels * d + 1));
                l = t / d;
                t = t - l * d;
                cp.R = Clamp(((l + (t >= threshold ? 1 : 0)) * 255 / levels));

                t = (int)(scale * cp.G * (levels * d + 1));
                l = t / d;
                t = t - l * d;
                cp.G = Clamp(((l + (t >= threshold ? 1 : 0)) * 255 / levels));

                t = (int)(scale * cp.B * (levels * d + 1));
                l = t / d;
                t = t - l * d;
                cp.B = Clamp(((l + (t >= threshold ? 1 : 0)) * 255 / levels));

                image.SetPixel(x, y, cp);
            }
        }
    }

    private byte Clamp(int val)
    {
        return (byte)(val < 0 ? 0 : val > 255 ? 255 : val);
    }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜