Convert from 32-BPP to 8-BPP Indexed (C #)

I need to take a full color JPG image and reassign its colors to an indexed palette. The palette will consist of certain colors populated from the database. I need to match each color of the image with its "closest" value in the index. I am sure that there are different algorithms for comparing and calculating the β€œclosest” value. Search only for C #, .NET libraries.

(It will be used in a process where we have 120 or so specific button colors, and we want to match any image with these 120 colors to make a collage).

+6
c # image gdi
source share
4 answers

Nothing will help you with GDI. Indexed images seem to be too far behind the technology that Microsoft cares about. All you can do is read and write indexed image files.

Usually there are usually two steps when quantizing colors in an image:
1) Find the best palette for the image (Color quantization)
2) Compare the source solors with the found palette (Color Mapping)

From what I understand, you already have a palette in the database, which means that the hardest part for you. All you have to do is map the 24-bit colors to the provided palette colors. If you do not have an initial palette, you will have to calculate it yourself using the quantization algorithm: the most well known are Octrees or Median Cut. Median Cut gives better results, but is slower and harder to implement and fine-tune.

To display colors, the simplest algorithm in your case is to calculate the distance from the source color to all colors in the palette and select the closest one.

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 think through the channels so that the blue has less weight, not too overboard, otherwise it will give terrible results, in particular 30/59/11 will not work:

 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; } 

Name this thing for all source colors and palettes and find Min. If you cache your results as you move on the map, it will be very fast.

In addition, the color of the source will rarely match the color of the palette, so as not to create stripes and simple areas and loss of detail in your image. To avoid this, you can use anti-aliasing. The simplest algorithm and the one that gives the best results is Diffusion Dithering.

Once you have matched your colors, you will have to manually lock the bitmap and write indexes where .Net will not allow you to write an indexed image.

+3
source share

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

Check out this article for sample code.

The article discusses obtaining the final palette for the image, but your process will be the reverse of the second part, reduce only the most used colors that are close to this palette.

+2
source share

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

0
source share

The word JPEG should contain audio signals. Images are most likely already in a highly quantized color space, and further oversampling will potentially lead to smoothing. If you can, work with uncompressed images to reduce this effect.

The answer to your question: yes - you can save images in an alternative format, but I'm not sure that the native functionality is adequate to what sounds like a rather complicated requirement. If you can define a color palette from a collection of images, you are likely to improve output quality.

The already mentioned blog entry, β€œUsing GDI + to Save Crystal-Clear GIF Images with .NET,” contains useful code links.

0
source share

All Articles