Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Superimpose function does not superimpose #33

Open
Fresheyeball opened this issue Nov 29, 2019 · 3 comments
Open

Superimpose function does not superimpose #33

Fresheyeball opened this issue Nov 29, 2019 · 3 comments

Comments

@Fresheyeball
Copy link

The superimpose function in Graphics.Image.Processing does not superimpose. It replaces the pixels in the target image with the overlay image. While useful, this is not the expected behavior. Especially, with superimposed images with alpha channels.

@Fresheyeball
Copy link
Author

Fresheyeball commented Nov 30, 2019

superimpose'
  :: Array arr RGBA e
  => AlphaSpace RGBA e
  => Fractional e => Ord e
  => (Int, Int)     -- ^ @(i, j)@ starting index from within a source image.
  -> Image arr RGBA e -- ^ Image to be positioned above the source image.
  -> Image arr RGBA e -- ^ Source image.
  -> Image arr RGBA e
superimpose' (!i0, !j0) !imgA !imgB = traverse2 imgB imgA const newPx where
  !(m, n) = dims imgA
  newPx getPxB getPxA (i, j) =
    let !(i', j') = (i - i0, j - j0)
        new = getPxA (i', j')
        old = getPxB (i, j)
    in if i' >= 0 && j' >= 0 && i' < m && j' < n then overlayAlpha old new else old


overlayAlpha :: Elevator e => Ord e => Fractional e => Pixel RGBA e -> Pixel RGBA e -> Pixel RGBA e
overlayAlpha base overlay = setPxC (liftPx2 f base overlay) AlphaRGBA 1
  where f b o = b + (getAlpha overlay * (o - b))

This works, but makes me wish that AlphaSpace came with a setAlpha so this could be more abstract.

@lehins
Copy link
Owner

lehins commented Nov 30, 2019

Thanks for submitting this. I'll make sure to get it fixed in a new version of hip, once I do get to the rewrite I have planned.
For now you could probably simulate setAlpha with setAlpha a = addAlpha a . dropAlpha

@Javran
Copy link

Javran commented May 23, 2021

Thanks @Fresheyeball for this workaround - it worked fine but it generates a greenish color when there are section where pixels of both image are transparent. So I checked Wikipedia, following https://en.wikipedia.org/wiki/Alpha_compositing I have an improved version of overlayAlpha that works as expected:

overlayAlpha
  :: (Elevator e, Ord e, Fractional e)
  => Pixel RGBA e
  -> Pixel RGBA e
  -> Pixel RGBA e
overlayAlpha bPxa oPxa =
  addAlpha rAlp (liftPx2 f (dropAlpha bPxa) (dropAlpha oPxa))
  where
    bAlp = getAlpha bPxa
    oAlp = getAlpha oPxa
    rAlp = oAlp + bAlp * (1 - oAlp)
    f b o =
      if rAlp == 0
        then 0
        else (o * oAlp + b * bAlp * (1 - oAlp)) / rAlp

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants