I have a number of ARGB images (alpha will always be 0 or 1, and if required I can discard the alpha channel to have only RGB input.) Each image is guaranteed to have <255 unique colours in it.
I would like to convert these images to 8-bit single-channel (grayscale only) where each grayscale value represents a particular colour in the source image.
To be clear, this isn't just colour reduction, since I want to ensure that a different grayscale value is produced for the source RGB (0, 0, 255) vs (255, 0, 0). That is, the luminance of the colour should not determine wha the grayscale pixels' value is. Rather, each unique source colour should map to a single destination colour, *and vice-versa*.
However, I don't actually care WHAT colours are produced in the output L8 image, as long as they have unique 1:1 mapping to source colours. That is to say, they could simply be allocated starting from 1. In other words, rather than thinking in terms of colour-to-grayscale, the operation is more accurately like converting RGB colour to 8-bit RGB palletized, then replacing the palette entries with a grayscale ramp.
Any advice on how to achieve this would be greatly appreciated.
Converting ARGB image with <256 Colours to single channel
Re: Converting ARGB image with <256 Colours to single channe
This should do the first part (converting your 32-bit ARGB to an 8-bit paletted PNG:
If that works, then replacing the palette (PNG PLTE chunk)
with a grayscale ramp would be pretty simple to do. You may need to convert your input
to raw RGBA or RGB or maybe PPM format first. For example:
logo.ppm has 256 colors as an RGB PPM
logo.png has 256 colors with a 256-color palette.
As you hinted, simply converting to grayscale results in an image with 173 levels, so indeed
you'd need to replace the palette with a gray ramp. You could use pngsplit (which
comes with pngcheck from libpng.org):The resulting bwramp.png has 256 colors (gray levels). Maybe there is a simple
way of replacing the palette within ImageMagick, but I find it easy enough to use
pngsplit.
Finally, if you don't want PNG output,
or whatever format you like.
Code: Select all
convert input output.png
with a grayscale ramp would be pretty simple to do. You may need to convert your input
to raw RGBA or RGB or maybe PPM format first. For example:
Code: Select all
convert logo: logo.ppm
identify logo.ppm
identify -verbose logo.ppm | grep Colors
convert logo.ppm logo.png
identify logo.ppm
identify -verbose logo.png | grep colors
logo.png has 256 colors with a 256-color palette.
As you hinted, simply converting to grayscale results in an image with 173 levels, so indeed
you'd need to replace the palette with a gray ramp. You could use pngsplit (which
comes with pngcheck from libpng.org):
Code: Select all
convert -size 256x1 gradient:black-white png8:blackwhite.png
identify -verbose blackwhite.png | grep Colors
pngsplit logo.png
pngsplit blackwhite.png
cat logo.png*sig logo*IHDR blackwhite*PLTE logo*IDAT logo*IEND > bwramp.png
identify bwramp.png
identify -verbose bwramp.png | grep Colors
way of replacing the palette within ImageMagick, but I find it easy enough to use
pngsplit.
Finally, if you don't want PNG output,
Code: Select all
convert bwramp.png output.tiff