Search code examples
imagemagick

Posterize to 1 bits per channel + extra luma bit


ImageMagick's -posterize 2 flag can be used to convert an image to 1 bits (2 levels) per R/G/B channel. But is there a way to convert to a format where I have two sets of 8 colors, with half and with full intensity? In other words, my target format is 4 bits per pixel: 1 bits per R/G/B and 1 fourth bit for luminosity.

EDIT for clarity based on some comments:

With -posterize 2, you get 8 colors total, since you have three channels and two levels per channel (since 2³ = 8):

Now imagine I have access to seven more colors (because "half-bright black" is still just black):

So I'd like to quantize (?) my picture to these total of 15 colors.

As for the output format, it shouldn't matter, the same way you can use -posterize 2 to e.g. produce a PNG that is formally 24-bit RGB, it just doesn't contain any non-0 or 255 values in any channel.


Solution

  • Based on @Mark Setchell's comment, using these two answers I was able to do this with a two-step process:

    1. Generate an image containing the palette

      $ convert  $(for l in 128 255
        do
          for r in 0 $l
          do
            for g in 0 $l
            do
              for b in 0 $l
              do
                echo "xc:rgb($r,$g,$b)"
              done
            done
          done
        done) +append palette.png
      

      This generates a file with 16 colors, because xc:rgb(0,0,0) is generated twice; but that should be OK AFAICT.

    2. Use this palette for color mapping

      $ convert foo.png +dither -map palette.png result.png
      

    While this does technically do what I set out to do, it turns out its result is quite poor; but that's for a separate question.