Reducing the number of colors in a texture to n

Hi,

I need to reduce the number of colors in an image to a fixed amount, let’s say 8 colors. I’ve seen there are numerous ways to conceptually do it and it is not an easy task because it is related with color perception and not just math. Is there a way to perform this operation via code, possibly not using shaders, unless I can write the result back into the texture. Something like the save for web in photoshop where you can set a gif with 8 colors and the system will preserve the 8 more meaningful colors to save.

Any suggestions?

Ps. If anybody sees a smart way to reduce the color palette of the vertex colors of a mesh by code without using a texture as an intermediate step is very welcome to share it :slight_smile:

Thanks a lot.


This is an example of the images where I need to reduce the color palette. It is the representation of the vertex colors of a mesh. In this case we have more than 500 colors but only a few are really used the rest are shades between them that I need to get rid of.

I think using techniques from image compression algorithms would be the way to go? You wouldn’t need to actually compress the image, but just apply the color reduction steps

JPEG seems to do this: JPEG ‘files’ & Colour (JPEG Pt1)- Computerphile - YouTube
And there is this Color Cell Compression too: Color Cell Compression - Wikipedia
Parameterized Color Cell Compression – Vidar’s Blog (vidarholen.net)

Hi,
Thank you. I can see the utility of what you said but honestly I have no idea in how I could proceed in that way. I checked the links but they are very general and complex explanations of image compression. In my case I need to reduce the palette but not creating averages from areas of the image because the way the image is made is very different from a photo. I need to basically reduce the total number of colors based on the most used on the overall image and change the leftovers to the most similar color inside the palette I decided to save.

Sounds like you already have the idea of an algorithm, then :smiley:
Do a pass on the colors array and rank each unique color by number of uses, keep the n most common for your palette, then do another pass, and for each color that’s not on the palette, find the most similar one and substitute.
Do you have any questions about changing vertex colors, or anything else?

That was the approach I was trying to implement. But one single mesh has 780.000 vertices and is not the most complex one. When I try to make a new array to keep count of how many times a color appears in the image the pc freezes for at least 30 seconds. It’s very heavy on the cpu. Plus once I’ll be able to keep only the most used colors I need a way to establish which is the most similar color for the replacement part, but I have no idea of how to decide the difference between 2 colors. confronting the channels is not a good solution…

How are you creating this array? I don’t think just creating an array should freeze your PC, unless is an absolutely gigantic array.

Search for color quantization. There are several algorithms and JS implementations out there. If you are going for quality it’s not a very fast operation, so if your image is updated in real time it might not solve your issues.

2 Likes

The tests I made were in Unity using both arrays and lists in C#. Custom objects to store just the color value and the number of occurrences. Didn’t try in Babylon yet, I came here to try to understand if there was a simple way to achieve this in which case I would try to port this part of the project in Babylon.

Thanks checking now. I don’t need it to be fast, it’s a one time operation in an app that is used to generate characters so I don’t need it to be realtime.

https://www.geeks3d.com/20091027/shader-library-posterization-post-processing-effect-glsl/

Pass it through a procedural texture with a Posterization effect?

You can either do it manually like here BabylonjsVideoProcessingSample/shader.ts at master · sebavan/BabylonjsVideoProcessingSample · GitHub or rely on a LUT (lookup texture)

1 Like

This sounds like a good use of K-means clustering:

However, since this is an iterative algorithm, you would probably only want to do this precomputed, (or GPU accelerated if you must do this at runtime)

Your constraints of “Don’t change the colors” and “use the most common existing colors” seems to suggest a modification of this algorithm to:

  1. do a first pass, tabulating the most common colors (with some margin of error because, like, float) and then

  2. use the most common n colors as your starting points to cluster to. Iterate through the picture, using Euclidean distance to calculate the “closest” cluster for each pixel.
    (This is where my lack of understanding of color science comes in, I’m not sure if RGB axes should be treated as equal in this calculation, perhaps there exists a linear basis or some function that describes this?)

Or something like that, Its definitely been solved before

1 Like

Hey @Drigax !!! long time no see my friend :slight_smile: Hope everything is good for you

1 Like

WOOT! Welcome back my buddy!. SO happy to see you here!

1 Like

Hi, GitHub - mcychan/PnnQuant.js: Fast pairwise nearest neighbor based algorithm with javascript is very good. Multiple language implementations also