Page 1 of 1

semi-flatten PNG images

Posted: 2011-01-07T04:19:08-07:00
by sas
Hi all,

how would one semi-flatten a PNG image against some background image using ImageMagick?

I.e. blend a partially translucent source image over a background image, but only let the background image shine through on those pixels where the source image has an opacity greater than 0. (Fully transparent pixels in the source image should also be fully transparent in the output image!)

Abstract example:
Image

I would appreciate any help...

Thanks!

Re: semi-flatten PNG images

Posted: 2011-01-07T08:35:59-07:00
by sas
Ok, after more experimentation, I did manage to get it to work after all... (At least for the sample images I checked with.)

If anybody knows if there's a better way to do this, or if it can be written in a more compact form (maybe a single console command instead of three?), then please tell.

-----------------------------------------------------------

Example source: (has translucency due to anti-aliasing!) Image ... Example background for semi-flattening: Image

This is how I went about it:
  1. create a transparency mask from the source image
    (Such that the mask is fully opaque wherever the source image is opaque or translucent, and fully transparent wherever the source image is fully transparent.)
    Image ---> Image

    Code: Select all

    convert source.png -channel matte -threshold 99.5% mask.png
  2. clip the background image with this mask
    Image + Image ---> Image

    Code: Select all

    composite -compose Dst_In mask.png background.png background_masked.png
  3. blend the source image over the clipped background image
    Image + Image ---> Image

    Code: Select all

    composite source.png background_masked.png output.png
-----
EDIT: The first of the three ImageMagick commands above caused the final outcome to have severe artifacts for some of my input images; I found the following replacement for it which seems to eliminate the problem:

Code: Select all

convert source.png -alpha extract -threshold 0% mask.png

Re: semi-flatten PNG images

Posted: 2011-01-09T17:30:54-07:00
by anthony
You are not specifically clear about what you want.

Do you want to just 'overlay' a semi-transparent image on a background?
That results in just background where overlay is transparent
Just teh overlay colors where the overlay image is fully-opaque
and a mix of color where it is semi-transparent.


Or do you just want to replace the colors of the source image with the colors from the
background preserving the transparency? (That is a 'In' compositon.


Basically given the two top images in this diagram....
Image
What do you want the result to be in each of the 4 triangular areas
top, left, right, bottom (always transparent!)
A 5th area is for the results in areas where the first image does not overlap the destination, and can be controlled by a separate '-define' switch.

These are ALL the logical choices for any form of composition, semi-transparency is automatically decided from those choices in a

So what do you want?

If what you want is NOT listed in the above, it is illogical and non-standard. As such you will need to describe it much more fully.

The above table is from IM examples, Duff-Porter Alpha Composition Operators
http://www.imagemagick.org/Usage/compose/#duff-porter

Re: semi-flatten PNG images

Posted: 2011-01-09T17:50:50-07:00
by anthony
your final example results seems to indicate you are wanting to define the background of a GIF image that only has boolean transparency, in termes of a web page background.

That is you want to replace semi-transparency with an appropriate opaque color blend, while keeping fully-transparent transparent and fully-opaque opaque.

If so, say so, rather than what you think you want!

Okay. First, can you align your GIF image with yoru web page background exactly??

That is if you just overlay the GIF image on the background, can you syncronize the image on the web page so the background does not become disjoint?

If you can not do that, then what you are doing is useless!!!! You will always get a disjoint result, so it is better to try and reduce that disjoint result.

You are better off using a 'average' or 'solid' color that roughly matches the whole background for the task.
See GIFs on a background pattern
http://www.imagemagick.org/Usage/formats/#bg_pattern


In BOTH cases you can just overlay the semi-transparent image on your background pattern or average color, then find what pixels did not change, to generate a mask of the image.
One method is shown in Change Mask Composition.
http://www.imagemagick.org/Usage/compose/#changemask
Whcih will directly produce what you want.

Code: Select all

convert  imbackground.png \( +clone imsource.png -composite \) \
      -fuzz 25% -compose ChangeMask -composite  output.gif
NOTE I can't test this as the images you provide has a checkerboard background pattern rather than transparency!!!

Re: semi-flatten PNG images

Posted: 2011-01-11T14:46:18-07:00
by sas
anthony wrote:your final example results seems to indicate you are wanting to define the background of a GIF image that only has boolean transparency, in termes of a web page background.

That is you want to replace semi-transparency with an appropriate opaque color blend, while keeping fully-transparent transparent and fully-opaque opaque.
Yes, pretty much.
(Similar to what the Semi-Flatten filter in Gimp does).
anthony wrote:If so, say so, rather than what you think you want!
The reason I didn't is that I wasn't looking for a generic manual solution for "somehow make anti-aliased GIF look good for a given background color/pattern, no matter the details", but rather a very specific solution that ties in with an existing scripted work-flow, in which an anti-aliased foreground image of arbitrary shape has already been generated as PNG, as have one or more background images of the same dimensions which provide the (approximate) color values of certain parts of the web page background which the GIF image will be shown on.

I do admit however that the abstract example images I gave weren't really sensible use cases of this problem/solution (I didn't use real-life images as the ones I had at hand were really small), and my original description of the problem might not have been as clear as I intended. Sorry about that.
anthony wrote:You are better off using a 'average' or 'solid' color that roughly matches the whole background for the task.
No, not necessarily.

