Search code examples
colorshexcalculation

Calculate hex color with transparency based on other colors


I have the following image:

image example

I want to find the hex color and transparency of the red circle based on the below information :

  • purple background circle is #afb0cc
  • human figure is #ffffff

By using eye-dropper I was able to figure out some additional information:

  • Red Circle over purple background circle is #d75866
  • Red Circle over human figure is #ff7f7f

Solution

  • Since your picture has part of the red circle overlapping nothing else, and actually being transparent in that area, we can cheat and just pick there.

    It's the RGBA tuple (255, 0, 0, 128).


    How to calculate that, if we didn't have it? System of equations.

    Let's say we have two layers, or pixels, or colors, and their composite:

    • A on top, with alpha channel alpha
    • B under it, background, fully opaque (no alpha channel)
    • C being the composite of A on top of B, also fully opaque

    I'll make the alpha channel be floating point and range from 0.0 to 1.0. Makes the arithmetic nicer.

    Now, compositing happens like this:

    C = (A * alpha) + (B * (1 - alpha))
    # or equivalently
    C = B + (A - B) * alpha
    
    # rearranged for alpha
    alpha = (C - B) / (A - B)
    
    # rearranged for A
    A = B + (C - B) / alpha
    

    You have a few values for C and B, and you want A and alpha. Each color is three values, but let's simplify and consider that "one" value (a vector). That means the equation contains two unknowns (A and alpha), so you need two equations to solve for them.

    Your "measurements" are those:

    # red circle over white:
    C1 = (255, 127, 127)
    B1 = (255, 255, 255)
    
    # red circle over black:
    C2 = (128,   0,   0)
    B2 = (  0,   0,   0)
    
    # red circle over blue/purple, which we don't need
    C3 = (215,  88, 102)
    B3 = (175, 176, 204)
    

    Now plug those in to get two equations.

    C1 = B1 + (A - B1) * alpha
    C2 = B2 + (A - B2) * alpha
    

    Some algebra (moving things around) (I checked it):

    alpha = (B1 - B2 - C1 + C2) / (B1 - B2)
    A = (B1*C2 - B2*C1) / (B1 - B2 - C1 + C2)
    

    And that gets you this value for your red transparent circle:

    # alpha
    array([0.50196, 0.50196, 0.50196])
    array([128., 128., 128.]) # / 255
    
    # A
    array([255.,   0.,   0.])
    

    Which is exactly what we expected.


    If you used other values for B and C, say from the blue/purple area (B3, C3), you would get close, but not exactly the right answer. The values for C are integers, which were necessarily rounded from the exact composition equation's result.

    The exact values for C3, given B and the fortunately known A and alpha, would be:

    C3 = array([215.15686,  87.6549 , 101.6    ])
    

    Yes, my alpha isn't a single value but a vector. That's not right, but it's good enough for those simple equations. You could set up more complex ones that carry each color component (RGB) individually, so that all color planes use the same alpha.

    If you wanted to use more samples of C and B, this would become a least squares problem.

    You could also work with intervals for your measurements.