Search code examples
imagemagicktransparency

imagemagick: set transparency by similarity to black


I have a image with filled contours of a certain colormap where white is the lowest level. I would not like to add alpha transparency to that map where white is totally transparent, and the less "similar" the color is to white, the less transparent it is (up to a maximum "fuzziness"). How can I do this?

Edit: To clarify: I want to assign for example:

  • all colors that are 1% fuzzy-similar to white 100% transparency
  • all colors that are 2-3% fuzzy-similar to white 99% transparency
  • all colors that are 3-4% fuzzy-similar to white 98% transparency
  • and so on, up to say 20% fuzzy-similar to white

Example: enter image description here


Solution

  • Updated Answer

    I think I have a better handle on what you want now. How about we calculate the lightness of your image, normalise it, split it into a number of discrete values (by binning) and then use that as the transparency... something like this:

    convert image.png                                          \
       \(                                                      \
          +clone -colorspace HSL -separate -delete 0,1         \
          -negate -normalize -posterize 5 -black-threshold 60% \
       \) -compose copyopacity -composite result.png
    

    enter image description here

    Let me explain that monster command. It says... Load up image.png and then do some processing "on-the-side" - that's everything in the parentheses (...). When you've done the "on-the-side" processing, use whatever you generated as the opacity/alpha channel for the original image -compose copy opacity -composite and save the result.

    Now, let's look at the "on-the-side" processing inside the (). That says... Copy the original image (+clone) and convert it to Hue, Saturation and Lightness channels rather than RGB (-colorspace HSL). Then separate the 3 channels (-separate) and discard channels 0 and 1 - so I discard the Hue (colour) and the Saturation (vividness) and I am just left with the Lightness, or Brightness of your original image - which is what we actually want. Now I normalise (-normalize) that brightness range to the full range 0-255 and convert it into 5 steps with the -posterize 5. So the steps will be 0-50, 50-100, 100-150, 150-200 and 200-255. Then I make all the steps less than 60% solid so that all the shadows and midtones in your image are fully opaque and just the highlights have stepped opacity. That is then used as the alpha channel when I finally exit the parentheses as above.

    If you want to actually see the opacity channel itself that all the "on-the-side" processing generates, just add -write opacity.png after -black-threshold 60% and before the closing ). Then you can preview the opacity channel in file opacity.png.

    I have put it over a chessboard so you can see the transparent areas. You will probably want to change the -posterize parameter to set the granularity and then threshold to leave less than say 80% unaffected.

    In order to fine-tune the method, use this command to generate a gradient, convert it to steps and discard some steps:

    convert -size 256x256 xc:red                                    \
      \( gradient:white-black -posterize 20 -white-threshold 50% \) \
      -compose copyopacity -composite result.png
    

    enter image description here

    Change the 20 and 50% to change the number of steps and the cutoff.

    If you want to composite over a chessboard (checkerboard) like Photoshop does, so that you can see the transparency, use this:

    composite -compose Dst_Over -tile pattern:checkerboard result.png preview.png
    

    enter image description here

    Original Answer

    Build a transparency mask first and then use it as the opacity of your original image.

    So, make a gradient - or any other transparency you fancy:

    convert -size 400x400 gradient:black-white       \
       -fill white -draw "rectangle 100,100 300,300" \
       -fill black -draw "rectangle 150,150 250,250" \
       -define png:color-type=0 alpha.png
    

    enter image description here

    And take a solid red image:

    convert -size 400x400 xc:red red.png
    

    enter image description here

    Now apply the alpha/opacity layer to the solid image:

    convert red.png alpha.png -compose copyopacity -composite result.png
    

    enter image description here