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.
I think posterize is more or less what you want:
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.
It’s not. Posterize doesn’t allow for exact control over the number of colours the image will end up with.
The quantization supported by that library is essentially the same as posterize. It doesn’t allow reducing the image to a specified number of colours.
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
colour). Even if I fix those, it’s unclear how to apply the code to a PImage.
Paste that code into a file named “Quantize.java”, and place it into the same folder as your “.pde” file(s).
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
colour), which I’m not sure is the correct way, I still have no idea how to apply it to a
I’d also take a tutorial that explains how to take generic Java code and make it Processing-compatible.
How does one use that? I’ve tried
PImage myImage = new Palette(6, "/path/to/image").img;
image(myImage, 0, 0, 600, 600);
and all I get is a gradient of colours.
Why does the class
Col exist? It doesn’t seem to be doing anything useful. Same with the
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.
That’s what I tried, but all I get is a gradient.
Ah, I thought you wanted the new reduced colors, in a PImage. You want the old image, but now with colors reduced, yes?
addColor() is for if you want to build a palette with manually selected colors vs. sampling a source image. Probably not relevant to your project.
One approach would be to use ToxicLibs: https://github.com/postspectacular/toxiclibs/blob/master/examples/color/ImageColors/ImageColors.pde
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.
In C++ I’ve used https://github.com/exoticorn/exoquant You could port that to Java. It allows you to specify the exact number of colors.
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).