I have to determine the epipolar line using this model:
I read some books and the Wikipedia-article. But I cannot figure out, what this means:
l2 = e2 x x2
Where l2 ist the epipolar line in the right/2nd image (red line) and x2 is the image point in the right image of the object x.
My problem: As I assume, the point e2 and x2 are in the right image plane, which means, that the cross product of them (in the formula l2) is perpendicular to the image plane and hence cannot be in the image plane, as the red line is.
What am I understanding wrong?
You can write the equation of a straight line in 2D,
ax + by + c = 0
as a dot product
l . x = 0
where l = [a b c]' is the line and x = [x y 1]' is a point on the line.
So, l and x are orthogonal.
In the second image, both e2 and x2 should lie on the epipolar line l2, meaning
l2 . e2 = 0, l2 . x2 = 0
So, l2 is orthogonal to both e2 and x2. You can find a vector that is orthogonal to both e2 and x2 by taking their cross product. Therefore, we can say l2 = e2 x x2.
You can see that l2 . e2, and l2 . x2 are indeed 0, using triple product properties.
l2 . e2 = e2 . l2 = e2 . (e2 x x2) = x2 . (e2 x e2) = 0
You should not look at the points as 2D points in the image that are crossed, that's the source of your confusion.
The cross is defined using 3D vectors such that
|e2x| |x2x|
l2 = |e2y| X |x2y|
| 1 | | 1 |
and after you get the resulting l2 (3D vector), you should normalize it so that
l2x^2+l2y^2=1
Related
Here's a problem that's been wrecking my brain for a while.
Given:
I have two coordinate spaces:
the global space G, and
a local space A, and
I know the position and rotation of A relative to G.
Question:
How can I programmatically calculate the position and rotation of G relative to A?
On graph paper, I can calculate this by hand:
if A relative to G is (4, 1) 90deg, then G relative to A is (-1, -4) -90deg
if A relative to G is (5, 0) 0deg, then G relative to A is (-5, 0) 0deg
... but I'm having trouble transferring this calculation to software.
In matrix form,
y = R x + t
where R is the rotation matrix and t the translation of the origin.
The reverse way,
x = R' (y - t) = R' y + (- R' t)
where R' is the inverse of R, and also its transpose.
When doing a ray trace with rayTraceP, I can find the point where a ray intersects with a diagram.
> rayTraceP (p2 (0, 0)) (r2 (1, 0)) ((p2 (1,-1) ~~ p2 (1,1))
Just (p2 (1.0, 0.0))
I want to use this to find not only the "collision point", but also the collision time and the normal vector to the surface at that point.
-- A Collision has a time, a contact point, and a normal vector.
-- The normal vector is perpendicular to the surface at the contact
-- point.
data Collision v n = Collision n (Point v n) (v n)
deriving (Show)
Given a start point for the ray and a velocity vector along the ray, I can find the contact point end using rayTraceP:
end <- rayTraceP start vel dia
And I can find the collision time using the distance between start and end:
time = distance start end / norm vel
But I'm stuck on finding the normal vector. I'm working within this function:
rayTraceC :: (Metric v, OrderedField n)
=> Point v n -> v n -> QDiagram B v n Any -> Maybe (Collision v n)
-- Takes a starting position for the ray, a velocity vector for the
-- ray, and a diagram to trace the ray to. If the ray intersects with
-- the diagram, it returns a Collision containing:
-- * The amount of time it takes for a point along the ray going at
-- the given velocity to intersect with the diagram.
-- * The point at which it intersects with the diagram.
-- * The normal vector to the surface at that point (which will be
-- perpendicular to the surface there).
-- If the ray does not intersect with the diagram, it returns Nothing.
rayTraceC start vel dia =
do
end <- rayTraceP start vel dia
let time = distance start end / norm vel
-- This is where I'm getting stuck.
-- How do I find the normal vector?
let normalV = ???
return (Collision time end normalV)
Some examples of what I want it to do:
> -- colliding straight on:
> rayTraceC (p2 (0, 0)) (r2 (1, 0)) (p2 (1,-1) ~~ p2 (1,1))
Just (Collision 1 (p2 (1, 0)) (r2 (-1, 0)))
> -- colliding from a diagonal:
> rayTraceC (p2 (0, 0)) (r2 (1, 1)) (p2 (1,0) ~~ p2 (1,2))
Just (Collision 1 (p2 (1, 1)) (r2 (-1, 0))
> -- colliding onto a diagonal:
> rayTraceC (p2 (0, 0)) (r2 (1, 0)) (p2 (0,-1) ~~ p2 (2,1))
Just (Collision 1 (p2 (1, 0)) (r2 (-√2/2, √2/2)))
> -- no collision
> rayTraceC (p2 (0, 0)) (r2 (1, 0)) (p2 (1,1) ~~ p2 (1,2))
Nothing
It is correct on everything in these examples except for the normal vector.
I have looked in the documentation for both Diagrams.Trace and Diagrams.Core.Trace, but maybe I'm looking in the wrong places.
There is no way to do this in general; it depends on what exactly you hit. There is a module Diagrams.Tangent for computing tangents of trails, but to compute the tangent at a given point you have to know its parameter with respect to the trail; and one thing we are missing at the moment is a way to convert from a given point to the parameter of the closest point on a given segment/trail/path (it's been on the to-do list for a while).
Dreaming even bigger, perhaps traces themselves ought to return something more informative---not just parameters telling you how far along the ray the hit are, but also information about what you hit (from which one could more easily do things like compute a normal vector).
What kinds of things are you computing traces of? There might be a way to take advantage of the particular details of your use case to get the normals you want in a not-too-terrible way.
Brent Yorgey's answer points out the Diagrams.Tangent module, and in particular normalAtParam, which works on Parameteric functions, including trails, but not all Diagrams.
Fortunately, many 2D diagram functions, like circle, square, rect, ~~, etc. can actually return any TrailLike type, including Trail V2 n. So a function with the type
rayTraceTrailC :: forall n . (RealFloat n, Epsilon n)
=>
Point V2 n
-> V2 n
-> Located (Trail V2 n)
-> Maybe (Collision V2 n)
Would actually work on the values returned by circle, square, rect, ~~, etc. if it could be defined:
> rayTraceTrailC
(p2 (0, 0))
(r2 (1, 0))
(circle 1 # moveTo (p2 (2,0)))
Just (Collision 1 (p2 (1, 0)) (r2 (-1, 0)))
And this function can be defined by breaking the trail up into a list of fixed segments which are either linear or bezier curves, using the fixTrail function. That reduces the problem to the simpler rayTraceFixedSegmentC.
rayTraceTrailC start vel trail =
combine (mapMaybe (rayTraceFixedSegmentC start vel) (fixTrail trail))
where
combine [] = Nothing
combine cs = Just (minimumBy (\(Collision a _ _) (Collision b _ _) -> compare a b) cs)
The rayTraceFixedSegmentC can use rayTraceP to calculate the contact point, but we can't find the normal vector right away because we don't know what the parameter is at that contact point. So punt further and add fixedSegmentNormalV helper function to the wish list:
rayTraceFixedSegmentC :: forall n . (RealFloat n, Epsilon n)
=>
Point V2 n
-> V2 n
-> FixedSegment V2 n
-> Maybe (Collision V2 n)
rayTraceFixedSegmentC start vel seg =
do
end <- rayTraceP start vel (unfixTrail [seg])
let time = distance start end / norm vel
let normalV = normalize (project (fixedSegmentNormalV seg end) (negated vel))
return (Collision time end normalV)
This fixedSegmentNormalV function just has to return a normal vector for a single segment going through a single point, without worrying about the vel direction. It can destruct the FixedSegment type, and if it's linear, that's easy:
fixedSegmentNormalV :: forall n . (OrderedField n)
=>
FixedSegment V2 n -> Point V2 n -> V2 n
fixedSegmentNormalV seg pt =
case seg of
FLinear a b -> perp (b .-. a)
FCubic a b c d ->
???
In the FCubic case, to calculate the parameter where the curve goes through pt, I'm not sure what to do, but if you don't mind approximations here we can just take a bunch of points along it and find the one closest to pt. After that we can call normalAtParam as Brent Yorgey suggested.
fixedSegmentNormalV seg pt =
case seg of
FLinear a b -> perp (b .-. a)
FCubic a b c d ->
-- APPROXIMATION: find the closest parameter value t
let ts = map ((/100) . fromIntegral) [0..100]
dist t = distance (seg `atParam` t) pt
t = minimumBy (\a b -> compare (dist a) (dist b)) ts
-- once we have that parameter value we can call a built-in function
in normalAtParam seg t
With this, the rayTraceTrailC function is working with this approximation. However, it doesn't work for Diagrams, only Located Trails.
It can work on the values returned by functions like circle and rect, but not on combined diagrams. So you have to keep those building blocks of diagrams separate, as trails, for as long as you need this collision ray tracing.
Using the normal vectors to reflect the rays (the outgoing ray has an equal angle from the normal vector) looks like this:
I am trying to translate a VDM model to Isabelle, but for some reason, what
I do, do not work
The following sample is a VDM function of my model
Dot_Move_invariant: Dot * Dot -> bool
Dot_Move_invariant(d1, d2) ==
d1 < d2 and
let coordinate_1 = Dot_Coord(d1) in
let coordinate_2 = Dot_Coord(d2) in
moving_coordinates_invariant(coordinate_1, coordinate_2);
And the following sample represents my attempt to translate it
definition
Dot_Move_invariant:: "Dot⇒Dot⇒𝔹"
where "Dot_Move_invariant d1 d2 ≡ d1 < d2 ∧ let x = (SOME y. y ∈ Dot_Coord d1) in x ∧ let y = (SOME x. x ∈ Dot_Coord d2 ) "
The error I get is: Inner syntax error⌂
Failed to parse prop
It might be following:
"Dot_Move_invariant d1 d2 ≡ d1 < d2 ∧ let x = (SOME y. y ∈ Dot_Coord d1) in x ∧ let y = (SOME x. x ∈ Dot_Coord d2 ) in y"
data Point = Point Float Float deriving (Show)
data Line = Line Point Point deriving (Show)
onLine :: Line -> Point -> Bool
onLine (Line (Point x1 y1) (Point x2 y2)) (Point x y) = True
Is there a way not to use so many brackets ?
I recommend a tool called hlint for identifying places where you can simplify your code.
In your code /as written/, you're not using the values x1, y1, x2, y2, x or y, so you could just write:
onLine _ _ = True
However, I assume that's just a stub, and in reality you will do something with the variables. In general, if you really need to reference all those variables, then you need to write it the way you have done. However, maybe you're using a helper function that only needs the entire line value. Then you could write something like:
onLine l p = blah blah blah
-- use slope l and yIntercept l to figure out if p is on the line
slope :: Line -> Float
slope (Line (Point x1 y1) (Point x2 y2)) = (y2 - y1) / (x2 - x1)
yIntercept :: Line -> Float
yIntercept (Line (Point x1 y1) (Point x2 y2)) = blah blah blah
Alternatively, you can just use accessor functions to extract the x and y co-ordinates from points and lines, but in this case it will probably make your code messier.
Also, in Haskell I believe it's generally more efficient to use Double rather than Float.
You can sometimes avoid brackets with record notation, sometimes with $, sometimes with infix functions, and sometimes they're OK if not excessive.
Let's use record notation for points, which get heavy access for the coordinates, but we'll leave Line alone.
data Point = Point {x::Double,y::Double} deriving (Show)
data Line = Line Point Point deriving (Show)
This defines x :: Point -> Double and y :: Point -> Double.
There's no such thing as equality for floating points, but I'll go for roughly right:
accuracy = 0.000000000001
is :: Double -> Double -> Bool
is x y = abs (x - y) < accuracy
I can use this as x point1 `is` x point2 neatly avoiding the bracketed is (x point1) (x point2)
When your data structure is not so heavily nested with pattern matching, a few brackets are easy to read:
gradient :: Line -> Double
gradient (Line one two) = (y two - y one) / (x two - x one)
But we can go one level deeper without using excessive brackets because of the functions x and y.
asFunction :: Line -> (Double -> Double) -- ( ) for clarity, not necessity
asFunction l#(Line point _) = \xx -> gradient l * (xx - x point) + y point
Notice I've used l# to introduce an alias for (Line point _) to save typing on the right.
Now we can use the infix function trick to get rid of a few more brackets:
onLine :: Line -> Point -> Bool
onLine l p = l `asFunction` x p `is` y p
On the right hand side, you can use $ to get rid of brackets, but you can't use it on the left in pattern matching because it's a function f $ x = f x. For example
this (that (the other thing (something other)))
= this $ that $ the other thing $ something other
= this . that . the other thing $ something other
You can take the line and point apart within the function by defining accessors, but there is no way to do the pattern matching without the parentheses.
Another way of getting rid of the parentheses is to do the pattern matching in a number of case expressions:
onLine l p = case l of
Line p1 p2 -> case p1 of
Point x1 y1 -> case p2 of
Point x2 y2 -> case p of
Point x y -> True -- you can use x1,y1,x2,y2,x and y here
This is close to what the compiler 'translates' the patternmatches to, but of course this is not much of an improvement!
However, there are a number of ways of writing this expression that also translate to the same cascaded pattern matching; here's one:
onLine l p = let
Line (Point x1 y1) (Point x2 y2) = l
Point x y = p
in True
and here's another:
onLine l p = True where
Line (Point x1 y1) (Point x2 y2) = l
Point x y = p
The last one is pretty nice and readable, in my opinion, but the other suggestions are much better, since they'll lead to a better structured program!
(There's some stuff about irrefutable patterns that I'm glossing over, and this only works for single-constructor datatypes)
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.