Jump to content

LWChris

Members
  • Posts

    71
  • Joined

  • Last visited

  • Days Won

    2

Community Answers

  1. LWChris's post in Accidentally flattened an image when saving it and can't undo. How can I reverse-engineer RGBA values from glasses lenses based on the color difference between the area that's under glasses and the area that isn't? was marked as the answer   
    I have been thinking about creating a plugin called "Color Unmixer" to answer exactly these questions of reverse engineering. Sadly, I've not yet gotten around to think of a good custom UI. But luckily, having had those plans means I have a good understanding of how it should work, and I can do for you by hand what the plugin should've done if it existed already. So... here we go!
     
    The Maths, the Basics, and You
    Finding the semi-transparent overlay color boils down to a system of 4 linear equations that you can solve if you have two pixels with distinct known background colors "b1" and "b2" that were overlain by the same unknown semi-transparent foreground color "f". That is, as long as both colors were overlain by the same foreground color at the same opacity, you can mathematically calculate that foreground color and its opacity.

    Your image has several of these pairs, so it should be possible to work out the color.
     
    But first of all, one thing I noticed right away: the outlines are not affected by the glass, i.e. the oval outline of the eyes stays black, no matter if it should be "under" the blue tint or highlight or not under the glasses at all. So my guess is those outlines were on a separate layer ABOVE the glasses. But that's probably something you remembered anyway.

    For the other bits, there's 4 pairs for both the highlight and the tint on the glasses. I've marked them red, yellow, lime and blue here (the 3rd lime marker is in the top right). Any "pair" consists of one of the base colors (outside of the glasses) and then either the corresponding part on the tinted or highlighted part of the glasses, respectively.
     

    Having 4 pairs per unknown overlay color is cool, because we can use two to determine the color and its opacity, and the other two to check if our calculations "add up" (literally) as a sanity check.

    But first, here's the actual formula what the visible mixed color "m" becomes when a semi-transparent foreground color "f" is overlayed over the background color "b":
     
    mc = bc + (fc - bc) * falpha / 255
     
    This formula is applied per channel "c". For example, for the red channel, the formula would be:
     
    mred = bred + (fred - bred) * falpha / 255
     
    The keen-eyed can probably also see why we need 2 pixel pairs: since we want to know the semi-transparent foreground color, we have to re-arrange that formula to solve for the f's (more on that later). But we have to make a choice: we can either solve for the red channel value fred, or for the alpha channel value falpha. Any m/b pair will produce three equations, one for each channel, and we can use those to solve for fred, fgreen and fblue respectively. But we then need a fourth equation from a different pair to also give us some formula we can instead re-arrange to solve for falpha.
     
    With all that being said, there's two snags we need to pay attention to:
     
    Snag 1: If the values for a color channel between background color and resulting mixed color match, that means the foreground color used the same color value (or maybe a really close one with very low opacity) for that channel, but we cannot use that equation any longer to solve for falpha. This makes sense; if you overlay "some amount of redness" with "any transparency of same amount of redness", the resulting mix will still have that same redness value to it, no matter the actual transparency. [Side note: this is also visible from the formula. If mred = bred, that means the calculation must've been "mred = bred + [something that equals 0]". This can either mean that falpha was 0, which is not really interesting, because I think we agree the overlay was probably not 100% transparent, or "fred - bred = 0", which means "fred = bred", and that's what we stated when we said that background and foreground use the same red value, or "(fred - bred) * falpha / 255" is so small it gets rounded to 0.]
     
    Snag 2: This one is not as obvious from the formula, but becomes clear once you start crunching numbers. RGB colors are discrete values, that is: integers. The formula works perfect for floating values, where mixed red values like 15.7311248 would be a possibility. Alas, in the actual image the red value is probably either 15 or more likely 16. That's something we need to keep in mind, and it is the reason why many online maths solvers might probably say that the system of equations cannot be solved, because with all that rounding, the results between channels or different pairs etc. just not quite "line up" when calculating forwards and backwards again. But we'll deal with that later.
     
    The Highlights
    But now: to the actual solving! Let's start with the highlight color first, so the pairs are going to be the background colors from outside the glasses plus the respective color from inside the glasses where these have a highlight.

    For the blue pair, both m and b are #FFFFFF. As per snag 1, we cannot use that to determine the highlight falpha, but at least it's probably safe to assume it was "some transparency of clean #FFFFFF white". We'll use the yellow pair to find that alpha value:

    The background color for the yellow markers (iris) is b = #56C3F6, the mixed result on the glass is m = #89D5F9. Let's use the red channel, since it exhibits the most intense value change from bred = 56hex to mred = 89hex, which equals bred = 86 to mred = 137 in decimal numbers. Now let's re-arrange our formula to solve for falpha:
     
    mc = bc + (fc - bc) * falpha / 255
    mc - bc = (fc - bc) * falpha / 255
    (mc - bc) / (fc - bc) = falpha / 255
    (mc - bc) / (fc - bc) * 255 = falpha
     
    There we have it, we can use this formula to get falpha:
    falpha = (mc - bc) / (fc - bc) * 255
     
    Inserting the values for mred = 137, bred = 86 and fred = 255 (which, remember, we deduced from the "clean white"), we get 76.95266272189..., so basically 77. Hence we predict the highlight color to be "#FFFFFF with a transparency of 77".
     
    Let's test our theory by applying the original formula "mc = bc + (fc - bc) * falpha / 255" to the lime pair.
     
    Here are the known values for the lime pair (where "m" is the one located in the highlight, not the tint):
    b = #FBD574 = rgb(251, 213, 116)
    m = #FCE29E = rgb(252, 226, 158)
    f = rgba(255, 255, 255, 77)
     
    Now we plug the values for b and f into the formula, and see if that correctly predicts m:
    mred = 251 + (255 - 251) * 77 / 255 = 252.21
    mgreen = 213 + (255 - 213) * 77 / 255 = 225.68
    mblue = 116 + (255 - 116) * 77 / 255 = 157.97
     
    And sure enough, if we round those values to whole numbers, we get m = rgb(252, 226, 158).

    Now for the red pair:
    b = #FCEDDA = rgb(252, 237, 218)
    m = #FDF2E5 = rgb(253, 242, 229)
     
    mred = 252 + (255 - 252) * 77 / 255 = 252.91
    mgreen = 237 + (255 - 237) * 77 / 255 = 242.44
    mblue = 218 + (255 - 218) * 77 / 255 = 229.17
     
    Again, rounding those values to whole numbers, we correctly get m = rgb(253, 242, 229). Hooray, the highlight color is indeed "#FFFFFF with a transparency of 77", just like we predicted earlier. Yay for Maths!
     
    The Blue Tint
    Now let's do the same thing for the blue tint. This time, it's going to require a little bit more effort, since the tint color isn't obvious already. But worry not, it's the same maths like for falpha, but we're re-arranging the original equation to solve for fc instead of falpha, and then use that formula for red, green, and blue:
     
    mc = bc + (fc - bc) * falpha / 255
    mc - bc = (fc - bc) * falpha / 255
    (mc - bc) * 255 = (fc - bc) * falpha
    (mc - bc) * 255 / falpha = fc - bc
    (mc - bc) * 255 / falpha + bc = fc
     
    We can use this formula to get fc:
    fc = (mc - bc) * 255 / falpha + bc
     
    Let's use it on the yellow pair. Here are the known values:
    b = #56C3F6 = rgb(86, 195, 246)
    m = #3C93F9 = rgb(60, 147, 249)
     
    Plugging in those two colors for all three channels, we get three equations which are only dependent on falpha:
    fred = (60 - 86) * 255 / falpha + 86
    fgreen = (147 - 195) * 255 / falpha + 195
    fblue = (249 - 246) * 255 / falpha + 246
     
    From the blue pair, we get these known values:
    b = #FFFFFF = rgb(255, 255, 255)
    m = #B2BDFF = rgb(178, 189, 255)
     
    This gives these equations:
    fred = (178 - 255) * 255 / falpha + 255
    fgreen = (189 - 255) * 255 / falpha + 255
    fblue = (255 - 255) * 255 / falpha + 255
     
    Since we know (or rather: require) all equations come from the same f (i.e.: with the same fred, and the same falpha), we can essentially solve for falpha by equating yellow's fred and the blue's fred, and then re-arrange the resulting equation to solve for falpha:
     
    fred = (60 - 86) * 255 / falpha + 86
    fred = (178 - 255) * 255 / falpha + 255

    (60 - 86) * 255 / falpha + 86 = (178 - 255) * 255 / falpha + 255
    -26 * 255 / falpha + 86 = -77 * 255 / falpha + 255
    -26 * 255 / falpha = -77 * 255 / falpha + 169
    51 * 255 / falpha = 169
    51 * 255 = 169 * falpha
    51 * 255 / 169 = falpha
    falpha = 76.95266272189349
     
    Hey! That value looks awfully familiar, doesn't it? Yep, we landed on the same result as with the highlight color earlier. In hindsight, it's probably not too surprising that we got the same transparency value of "77" for both parts of the glass. The glasses were probably created on a separate layer using opaque colors and a uniform layer transparency of 77. But now we know for sure (and I could include the steps to calculate falpha for a non-trivial case).
     
    Anyway, back to the original "yellow equations". Now that we have confirmed that falpha is indeed 77, we can complete those equations and hopefully get our foreground color. So here goes nothing:
     
    fred = (60 - 86) * 255 / 77 + 86 = -0.10
    fgreen = (147 - 195) * 255 / 77 + 195 = 36.04
    fblue = (249 - 246) * 255 / 77 + 246 = 255.94
     
    Here we have a classic example of snag 2. The "known" values were rounded, so reversing the operation has lead to slight deviations from the original colors. We get negative values such as -0.10, or values like 255.94, which would get rounded to 256 and thereby exceed the possible maximum of 255. But for now, let's reasonably assume f to be rgba(0, 36, 255, 77) and see where that assumption takes us. We can check it using the other two pairs - and that's why having such extra pairs for verification is so nice.
     
    Let's test red first. Known colors:
    b = #FCEDDA = rgb(252, 237, 218)
    m = #B0B0E5 = rgb(176, 176, 229)
     
    Assuming f = rgba(0, 36, 255, 77), the formula suggests:
    mred = 252 + (0 - 252) * 77 / 255 = 175.91
    mgreen = 237 + (36 - 237) * 77 / 255 = 176.31
    mblue = 218 + (255 - 218) * 77 / 255 = 229.17
     
    Great news! These values check out for our observed m.
     
    Now, for our final test, we check the lime pair. Known colors:
    b = #FBD574 = rgb(251, 213, 116)
    m = #B0A09E = rgb(176, 160, 158)
     
    And one last time, assuming f = rgba(0, 36, 255, 77), the formula suggests:
    mred = 251 + (0 - 251) * 77 / 255 = 175.21
    mgreen = 213 + (36 - 213) * 77 / 255 = 159.55
    mblue = 116 + (255 - 116) * 77 / 255 = 157.97
     
    Spot on! Nice.
     
    The Answer
    And there we have it. From using nothing but the final result and Maths, we can deduce:
    The glasses were made using a highlight color of #FFFFFF and a tint color of #0024FF, on a layer with "77" transparency.
     
    Cheers, Chris
  2. LWChris's post in Is there a hotkey to increase/decrease font size on the text tool? was marked as the answer   
    None that I know of, but you can place your cursor over the dropdown textbox (without clicking it) and then use the mouse wheel to change the size. That is less cumbersome than typing numbers, and allows you visualize between the given options. If you're interested in visualizing ALL different options (e. g. the ones between 48 and 72) then you're out of luck AFAIK, but maybe I'm not aware of something.
×
×
  • Create New...