computing RGBA to match an RGB color - colors

If I have an RGB color, with 100% opacity.
I want that same color (or close to it) with a transparent alpha channel. I will paint the transparent color over a white background.
How do I compute the RGBA color?
I guess what I am asking is the opposite of this question.

You mean you want the RGBA color with maximum transparency which, when drawn on top of a white background, gives the original RGB color?
Let R0, G0 and B0 be the components of the original color, each ranging from 0.0 to 1.0, and let R, G, B and A be the components of the new RGBA color (with A = 1 denoting 100% opacity). We know that the colors must satisfy:
R0 = A·R + (1 − A)
G0 = A·G + (1 − A)
B0 = A·B + (1 − A)
which, if we knew A, we could easily solve for R, G and B:
R = (R0 − 1 + A) / A = 1 − (1 − R0) / A
G = (G0 − 1 + A) / A = 1 − (1 − G0) / A
B = (B0 − 1 + A) / A = 1 − (1 − B0) / A
Since we require that R ≥ 0, G ≥ 0 and B ≥ 0, it follows that 1 − R0 ≥ A, 1 − G0 ≥ A and 1 − B0 ≥ A, and therefore the smallest possible value for A is:
A = max( 1 − R0, 1 − G0, 1 − B0 ) = 1 − min( R0, G0, B0 )
Thus, the color we want is:
A = 1 − min( R0, G0, B0 )
R = 1 − (1 − R0) / A
G = 1 − (1 − G0) / A
B = 1 − (1 − B0) / A
Ps. For a black background, the same formulas would be even simpler:
A = max( R0, G0, B0 )
R = R0 / A
G = G0 / A
B = B0 / A
Pps. Just to clarify, all the formulas above are for non-premultiplied RGBA colors. For premultiplied alpha, just multiply R, G and B as calculated above by A, giving:
R = A · ( 1 − (1 − R0) / A ) = R0 − (1 − A)
G = A · ( 1 − (1 − G0) / A ) = G0 − (1 − A)
B = A · ( 1 − (1 − B0) / A ) = B0 − (1 − A)
(or, for a black background, simply R = R0, G = G0 and B = B0.)

Related

How to properly convert hsl colors to rgb colors in lua?

