Is there a simple way (preferably a function) to apply color quantization to an image? Specifically I’d like to pick a PImage and an int of colours, and it’d reduce the number of colours to that int, trying to keep it as close as possible to the original.
For reference, imagemagick can do it easily (I’d link to it, but discourse isn’t letting me): magick input.png +dither -colors 6 output.png outputs an image with 6 colours. Not shades, but colours. The +dither is actually not doing dithering but banding, which is closer to what I want.
POSTERIZE
Limits each channel of the image to the number of colors specified as the parameter. The parameter can be set to values between 2 and 255, but results are most noticeable in the lower ranges.
Could I please get a bit of guidance on how to apply that in processing? Adding that code gives a ton of errors in the IDE (related to static and colour). Even if I fix those, it’s unclear how to apply the code to a PImage.
Yes, that’s how far I got before. But it doesn’t work right off the bat (as I mentioned, it complains about static and later color, because it tries to assign it to an int). Even if I fix those (removing all static and renaming color to colour), which I’m not sure is the correct way, I still have no idea how to apply it to a PImage.
Basically the technique is to measure the distance between RGB colors as if they were points in space.
In this example you first create a palette by measuring the distance between each color and black (0,0,0). Then you can evaluate any new colors by returning the palette color they’re closest to.
The Col class is used for making that calculation–it contains a color and a distance measurement. You could do the same with an array of colors and an array of floats, but I find this approach easier.
That explains what the code does (though I still don’t get why have an extra class for Col instead of keeping everything in the same one), but not how to use it.
So are you saying your code doesn’t actually spit out the new image with reduced colours?
Hmm. Just eyeballing it, it looks like Palette.img is a PImage (line 19), and it is populated from the Pallete.colors array by the Palette.createImage() method. When you call Palette.sample(), it writes values into colors[], then calls createImage() which copies them into img. You can now access that image. If you want, you could modify createImage() – and sample() – to return it, rather than void.
The tricky part is that to calculate the histogram it uses a float tolerance value, and it’s not known in advance how many colors you will get. If performance is not so important, you could run Histogram.newFromARGBArray multiple times, tweaking the tolerance until you get the number of colors you want.
One more approach is to avoid reinventing the wheel and call a command line program like imagemagick (if that is allowed by your project’s constraints).