English 中文(简体)
Convert from 32-BPP to 8-BPP Indexed (C#)
原标题:

I need to take a full color JPG Image and remap it s colors to a Indexed palette. The palette will consist of specific colors populated from a database. I need to map each color of the image to it s "closest" value in the index. I am sure there are different algorithms for comparing and calculating the "closest" value. Looking for C#, .NET managed code libraries only.

(It will be used in a process where we have 120 or so specific colors of buttons, and we want to map any image to those 120 colors to make a collage).

问题回答

Nothing will help you with GDI. It seems indexed images are too backward a technology for Microsoft to care. All you can do is read and write indexed image files.

There are usually two step when quantizing colors in an image:
1) Find the best palette for the image (Color Quantization)
2) Map the source solors to the found palette (Color Mapping)

From what I understand, you already have the palette in the database, that means the hardest part has been done for you. All you need to do is map the 24 bit colors to the provided palette colors. If you don t have the starting palette, then you will have to compute it yourself using a quantisation algorithm: Octrees or Median Cut are the most well known. Median Cut gives better results but is slower and harder to implement and fine tune.

To map the colors, the simplest algorithm in your case is to calculate the distance from your source color to all the palette colors and pick the nearest.

float ColorDistanceSquared(Color c1, Color c2)
{
    float deltaR = c2.R - c1.R;
    float deltaG = c2.G - c1.G;
    float deltaB = c2.B - c1.B;
    return deltaR*deltaR + deltaG*deltaG + deltaB*deltaB;
}

You can also ponderate the channels so that blue has less weight, don t go too overboard with it, else it will give horrible results, specifically 30/59/11 won t work at all:

float ColorDistanceSquared(Color c1, Color c2)
{
    float deltaR = (c2.R - c1.R) * 3;
    float deltaG = (c2.G - c1.G) * 3;
    float deltaB = (c2.B - c1.B) * 2;
    return deltaR*deltaR + deltaG*deltaG + deltaB*deltaB;
}

Call that thing for all source and palette colors and find the Min. If you cache your results as you go in a map, this will be very fast.

Also, the source color will rarely fit a palette color enough to not create banding and plain areas and loss of details in your image. To avoid that, you can use dithering. The simplest algorithm and the one that gives the best results is Error Diffusion Dithering.

Once you mapped your colors, you will have to manually lock a Bitmap and write the indices in there as .Net won t let you write to an indexed image.

This process is called Quantization. Since each color represents 3 packed values, you ll need to use Octrees to solve this problem.

Check out this article with example code.

The article focuses on getting the ultimate palette for the image, but your process it would be reverse for the second part, only reduce the most used colors that are close to the given palette.

I had to do this in a big .NET project. There s nothing in the framework for it, but this article quickly led me to a solution: http://codebetter.com/blogs/brendan.tompkins/archive/2004/01/26/6103.aspx

The JPEG word should ring alarm bells. The images are very likely to already be in a heavily quantised colour space, and further resampling will potentially introduce aliasing. If you can, work from uncompressed images to reduce this effect.

The answer to your question is yes - you can save the images in an alternate format - but I m not sure if the native functionality is adequate for what sounds like a quite complex requirement. If you are able to define the colour palette from the collection of images, you will likely improve the quality of the output.

The already referenced blog entry entitled Use GDI+ to Save Crystal-Clear GIF Images with .NET contains useful references to code.





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签