I have the following code:
#!/usr/bin/env lua5.3
-- Code adapted from https://github.com/EmmanuelOga/columns/blob/master/utils/color.lua#L51
local function hslToRgb(h, s, l, a)
local r, g, b
h = (h / 255)
s = (s / 100)
l = (l / 100)
if s == 0 then
r, g, b = l, l, l -- achromatic
else
local function hue2rgb(p, q, t)
if t < 0 then t = t + 1 end
if t > 1 then t = t - 1 end
if t < 1/6 then return p + (q - p) * 6 * t end
if t < 1/2 then return q end
if t < 2/3 then return p + (q - p) * (2/3 - t) * 6 end
return p
end
local q
if l < 0.5 then q = l * (1 + s) else q = l + s - l * s end
local p = 2 * l - q
r = hue2rgb(p, q, h + 1/3)
g = hue2rgb(p, q, h)
b = hue2rgb(p, q, h - 1/3)
end
if not a then a = 1 end
return r * 255, g * 255, b * 255, a * 255
end
local h,s,l,a
h,s,l,a = hslToRgb(220, 16.4, 21.6)
print(h,s,l,a)
-- expected output: 46 52 64 255
-- actual output: 64.11312 46.04688 60.92496 255
But, as stated at the end, the color values it outputs are completely wrong. The decimals are not an issue (as in, it's not an issue that it outputs them; their values are still wrong).
A hue value it's calculated in degrees, so the max isn't 255, but 360:
function hslToRgb(h, s, l)
h = h / 360
s = s / 100
l = l / 100
local r, g, b;
if s == 0 then
r, g, b = l, l, l; -- achromatic
else
local function hue2rgb(p, q, t)
if t < 0 then t = t + 1 end
if t > 1 then t = t - 1 end
if t < 1 / 6 then return p + (q - p) * 6 * t end
if t < 1 / 2 then return q end
if t < 2 / 3 then return p + (q - p) * (2 / 3 - t) * 6 end
return p;
end
local q = l < 0.5 and l * (1 + s) or l + s - l * s;
local p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
end
if not a then a = 1 end
return r * 255, g * 255, b * 255, a * 255
end
You can see this code working here.
I have been working on a more elegant solution to the HSV to RGB problem for a little bit now and this is what I've come up with.
local ceil = math.ceil
local abs = math.abs
local function clamp(v, min, max)
if v < min then return min end
if v > max then return max end
return v
end
local function HSV(h, s, v)
local vert = ceil(h / 120)
local r = abs(((h / 60) - 2 * vert))
local r, g, b = clamp(r, 1 - s, 1), clamp(2 - r, 1 - s, 1), (1 - s * v)
if vert == 1 then return r, g, b end
if vert == 2 then return b, r, g end
if vert == 3 then return g, b, r end
end
-- HSV to RGB
min = math.min
max = math.max
abs = math.abs
local function HSV2RGB (h, s, v)
local k1 = v*(1-s)
local k2 = v - k1
local r = min (max (3*abs (((h )/180)%2-1)-1, 0), 1)
local g = min (max (3*abs (((h -120)/180)%2-1)-1, 0), 1)
local b = min (max (3*abs (((h +120)/180)%2-1)-1, 0), 1)
return k1 + k2 * r, k1 + k2 * g, k1 + k2 * b
end

How to numerically calculate value of complex function given derivative of this function in Haskell?

Given:
Haskell
Complex-valued function df/dz defined on complex plane U (let's say z is a Complex Double).
Point z1 from the U on which df/dz is defined.
Question:
How to get value of function f(z) for which df/dz is a derivative, in point z1?
I. e. how to restore value of original function given only it's derivative, assuming complex plane?
This question is somewhat related to my previous question about calculating integrals of complex functions, but they are about different things. Here I am interested not in calculating some scalar value, but in finding the origin function given it's derivative. It's essentially calculating the indefinite integral of this derivative.
(Runge–Kutta in Haskell)
You can use some numeric solver like Runge-Kutta
-- define 4th order Runge-Kutta map (RK4)
rk4 :: Floating a => (a -> a) -> a -> a -> a
rk4 f h x = x + (1/6) * (k1 + 2*k2 + 2*k3 + k4)
where k1 = h * f (x)
k2 = h * f (x + 0.5*k1)
k3 = h * f (x + 0.5*k2)
k4 = h * f (x + k3)
in that case function signature is Floating but you can use RealFloat instead (you can use runge-kutta in complex).
Complete example:
Prelude> import Data.Complex
Prelude Data.Complex> let rk4 f h x = x + (1/6) * (k1 + 2*k2 + 2*k3 + k4) where {k1 = h * f(x);k2 = h * f (x + 0.5*k1);k3 = h * f (x + 0.5*k2);k4 = h * f (x + k3)}
Prelude Data.Complex> let f z = 2 * z
Prelude Data.Complex> rk4 f (0.1 :+ 0.2) (0.3 :+ 1.2)
(-0.2334199999999999) :+ 1.4925599999999999
Prelude Data.Complex>
On the other hand, #leftaroundabout suggest extend that behavior to VectorSpace (great! of course! :D )

Interpolation of a triangle

I have a unit right triangle and a value at each of the 3 vertices.
I need to interpolate to find the value at a point inside the triangle.
Hours of searching have turned up nothing that actually tells me how to do this.
Here is my closest attempt, which is actually pretty close but not quite right -
result =
v1 * (1 - x) * (1 - y) +
v2 * x * (1 - y) +
v3 * x * y;
v1, v2, and v3 are the values at the 3 vertices of the triangle.
(x, y) is the point in the triangle that you are trying to find the value of.
Any kind of method would help me here. It doesn't necessarily need to be a unit/right triangle.
Updated info:
I have a grid of evenly spaced points and a value at each point.
I make a triangle out of the nearest 3 points on the grid.
Here is a picture to illustrate it -
So I have to interpolate between 5, 3, and 7 to find the value of x.
The point could also be inside the other triangle, meaning you would interpolate between 5, 7, and the value of the bottom left corner of the square.
In the code I showed, v1 = 5, v2 = 3, v3 = 7.
x is the fractional distance (range [0-1]) in the "x" direction, and y is the fractional distance in the "y" direction.
In the picture's example, x would probably be about 0.75 and y would be about 0.2
Here are my closest attempts -
Created using -
if (x > y) //if x > y then the point is in the upper right triangle
return
v1 * (1 - x) * (1 - y) +
v2 * x * (1 - y) +
v3 * x * y;
else //bottom left triangle
return
v1 * (1 - x) * (1 - y) +
v4 * (1 - x) * y +
v3 * x * y;
And another attempt -
Created using -
if (x > y)
return
(1 - x) * v1 + (x - y) * v2 + y * v3;
else
return
(1 - y) * v1 + (y - x) * v4 + x * v3;
They're both close to what I need but obviously not quite right.
You should use barycentric coordinates. There is a very thorough write-up here that also discusses alternative solutions and why barycentric coordinates are best: CodePlea - Interpolating in a Triangle
Basically, the weights will end up looking like this:
Actually the simplest and most robust solution is based on barycentric coordinates -
http://answers.unity3d.com/questions/383804/calculate-uv-coordinates-of-3d-point-on-plane-of-m.html
I asked this 3 years ago and have still been working on a way to do this. I do believe it is impossible to do it without artifacts unless using an equilateral triangle.
Here is a decent way to do it using barycentric coordinates and then adding a technique that gets rid of most of the artifacts.
v1, v2, v3 are the values at the three points of the triangle. x, y is the point you want to find a value for.
if (x > y)
{
b1 = -(x - 1);
b2 = (x - 1) - (y - 1);
b3 = 1 - b1 - b2;
}
else
{
b1 = -(y - 1);
b2 = -((x - 1) - (y - 1));
b3 = 1 - b1 - b2;
}
float
abs = x - y;
if (abs < 0) abs *= -1;
if (abs < 0.25f)
{
abs = 0.25f - abs;
abs *= abs;
b1 -= abs;
b3 -= abs;
}
b1 *= b1;
b2 *= b2;
b3 *= b3;
float fd = 1 / (b1 + b2 + b3);
b1 *= fd;
b2 *= fd;
b3 *= fd;
return
v1 * b1 +
v2 * b2 +
v3 * b3;
Ok, so we will do a linear interpolation, assuming that the gradient is constant with respect to x and to y. d/dx = v2 - v1 and d/dy = v3 - v2, and f(0,0) = v1. We have a simple two dimensional differential equation.
d{f(x,y)} = (v2 - v1)*dx
f(x,y) = (v2 - v1)*x + g(y)
d{f(x,y)} = g'(y) = (v3 - v2)*dy
g(y) = (v3 - v2)*y + C
f(x,y) = (v2 - v1)*x + (v3 - v2)*y + C
f(0,0) = v1 = (v2 - v1)*0 + (v3 - v2)*0 + C = C
f(x,y) = (v2 - v1)*x + (v3 - v2)*y + v1
or in terms of v1 v2 and v3
f(x,y) = (1 - x)*v1 + (x - y)*v2 + y*v3
If you want to do it in a square for four vertices, as above with v4 in the bottom left at x=0 y=1, here are the conditions: d/dx = (v2 - v1) (1 - y) + (v3 - v4) y, d/dy = (v3 - v2) x + (v4 - v1) (1 - x), f(0,0) = v1
d/dx = (v2 - v1) (1 - y) + (v3 - v4) y
f(x,y) = (v2 - v1) (1 - y) x + (v3 - v4) y x + g(y)
d/dy = (v3 - v2) x + (v4 - v1) (1 - x) = -(v2 - v1) x + (v3 - v4) x + g'(y)
v3 - v2 + (v4 - v1) / x + v4 - v1 = -v2 + v1 + v3 - v4 + g'(y) / x
(v4 - v1) / x + 2*(v4 - v1) = g'(y) / x
g'(y) = (v4 - v1) + 2 x (v4 - v1)
g(y) = (v4 - v1) (1 + 2 x) y + C
f(x,y) = (v2 - v1) (1 - y) x + (v3 - v4) y x + (v4 - v1) (1 + 2 x) y + C
f(0,0) = (v2 - v1) (1 - 0) 0 + (v3 - v4) 0 0 + (v4 - v1) (1 + 2 0) 0 + C = v1
f(x,y) = (v2 - v1) (1 - y) x + (v3 - v4) y x + (v4 - v1) (1 + 2 x) y + v1
Here is some pseudocode for nearest-neighbor:
if( dist( p, p1 ) <= dist( p, p2 ) && dist( p, p1 ) <= dist( p, p3 ) )
return val( p1 )
if( dist( p, p2 ) <= dist( p, p3 ) && dist( p, p2 ) <= dist( p, p1 ) )
return val( p2 )
if( dist( p, p3 ) <= dist( p, p1 ) && dist( p, p3 ) <= dist( p, p2 ) )
return val( p3 )
I think this also generates a voronoi diagram

type error in Haskell

I am getting the following error:
exercise-2-2.hs:15:49:
Couldn't match expected type `Double' with actual type `Int'
In the fourth argument of `regularPolygonHelper', namely `theta'
In the expression: regularPolygonHelper n s 0 theta r
In an equation for `regularPolygon':
regularPolygon n s
= regularPolygonHelper n s 0 theta r
where
r = s / 2.0 * (sin (pi / n))
theta = (2.0 * pi) / n
in the following code:
data Shape = Rectangle Side Side
| Ellipse Radius Radius
| RTTriangle Side Side
| Polygon [Vertex]
deriving Show
type Radius = Float
type Side = Float
type Vertex = (Float, Float)
square s = Rectangle s s
circle r = Ellipse r r
regularPolygon :: Int -> Side -> Shape
regularPolygon n s = regularPolygonHelper n s 0 theta r
where r = s / 2.0 * (sin (pi / n))
theta = (2.0 * pi) / n
regularPolygonHelper :: Int -> Side -> Int -> Double -> Double -> Shape
regularPolygonHelper 0 s i theta r = Polygon []
regularPolygonHelper n s i theta r =
(r * cos (i * theta), r * sin (i * theta)) :
(regularPolygonHelper (n - 1) s (i + 1) theta r)
Why is this? Isn't (2.0 * pi) / n a double?
Haskell has no automatic conversion between different numeric types. You have to do this by hand. In your case, (2.0 * pi) / fromIntegral n would do the trick. (You have to add this at all the other places where you want to have a cast too) The reason for this is, that implicit conversion would make type inference much harder, IMHO it is better to have type inference than automatic conversion.
better not mix the types so much
here is a version that compiles so far:
data Shape = Rectangle Side Side
| Ellipse Radius Radius
| RTTriangle Side Side
| Polygon [Vertex]
deriving Show
type Radius = Double
type Side = Double
type Vertex = (Double, Double)
square s = Rectangle s s
circle r = Ellipse r r
regularPolygon :: Int -> Side -> Shape
regularPolygon n s = regularPolygonHelper n s 0 theta r
where r = s / 2.0 * (sin (pi / fromIntegral n))
theta = (2.0 * pi) / fromIntegral n
regularPolygonHelper :: Int -> Side -> Int -> Double -> Double -> Shape
regularPolygonHelper 0 s i theta r = Polygon []
regularPolygonHelper n s i theta r =
let Polygon rPoly = regularPolygonHelper (n - 1) s (i + 1) theta r in
Polygon ((r * cos (fromIntegral i * theta), r * sin (fromIntegral i * theta)) : rPoly)

Equation for Sliding Collision of LineSegments

I need an equation to find point F.
Point A, B, and D are known. Point F is unknown. Point F is on line AB. Line AB is perpendicular to line DF. What is the equation for F?
I'm assuming you want something computationally fast, since you mention 'collision', and this is Stack Overflow. First, a diagram:
We want to calculate the components of AF, which we'll label f = qi + pj. AFD forms a triangle, so we can get the length of f from AD, which we'll label d. Let's mark lengths in italics versus vectors in bold:
f = d cos(θ).
But trig is computationally expensive. So let's use the fact that the vector dot product between b (AB) and d is:
b · d = b d cos(θ)
The angle is the same because AF and AB are on the same line. Substituting in for dcos(θ):
b · d = b f
f = (b · d) / b
Now we have f, but we want its components p and q. Calling the angle to the horizontal φ:
q = f cos(φ)
p = f sin(φ)
But again we're avoiding trig. We know that f is along b, so f = kb, and in fact using the unit vector in the direction of b:
f = f (b/b)
Substituting our expression for f:
f = [(b · d) / b ] (b/b)
= [(b/ b) · d ] (b/b)
= [b · d] b / (b2)
Defining a factor k which is common to both components:
k = (bx dx + by dy) /b2
By keeping the b2 separate, we can avoid a square root operation to get the unit vector along b
Our components, then:
q = k bx
p = k by
Finally, add back in the offset of point A.
Fx = Ax + q
Fy = Ay + p
So, the pseudo code:
var vbx = Bx - Ax; //vector b x component
var vby = By - Ay; //vector b y component
var dot = vbx*(Dx-Ax) + vby*(Dy-Ay); // dot product of b and d
var k = dot/(vbx*vbx + vby*vby); // inverse of square of vector b length
var fx = Ax + k*vbx
var fy = Ay + k*vby
No square root calls, no trig, 8 additions/subtractions, 6 multiplications, 1 division. The only instabilities I can see are: divide by zero when A and B are at the same position, possible overflow calculating dot if AB is large and AD is large.
First, find the slope of line AB with the point-slope formula using A and B's coordinates:
Point Slope Formula
You can then find b to finished the equation for line AB:
y = mx + b where m is the slope you already found and b is the y-intercept that you just found.
The slope of line DF would be the negative reciprocal of the slope of line AB. Plug this into the equation:
y = mx + b where m is the negative reciprocal of the slope of line AB and b comes later.
Now, solve for b using the x and y values of point D, and plug that into the equation.
You should now have an equation for line DF and another equation for line AB. Now solve for the intercept of the two equations by setting them equal to one another and solving for x first and then plugging in x and finding y.
Here's an example.
A = (1, 2). B = (4, 8). D = (2, 5).
Line AB:
(y - y1) = m*(x - x1)
(1 - 4) = m*(2 - 8)
-3 = m*(-6)
0.5 = m
y = (0.5)*x + b
2 = (0.5)*1 + b
2 = (0.5) + b
1.5 = b
y = 0.5*x + 1.5
Line DF:
m = -(1/mAB)
m = -(1/0.5)
m = -2
y = -2*x + b
5 = -2*2 + b
5 = -4 + b
9 = b
y = -2*x + 9
Intersection of AB and DF (i.e. coordinates of point F)
Line DF: y = -2*x + 9
Line AB: y = 0.5*x + 1.5
-2*x + 9 = 0.5*x + 1.5
9 = 2.5*x + 1.5
7.5 = 2.5*x
x = 3
y = -2*x + 9
y = -2*3 + 9
y = -6 + 9
y = 3
F = (3, 3)
You haven't specified exactly where point F is along line DF, so there's no single answer. If you're just trying to find SOME point along a line perpendicular to line AB, from point D, then
F.x = D.x + (B.y - A.y)
F.y = D.y + (B.x - A.x)
will work.

Resources