Calculating opacity value mathematically - I need a source - css

I'm looking for a formula to calculate the RGB of a new color, based on the opacity. Of course, there's already an answer for this (i.e. Calculating opacity value mathematically), especially this answer:
The formula for combining C1 = (R1,G1,B1) and C2 = (R2,G2,B2) into a new color C3, where C2 is overlayed on top of C1 with opacity p is usually ( (1-p)R1 + p*R2, (1-p)*G1 + p*G2, (1-p)*B1 + p*B2 ).
This is great, it works, I get the correct value. However, I need a reliable source for this formula, which I cannot find. Sure, that answer has an link to Wikipedia, which again lacks the source.
If there's any other formula for calculating the color based on the opacity value mathematically and there's a reliable source for such a formula (e.g. book or scientific paper), feel free to share it.
Thanks!

Thanks to anyone who helped. I actually found the answer in this link: http://jcgt.org/published/0004/02/03/paper.pdf
It's a (semi)scientific paper, and the formula is as follows:
Aα * Ac + (1−Aα)*Bα*Bc / Aα + (1−Aα)*Bα
I've tested it on this scenarios:
rgb_div = (80, 85, 250); opacity = 0.2
rgb_bg = (100, 205, 30); opacity = 1
new color = (96, 181, 74)

Related

Achieving "same" colour of different transparencies

Consider 2 or more boxes that look to be the "same" colour, but with different transparencies:
In this example, the left div is rgba(200,200,200,0.8), and the right rgba(150,150,150,0.4). The second row has a red bar behind them to show that their transparencies are different.
I know the left and right divs do not look the same (the left div looks slightly darker). My question is how can I make them so:
Given a colour (r1, g1, b1, a1), how can I work out another "colour" (r2, g2, b2, a2) such that a1 != a2 and the two colours look the "same".
Here's the fiddle I used to generate the above picture: jsfiddle
At the moment, I simply pick some r2, g2, and b2, then fiddle around with a2 until the two colours look similar enough. But there should be a relation between colours and their transparencies that we can use to work this out precisely and for any given colour.
Have a look at this link : https://viget.com/inspire/equating-color-and-transparency.
I hope it will be what you're looking for.
Edit:
Here is an example of application of the formula given in the link above, based on the case you describe in your post, so you can better understand how to use it.
Here is the formula given in the link. I just changed the name of the variables to make them more explicit ("overlay" became "initialValue", "target" became "finalValue"):
finalValue = opacity x initialValue + (1 - opacity) x background
From this, I can deduce the following formula :
opacity = (background - finalValue) / (background - initialValue)
So, back to your example case, the first formula applied to your left div gives a finalValue of :
finalValue = 0.8 x 200 + 0.2 x 255 = 211
So, the objective for your right div is to calculate the opacity necessary to match this final value, from the initial value of 150 :
opacity = (255 - 211) / (255 - 150) = 0.419
If you try rgba(150, 150, 150, 0.419) on your right div, you will see that the final color is the same.

Saving images read with glReadPixels where alpha value is not one

When saving an image using glReadPixels, the colors are distorted where their alpha value is less than one.
The surface is managed by QtQuick. With glGetInteger I found out there are 8 bits for each channel, including alpha.
I can get a better result, but not perfect, using something like this:
for x := 0; x < m.Bounds().Dx(); x++ {
for y := 0; y < m.Bounds().Dy(); y++ {
c := m.RGBAAt(x, y)
w := float64(c.A) / 255
c.R = uint8(float64(c.R)*w + 255*(1-w) + 0.5)
c.G = uint8(float64(c.G)*w + 255*(1-w) + 0.5)
c.B = uint8(float64(c.B)*w + 255*(1-w) + 0.5)
c.A = 255
m.SetRGBA(x, y, c)
}
}
I tried to clear the alpha component in OpenGL itself using:
s.gl.ClearColor(0, 0, 0, 1)
s.gl.ColorMask(false, false, false, true)
s.gl.Clear(GL.COLOR_BUFFER_BIT)
Now the result is similar to my manual composing, moreover displayed and the captured image are the same but are still different from (and darker than) what was displayed before.
I'm interested in how OpenGL/Qt uses the alpha channel when displaying the color buffer. Maybe QtQuick composes it with a backing layer?
I solved the problem by never changing alpha during drawing. So instead of gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA), I now use gl.BlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA) and modified the other parameters to get it looking as before.
As Andon M. Coleman pointed out in his comments, this is the same as using pre-multiplied alpha blending. This way, the alpha value of color buffer remains always one and the problem is worked around.
glBlendFuncSeparate, which specify pixel arithmetic for RGB and alpha components separately, would have been useful to get the same result.

