[Image-SIG] Image.blend() loses brightness
patrick.surry at gmail.com
Thu Sep 22 20:10:26 CEST 2011
Image.blend() tends to lose half a unit of brightness (on a scale of 0-255)
wherever the two input images differ.
I noticed this while blending a series of greyscale book page images (black
background, white text) in a loop, blending the n-th page in to the
composite of the previous ones with alpha=1/n – i.e. first page is taken at
full value, then second blended at alpha=1/2, third blended to that result
with alpha = 1/3 etc. But this inevitably results in an all-black image.
But it should result in a final image where all pages have equal weight.
Turns out that there's a roundoff problem in Image.blend(im1,im2,alpha)
which calculates (UINT8)(im1 + alpha*(im2-im1)) at each pixel, but since
UINT8 acts like floor() the result of the calculation is always rounded
down. The right fix is to add half a unit before the floor, i.e. instead
calculate (uint8) (im1 + alpha*(im2-im1)+0.5). This has no effect on points
where the images match (the 0.5 just gets discarded again), but removes the
downward bias when they don’t.
You can work around this using a combination of ImageChops.add() and
subtract(), remembering that subtract truncates negative values at 0:
def blend_unbiased (im1,im2,alpha):
# because subtract() truncates at zero, we have to use two steps to
include both the positive and negative differences,
# essentially calculating:
# floor(im + max(0,(im2-im1)*alpha + 0.5) -
This ends up with the expected final image after a sequence of merge steps.
(This same issue likely applies to other image composition operations)
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the Image-SIG