Imagine a GIF image that represents the edge or corner of an outlined/shadowed box on a web page. The background color/pattern inside the box might be different from the background color/pattern outside the box, so in the GIF image the pixels belonging to the "inside" of the box need to be semi-flattened against a different color than the pixels belonging to the "outside" of the box.

Anyways in the work-flow mentioned above, the information about which pixel should be semi-flattened against which color already exists, in the form of the given background image(s).
anthony wrote:In BOTH cases you can just overlay the semi-transparent image on your background pattern or average color, then find what pixels did not change, to generate a mask of the image.
One method is shown in Change Mask Composition.
http://www.imagemagick.org/Usage/compose/#changemask
Whcih will directly produce what you want.

Code: Select all

convert  imbackground.png \( +clone imsource.png -composite \) \
      -fuzz 25% -compose ChangeMask -composite  output.gif
When removing the -fuzz option, this produces something very similar to the result of the first two steps of my 3-step solution above:
Image + Image = Image

The third step (overlaying the source image on this masked background) would still have to be done as a separate command though, right?

Re: semi-flatten PNG images

Posted: 2011-01-11T14:51:55-07:00
by fmw42
You should be able to combine all steps as long as you use convert rather than composite to merge the images and use clones and parenthesis processing.

see

http://www.imagemagick.org/script/compose.php
http://www.imagemagick.org/Usage/basics/#parenthesis
http://www.imagemagick.org/Usage/layers/#convert

Re: semi-flatten PNG images

Posted: 2011-01-11T17:08:29-07:00
by anthony
Apologies. Add a +swap before the ChangeMask composition...
here is the example again but with the image given that have no checkerboard pattern,

Code: Select all

convert backgroundtv.png \( +clone sourceup.png -composite \) \
      +swap -fuzz 5% -compose ChangeMask -composite  output.gif
The colors retained are from the background, so the swap is needed to place the 'overlaid' image first (as background).

Parenthesis is used so as to remove the need to read the background image twice.
This is equivalent without parenthesis.

Code: Select all

convert backgroundtv.png sourceup.png -composite \
            backgroundtv.png -fuzz 5% -compose ChangeMask -composite  output.gif
The fuzz is recommended to threshold the most minor changes, especially when you have a large semi-transparent gradient produced by blur, such gradients can show changes a great distances from the main image boundary. Adjust as needed -fuzz 0 is equivalent to 'no fuzz'.

Re: semi-flatten PNG images

Posted: 2011-01-13T11:51:17-07:00
by sas
Thanks, anthony!

Your solution works great:
Image + Image --> Image

Also thanks for including the "without parenthesis" version, as that really helped me understand how the command works.

PS: Will this command work with every (moderately recent) ImageMagick version, or do I need to make sure to upgrade to a certain minimum version on all machines on which the command is supposed to be run?

Re: semi-flatten PNG images

Posted: 2011-01-13T12:05:15-07:00
by fmw42
From Anthony's page on compose methods (http://www.imagemagick.org/Usage/compose/), it says:

"The 'ChangeMask' composition method was added to IM v6.3.4 ..."

So that is likely the minimum version needed

Re: semi-flatten PNG images

Posted: 2011-01-13T15:51:41-07:00
by anthony
fmw42 wrote:"... added to IM v6.3.4 ..."
So that is likely the minimum version needed
Correct.

No need for any -matte or -alpha set settings as 'ChangeMask' will add alpha automatically to the result, and the first 'Over' composite will handle images with or without alpha correctly.

Re: semi-flatten PNG images

Posted: 2011-01-13T18:17:22-07:00
by sas
Hi,

the "Over + ChangeMask" solution still seems to have issues after all. (Well, they might not be issues for other people, but for my use-case, they're problematic.)

For example, given below is a real-life example of my use-case (well, real-life plus -sample 1000% plus black border).

The "Over + ChangeMask" method suggested by anthony produces:

Code: Select all

convert cbackground.png \( +clone csource.png -composite \) \
      +swap -fuzz 2% -compose ChangeMask -composite  csemiflat.png
Image + Image --> Image

Note how all semi-transparent pixels for have been flattened (even ones for which the background image did not provide a background color for semi-flattening), and how the black border was removed since it appeared in both the source and background image (even though this has nothing to do with semi-flattening).

Compare this with the most recent incarnation of my "alpha extract + Dst_In + Over" method (I managed to put it into a single command now):

Code: Select all

convert \( cbackground.png \( csource.png -alpha extract -threshold 5% -alpha copy \) \
       -compose Dst_In -composite \) csource.png \
       -compose Over -composite  csemiflat2.png
Image + Image --> Image

This is really how I would prefer the outcome to look.

The only downside is that it needs to read the source image twice. (Or is there something else wrong with doing it this way?)

Any thoughts?

Re: semi-flatten PNG images

Posted: 2011-01-13T20:00:05-07:00
by fmw42
convert \( cbackground.png \( csource.png -alpha extract -threshold 5% -alpha copy \) \
-compose Dst_In -composite \) csource.png \
-compose Over -composite csemiflat2.png

try changing the above to

convert cbackground.png csource.png \
\( -clone 1 -alpha extract -threshold 5% -alpha copy \) \
\( -clone 0 -clone 2 -compose Dst_In -composite \) \
-delete 0,2 +swap -compose Over -composite csemiflat2.png