making a sine wave steeper?

I've written a a little function that gives me out a value based on a sine wave when I put in a float between 0 and 1. I'm using it to lerp things around in a game.
public static class Utilities
{
public static float SineMe(float prop)
{
float output = (prop*180f)-90f;
output = Mathf.Sin(output*Mathf.Deg2Rad);
output = (output+1f)/2f;
return output;
}
}
It works fine.. But I was wondering is there a mathematical way of altering the sine wave so I can make it 'steeper' or 'shallower' in the middle?
In the diagram below the blue curve is a sine wave, I'm wondering if I can make it more like the green line.
What you're showing already isn't really sine - the range of sine is between -1 and +1. You're applying the linear function f(x) = (x+1)/2 to change that range. So place another function between the sine and that transform.
To change the shape, you need a non-linear function. So, here's a cubic equation you might try...
g(x) = Ax^3 + Bx^2 + Cx + D
D = 0
C = p
B = 3 - 3C
A = 1 - (B + C)
The parameter p should be given a value between 0.0 and 9.0. If it's 1.0, g(x) is the identity function (the output is the unmodified input). With values between 0.0 and 1.0, it will tend to "fatten" your sine wave (push it away from 0.0 and towards 1.0 or -1.0) which is what you seem to require.
I once "designed" this function as a way to get "fractal waveforms". Using values of p between 1.0 and 9.0 (and particularly between around 3.0 and 6.0) iterative application of this formula is chaotic. I stole the idea from the population fluctuation modelling chaotic function by R. M. May, but that's a quadratic - I wanted something symmetric, so I needed a cubic function. Not really relevant here, and a pretty aweful idea as it happens. Although you certainly get chaotic waveforms, what that really means is huge problems with aliassing - change the sample rate and you get a very different sound. Still, without the iteration, maybe this will give you what you need.
If you iterate enough times with p between 0.0 and 1.0, you end up with a square wave with slightly rounded corners.
Most likely you can just choose a value of p between 0.0 and 1.0, apply that function once, then apply your function to change the range and you'll get what you want.
By the way, there's already a comment suggesting a cheat sheet of "easing functions". "Easing" is a term from animation, and computer animation software often uses Bezier curves for that purpose - the same Bezier curves that vector graphics software often uses. Bezier curves come in quadratic and cubic variants, with cubic being the more common. So what this is doing probably isn't that different. However, cubic Bezier easing gives you more control - you can control the "ease-in" independently of the "ease-out", where my function only provides one parameter.
You can use the y(x) = 1-(1-x)^n function when x = [0..1], as a transform function.
You will just have to replace x by the absolute value of your sinus and report the sign of sinus to the result. In that way you can tweak the sinus slope by increasing n. So what you want is this:
float sinus = Mathf.Sin(output*Mathf.Deg2Rad);
int sign = (sinus >= 0 ? 1 : -1);
int n = 4; // slope parameter
float waveform = sign * ( 1-Mathf.Pow(1-Mathf.Abs(sinus), n) );
You can root the sine function to make it steeper (only working for positive values). The higher the root, the steeper the sine.
Graph of a steeper sine wave function
I discovered this nifty trick for a steeper sine wave (0..1).
f(x) = cos(sin(x)^3)^10
If you need (-1..1):
2 * (f(x) - 0.5)
I think I found the solution.
(0.5+sin(x*π-π/2)/2)^((2*(1-x))^k)
in the interval x = [0.0, 1.0]
with k that control the steepness.
k=0.0 for the unmodified sinus (purple)
k=1.0 (green)
k=2.0 (blue)
https://www.desmos.com/calculator/wdtfsassev
I was looking for a similar function, not for the whole sine but just half the period.
I bumped into the Logistic function:
f(x) = L / (1 + e^(-k(x-x0)))
where
e = the natural logarithm base (also known as Euler's number),
x0 = the x-value of the sigmoid's midpoint,
L = the curve's maximum value, and
k = the steepness of the curve.
See https://en.wikipedia.org/wiki/Logistic_function
Works for me
what about
sign(sin(x))*sqrt(abs(sin(x))
https://www.desmos.com/calculator/5nn34xqkfr

Conversion between RGB and RYB color spaces

I am currently trying to convert colours between RGB (red, green, blue) colour space and RYB (red, yellow, blue) colour space and back again.
Based on the details in the following paper, I am able to convert from RYB to RGB using trilinear interpolation - where the parametric weightings (s, t, u) are the RYB colors, and the vertices of the cube are 3d points in RGB space.
Paint Inspired Color Mixing and Compositing for Visualisation - Gossett and Chen - Section 2.1 - Realization Details
My difficulties are in reversing the conversion process.
A second paper references the use of this technique and also indicates that the reverse conversion was achieved using Newton's Method. But provides no further details. This would probably indicate root finding in solving the trilinear interpolation equations.
On the Transfer of Painting Style to Photographic Images through Attention to Colour Contrast - Xiaoyan Zhang; Constable, M.; Ying He;
Before I expand on this question with the equations, has anybody seen, or solved this in a language such as Java/C/C++/C#?
My current approach is to take the forward equations of the trilinear interpolation (RYB to RGB), expand and rearrange to provide 3 simultaneous equations for 3 unknowns (the parametric weightings: s, t, and u) then work out how to find the roots using the Newton-Raphson method. Am I going about this in the right way?
I managed to solve it in the end.
Take the equations for a trilinear interpolation:
wikipedia
Edit: Wikipedia revision at the time
Substitute the first equations into the last, the expand and collect the coefficients for:
Xd, Yd, Zd, XdYd, XdZd, YdZd, ZdYdZd and the constant.
Then find the partial differentiation of the equation in each of the 3 dimensions each in respect to Xd, Yd and Zd. Use these new equations to populate the (3x3) Jacobian matrix and then use Newton's method to solve in software.
Newton-Raphson Method
I found this JavaScript implementation of RYB->RGB conversion based on cubic splines. Here is my Lua port (all values lie in the interval 0-1):
local ryb2rgb = function( R, Y, B )
local R, Y, B = R*R*(3-R-R), Y*Y*(3-Y-Y), B*B*(3-B-B)
return 1.0 + B * ( R * (0.337 + Y * -0.137) + (-0.837 + Y * -0.163) ),
1.0 + B * ( -0.627 + Y * 0.287) + R * (-1.0 + Y * (0.5 + B * -0.693) - B * (-0.627) ),
1.0 + B * (-0.4 + Y * 0.6) - Y + R * ( -1.0 + B * (0.9 + Y * -1.1) + Y )
end
Here is a category on UIColor that does the same thing, returning elements between RGB, RYB, and CMYK. Further, you can mix any number of colors in the respective color space (they mix differently, of course, depending).
https://github.com/ddelruss/UIColor-Mixing

Can we find out the difference between 2 RGb colors to find out a 3rd color?

2 colors are mixed together. If i have the RGB for the resultant color and RGB for one of the colors mixed, then somehow i could calculate the 2nd color?
I will try to explain visually what i am trying to say. Here is a flickr link
http://www.flickr.com/photos/48150615#N08/4407414157
I know that the circle in the middle has an opacity of 20%
Is there any way to know the color value of the circle so that i can deduct that to get the same color value as the background color.
if i understood the task correctly...
let's do some school math
c is color of initial image, t is color of transparent color, a (for alpha) is transparency, c' is result color.
c' = (1 - a) * t + a * c
you want to find c.
c = (c' - (1 - a) * t) / a
you need to know a, t and c'
Firstly it depends how you're going to mix them. That is, you could average the RGB components (this means blue (0,0,255) + yellow (255,255,0) == grey (128,128,128)), or you could work on Hues, Saturation and Value, which often gives a much more "as expected" result.
Anyway, in either case, it's some simple maths:
if the way to get the average is C3 = (C1 + C2) / 2
then the way to find C2 is C2 = (C3 * 2) - C1
CIELAB color space is specially designed for calculating differences between colors, but it might be a overkill in you case. Probably HSV is easy solution for you.
Just subtract each component. The components are often stored in hexadecimal format, in which case you will need to convert the numbers to decimal or do hex math.

Resources