MJW Posted June 15, 2016 Share Posted June 15, 2016 I recently wrote the Color Clearer plugin, which is intended to increase the transparency of each pixel while producing the same color when alpha-blended against a background of a specified color. Pixels that match the selected color can be made completely transparent, while pixels that are very unlike the selected color must be mostly opaque. I had two goals with the plugin: first I wanted it to work when the original pixels are partially transparent; second, I wanted the adjusted pixels to match the original pixels exactly when alpha blended to a background of the selected color. The first turned out to be very easy: all that needed to be done is to compute the alphas and colors to match the original colors alpha-blended with the selected color. The second is a bit trickier, since it must take into account the integer math used by PDN to blend layers. Because I think the same techniques might be useful for other plugins, I thought I'd explain them. I wrote a brief comment called Integer Division and Inequalities. I later found the same information is contained (in a slightly different form) in the rather thorough Wikipedia article on Floor and ceiling functions. Both explain how to find the largest or smallest integers that satisfy inequalities involving integer division. ---------- Definitions: C_{F}: One of the original RGB foreground color components. The foreground color is the color of the source pixel. C_{F}': One of the adjusted foreground RGB color components. A_{F}: The original foreground alpha. A_{F}': The adjusted foreground alpha. C_{B}: One of the background RGB color components. The background color is the color selected to be made transparent. C_{C}: One of the composited (alpha-blended) foreground and background RGB color components. The composite color is the color that would result if the actve layer were placed over an opaque layer filled with the background color. We want to find new values for the foreground color and foreground alpha which will minimize alpha while still producing the same composite color when alpha blended to the background color. Each of the RGB components will have its own minimum alpha. For instance, if the foreground and background red have the same value, alpha can be 0, while if the foreground green is 0 and the background green is 255, only an alpha near 255 will preserve the alpha-blended green value. Since we need an alpha that preserves all the components, alpha is the maximum of the three minimum component-alphas. For PDN alpha blending, C_{C} = Truncate{ [255 * C_{B} + A_{F} * (C_{F} - C_{B})] / 255 } The Truncate function represents the fact that the computation is done using integer division. The result could be rounded by adding 127 or 128 to the numerator, prior to the integer division, but that's not what PDN does. For each of the RGB components, we need to find new values C_{F}' and A_{F}' which minimize A_{F}'. ----- The Adjusted Alpha ----- We need: C_{C} = Truncate{ [255 * C_{B} + A_{F}' * (C_{F}' - C_{B})] / 255 } This requires, 255 * C_{C} ≤ 255 * C_{B} + A_{F}' * (C_{F}' - C_{B}) < 255 * (C_{C} + 1) 255 * (C_{C} - C_{B}) ≤ A_{F}' * (C_{F}' - C_{B}) < 255 * (C_{C} - C_{B} + 1) If C_{C} = C_{B}, then the minimum A_{F}' that satisfies the inequality is A_{F}' = 0. If C_{C} > C_{B}, then the left side of the inequality is greater than zero. To minimize A_{F}', (C_{F}' - C_{B}) must be made as large as possible; so C_{F}' = 255. Thus, 255 * (C_{C} - C_{B}) ≤ + A_{F}' * (255 - C_{B}) < 255 * (C_{C} - C_{B}) + 255 255 * (C_{C} - C_{B}) / (255 - C_{B}) ≤ A_{F}' < [255 * (C_{C} - C_{B}) + 255] / (255 - C_{B}) The minimum value of A_{F}' that satisfies the inequality is, A_{F}' = Truncate{ [255 * (C_{C} - C_{B}) - 1] / (255 - C_{B}) } + 1 If C_{C} < C_{B}, then the left side of the inequality is less than zero, and the right side is less than or equal to 0. Multiplying by -1 gives: 255 * (C_{B} - C_{C}) ≥ + A_{F}' * (C_{B } - C_{F}') > 255 * (C_{B} - C_{C} - 1) 255 * (C_{B} - C_{C} - 1) < A_{F}' * (C_{B } - C_{F}') ≤ 255 * (C_{B} - C_{C}) To minimize A_{F}', (C_{B } - C_{F}') must be made as large as possible; so C_{F}' = 0. Thus, 255 * (C_{B} - C_{C} - 1) < A_{F}' * C_{B } ≤ 255 * (C_{B} - C_{C}) 255 * (C_{B} - C_{C} - 1) / C_{B } < A_{F}' ≤ 255 * (C_{B} - C_{C}) / C_{B } The minimum value of A_{F}' that satisfies the inequality is, A_{F}' = Truncate[ 255 * (C_{B} - C_{C} - 1) / C_{B } ] + 1 Once the minimum adjusted alpha is computed for each of the RBG components, the alpha for the color is calculated as the maximum of the three values. ----- The Adjusted Color ----- The adjusted foreground color is computed for the adjusted alpha. In many cases, particularly for small alphas, there's a range of colors that will produce the desired composite color. If alpha is zero, any color will do. If alpha is some small non-zero value, the foreground color still makes little contribution to the composite color, so a wide range of colors can be used. The question becomes how to choose which color. I think a good choice is to select each adjusted RGB component to be the value that's nearest to the original foreground color's component. If alpha is zero, any color can be used, including the original color (which is obviously closest). Assuming alpha is non-zero, then as previously shown: 255 * (C_{C} - C_{B}) ≤ A_{F}' * (C_{F}' - C_{B}) < 255 * (C_{C} - C_{B} + 1) 255 * (C_{C} - C_{B}) ≤ A_{F}' * [(C_{F}' - C_{F}) + (C_{F} - C_{B})] < 255 * (C_{C} - C_{B} + 1) 255 * (C_{C} - C_{B}) - A_{F}' * (C_{F} - C_{B}) ≤ A_{F}' * (C_{F}' - C_{F}) < 255 * (C_{C} - C_{B} + 1) - A_{F}' * (C_{F} - C_{B}) or, 255 * (C_{C} - C_{B}) - A_{F}' * (C_{F} - C_{B}) ≤ A_{F}' * (C_{F}' - C_{F}) < 255 * (C_{C} - C_{B}) - A_{F}' * (C_{F} - C_{B}) + 255 Let T = 255 * (C_{C} - C_{B}) - A_{F}' * (C_{F} - C_{B}) T ≤ A_{F}' * (C_{F}' - C_{F}) < T + 255 T ≤ A_{F}' * (C_{F}' - C_{F}) ≤ T + 254 If T ≤ -255, then A_{F}' * (C_{F}' - C_{F}) is bounded between negative values, so it is negative. To minimize the magnitude, we must choose the largest value. This requires: A_{F}' * (C_{F}' - C_{F}) ≤ T + 254 C_{F}' - C_{F} ≤ (T + 254) / A_{F}' -(T + 254) / A_{F}' ≤ C_{F} - C_{F}' C_{F} - C_{F}' = Truncate{ [-(T + 254) - 1] / A_{F}' } + 1 C_{F} - C_{F}' = Truncate[ -(T + 255) / A_{F}' ] + 1 C_{F}' = C_{F} - 1 - Truncate[ -(T + 255) / A_{F}' ] Since for integer division, (-a)/b = -(a/b), C_{F}' = C_{F} - 1 + Truncate[ (T + 255) / A_{F}' ] If -254 ≤ T ≤ 0, then A_{F}' * (C_{F}' - C_{F}) is bounded between a negative and a non-negative, so the inequality is satisfied if C_{F}' = C_{F}. If T > 0, then A_{F}' * (C_{F}' - C_{F}) is positive, so to minimize the magnitude, we must choose the smallest value. This requires: T ≤ A_{F}' * (C_{F}' - C_{F}) T / A_{F}' ≤ C_{F}' - C_{F} C_{F}' - C_{F} = Truncate[ (T - 1) / A_{F}' ] + 1 C_{F}' = C_{F} + 1 + Truncate[ (T - 1) / A_{F}' ] ----- Summarizing ----- For each of the three RGB color components, compute the minimum alpha (note the A_{F}' in the alpha computation represents the minimum alpha for the particular color component. In the color computation, it represents the over-all alpha.) C_{C} = C_{B}: A_{F}' = 0 C_{C} > C_{B}: A_{F}' = Truncate{ [255 * (C_{C} - C_{B}) - 1] / (255 - C_{B}) } + 1 C_{C} < C_{B}: A_{F}' = Truncate[ 255 * (C_{B} - C_{C} - 1) / C_{B } ] + 1 Once the three alphas are found (call them A_{R}, A_{G}, and A_{B}) then the adjusted alpha is the maximum. That is: A_{F}' = Max(A_{R}, A_{G}, A_{B}) Now compute the three adjusted RGB color components using: Let T = 255 * (C_{C} - C_{B}) - A_{F}' * (C_{F} - C_{B}) T ≤ -255: C_{F}' = C_{F} - 1 - Truncate[ -(T + 255) / A_{F}' ] (or C_{F}' = C_{F} - 1 + Truncate[ (T - 255) / A_{F}' ]) -254 ≤ T ≤ 0: C_{F}' = C_{F} T > 0: C_{F}' = C_{F} + 1 + Truncate[ (T - 1) / A_{F}' ] (Truncate indicates integer division is used.) One thing worth noting is that while I chose to make the adjusted foreground color as near to the original foreground color as possible, nothing in the derivation depended on that particular choice. Therefore, if instead I wanted to make the adjusted color as near to the composite color (or any other color) as possible, I could just subtitute that color's components in place of C_{F} 3 Quote Link to comment Share on other sites More sharing options...

MJW Posted June 15, 2016 Author Share Posted June 15, 2016 In case the forest was lost among the trees, I'll explain the basic steps involved. 1) Rewrite the integer computation as inequalities. This converts the problem into a continuous form, which is much easier to deal with. 2) Isolate the term you're interested in as far as possible. The term should normally be be one you wish to minimize or maximize. For example, in the color section, I use (C_{F}' - C_{F}), not C_{F}', even though C_{F}' is what I ultimately want to determine. More or less, solve for the term, but completely solving for it may involve division or multiplication by terms whose sign can change the direction of the inequalities. Which brings us to the next step. 3) If necessary (as it likely will be), divide the problem into several cases, which depend on the sign or magnitude of some of the terms. This is the step that requires the most ingenuity. If, as mentioned in the last step, a term can have different signs which can alter the direction of the inequalities, consider what values it can have. Each case should allow the variable of interest to be completely isolated. 4) For each case, isolate the variable of interest, then use the rules for integer division and inequalities to find the best solution. (There may be some situations where there's only one solution, or where any valid solution will do.) I forgot rule 0), which is: Know what integer computation is done. I couldn't find anything showing exactly how PDN alpha blends pixels to an opaque background -- whether it truncates or rounds and so forth -- so I had to experiment a little to find out. Quote Link to comment Share on other sites More sharing options...

## Recommended Posts

## Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.