Transform plane to XY plane - math

I am trying to find transformation matrix, which will allow me to transfer given plane to XY plane. Based on this answer, I have prepared small Python function which does these calculations. However I don't understand why final plane is not in XY.
Could you help me and tell me what I am doing wrong?
my input plane (3d view):
390.17 * x + -571.67 * y + -4008.29 * z + 2833797.03 = 0
input = [390.17, -571.67, -4008.29, 2833797.03]
z = 0.0973*x - 0.1427*y + 706.9838
It seems to me that to transfer it to XY plane, rotation about X and Y axes should be done (first). The last element is translation along Z axis.
Based on this answer I have prepared my function transform_plane(). (code below).
As a result function returns new plane: (3d view)
2.19436115e+00 1.61044899e+03 4.06772244e+03 -4.20201320e+04 = 0
out = [2.19436115e+00, 1.61044899e+03, 4.06772244e+03, -4.20201320e+04]
Z = -0.0005*x-0.3959*y+10.3301
It looks like, the plane was only rotated about Y, and to align it with XY, it should also be rotated about X axis.
Does it mean that I forgot about something? or matrix presented in linked answer is not sufficient to get transformation for two different axes?
EDIT:
Thanks to answer below I was able to find missing square root, however still I don't understand why my translation is not sufficient.
Instead of Z = 0, my result is Z = 10. It seems to me that maybe -d/c should also be divided by square root.
My implementation:
import numpy as np
def calc_cos_phi(a, b, c):
return c / sqrt(a*a + b*b + c*c)
def calc_sin_phi(a, b, c):
return sqrt((a*a + b*b) / (a*a + b*b + c*c))
def calc_u1(a, b, c):
return b / (a*a + b*b)
def calc_u2(a, b, c):
return -a / sqrt(a*a + b*b)
def get_transform_matrix(plane):
a, b, c, d = plane
cos_phi = calc_cos_phi(a, b, c)
sin_phi = calc_sin_phi(a, b, c)
u1 = calc_u1(a, b, c)
u2 = calc_u2(a, b, c)
out = np.array([
[cos_phi + u1 * u1 * (1 - cos_phi) , u1 * u2 * (1 - cos_phi) , u2 * sin_phi , 0 ],
[u1 * u2 * (1 - cos_phi) , cos_phi + u2 * u2 * (1 - cos_phi) , -u1 * sin_phi , 0 ],
[-u2 * sin_phi , u1 * sin_phi , cos_phi , -d / c ],
[0 , 0 , 0 , 1 ]
])
return out
def transform_plane(plane):
t = get_transform_matrix(plane)
t_inv = np.linalg.inv(t)
new_plane = np.dot(plane, t_inv)
print("new plane:")
print(new_plane)
return new_plane
Test:
plane = [390.17, -571.67, -4008.29, 2833797.03]
plane_xy = transform_plane(plane)

You have missed sqrt here:
def calc_u1(a, b, c):
return b / (a*a + b*b)
should be
def calc_u1(a, b, c):
return b / sqrt(a*a + b*b)
Replacement gives [-1.13686838e-13 0.00000000e+00 4.06760715e+03 -4.19362793e+04] - x coefficient is almost zero, plane is parallel to OXY (like z=-1.05)

Related

Perpendicular on a line segment from a given point

I want to calculate a point on a given line that is perpendicular from a given point.
I have a line segment AB and have a point C outside line segment. I want to calculate a point D on AB such that CD is perpendicular to AB.
I have to find point D.
It quite similar to this, but I want to consider to Z coordinate also as it does not show up correctly in 3D space.
Proof:
Point D is on a line CD perpendicular to AB, and of course D belongs to AB.
Write down the Dot product of the two vectors CD.AB = 0, and express the fact D belongs to AB as D=A+t(B-A).
We end up with 3 equations:
Dx=Ax+t(Bx-Ax)
Dy=Ay+t(By-Ay)
(Dx-Cx)(Bx-Ax)+(Dy-Cy)(By-Ay)=0
Subtitute the first two equations in the third one gives:
(Ax+t(Bx-Ax)-Cx)(Bx-Ax)+(Ay+t(By-Ay)-Cy)(By-Ay)=0
Distributing to solve for t gives:
(Ax-Cx)(Bx-Ax)+t(Bx-Ax)(Bx-Ax)+(Ay-Cy)(By-Ay)+t(By-Ay)(By-Ay)=0
which gives:
t= -[(Ax-Cx)(Bx-Ax)+(Ay-Cy)(By-Ay)]/[(Bx-Ax)^2+(By-Ay)^2]
getting rid of the negative signs:
t=[(Cx-Ax)(Bx-Ax)+(Cy-Ay)(By-Ay)]/[(Bx-Ax)^2+(By-Ay)^2]
Once you have t, you can figure out the coordinates for D from the first two equations.
Dx=Ax+t(Bx-Ax)
Dy=Ay+t(By-Ay)
function getSpPoint(A,B,C){
var x1=A.x, y1=A.y, x2=B.x, y2=B.y, x3=C.x, y3=C.y;
var px = x2-x1, py = y2-y1, dAB = px*px + py*py;
var u = ((x3 - x1) * px + (y3 - y1) * py) / dAB;
var x = x1 + u * px, y = y1 + u * py;
return {x:x, y:y}; //this is D
}
There is a simple closed form solution for this (requiring no loops or approximations) using the vector dot product.
Imagine your points as vectors where point A is at the origin (0,0) and all other points are referenced from it (you can easily transform your points to this reference frame by subtracting point A from every point).
In this reference frame point D is simply the vector projection of point C on the vector B which is expressed as:
// Per wikipedia this is more efficient than the standard (A . Bhat) * Bhat
Vector projection = Vector.DotProduct(A, B) / Vector.DotProduct(B, B) * B
The result vector can be transformed back to the original coordinate system by adding point A to it.
A point on line AB can be parametrized by:
M(x)=A+x*(B-A), for x real.
You want D=M(x) such that DC and AB are orthogonal:
dot(B-A,C-M(x))=0.
That is: dot(B-A,C-A-x*(B-A))=0, or dot(B-A,C-A)=x*dot(B-A,B-A), giving:
x=dot(B-A,C-A)/dot(B-A,B-A) which is defined unless A=B.
What you are trying to do is called vector projection
Here i have converted answered code from "cuixiping" to matlab code.
function Pr=getSpPoint(Line,Point)
% getSpPoint(): find Perpendicular on a line segment from a given point
x1=Line(1,1);
y1=Line(1,2);
x2=Line(2,1);
y2=Line(2,1);
x3=Point(1,1);
y3=Point(1,2);
px = x2-x1;
py = y2-y1;
dAB = px*px + py*py;
u = ((x3 - x1) * px + (y3 - y1) * py) / dAB;
x = x1 + u * px;
y = y1 + u * py;
Pr=[x,y];
end
I didn't see this answer offered, but Ron Warholic had a great suggestion with the Vector Projection. ACD is merely a right triangle.
Create the vector AC i.e (Cx - Ax, Cy - Ay)
Create the Vector AB i.e (Bx - Ax, By - Ay)
Dot product of AC and AB is equal to the cosine of the angle between the vectors. i.e cos(theta) = ACx*ABx + ACy*ABy.
Length of a vector is sqrt(x*x + y*y)
Length of AD = cos(theta)*length(AC)
Normalize AB i.e (ABx/length(AB), ABy/length(AB))
D = A + NAB*length(AD)
For anyone who might need this in C# I'll save you some time:
double Ax = ;
double Ay = ;
double Az = ;
double Bx = ;
double By = ;
double Bz = ;
double Cx = ;
double Cy = ;
double Cz = ;
double t = ((Cx - Ax) * (Bx - Ax) + (Cy - Ay) * (By - Ay)) / (Math.Pow(Bx - Ax, 2) + Math.Pow(By - Ay, 2));
double Dx = Ax + t*(Bx - Ax);
double Dy = Ay + t*(By - Ay);
Here is another python implementation without using a for loop. It works for any number of points and any number of line segments. Given p_array as a set of points, and x_array , y_array as continues line segments or a polyline.
This uses the equation Y = mX + n and considering that the m factor for a perpendicular line segment is -1/m.
import numpy as np
def ortoSegmentPoint(self, p_array, x_array, y_array):
"""
:param p_array: np.array([[ 718898.941 9677612.901 ], [ 718888.8227 9677718.305 ], [ 719033.0528 9677770.692 ]])
:param y_array: np.array([9677656.39934991 9677720.27550726 9677754.79])
:param x_array: np.array([718895.88881594 718938.61392781 718961.46])
:return: [POINT, LINE] indexes where point is orthogonal to line segment
"""
# PENDIENTE "m" de la recta, y = mx + n
m_array = np.divide(y_array[1:] - y_array[:-1], x_array[1:] - x_array[:-1])
# PENDIENTE INVERTIDA, 1/m
inv_m_array = np.divide(1, m_array)
# VALOR "n", y = mx + n
n_array = y_array[:-1] - x_array[:-1] * m_array
# VALOR "n_orto" PARA LA RECTA PERPENDICULAR
n_orto_array = np.array(p_array[:, 1]).reshape(len(p_array), 1) + inv_m_array * np.array(p_array[:, 0]).reshape(len(p_array), 1)
# PUNTOS DONDE SE INTERSECTAN DE FORMA PERPENDICULAR
x_intersec_array = np.divide(n_orto_array - n_array, m_array + inv_m_array)
y_intersec_array = m_array * x_intersec_array + n_array
# LISTAR COORDENADAS EN PARES
x_coord = np.array([x_array[:-1], x_array[1:]]).T
y_coord = np.array([y_array[:-1], y_array[1:]]).T
# FILAS: NUMERO DE PUNTOS, COLUMNAS: NUMERO DE TRAMOS
maskX = np.where(np.logical_and(x_intersec_array < np.max(x_coord, axis=1), x_intersec_array > np.min(x_coord, axis=1)), True, False)
maskY = np.where(np.logical_and(y_intersec_array < np.max(y_coord, axis=1), y_intersec_array > np.min(y_coord, axis=1)), True, False)
mask = maskY * maskX
return np.argwhere(mask == True)
As Ron Warholic and Nicolas Repiquet answered, this can be solved using vector projection. For completeness I'll add a python/numpy implementation of this here in case it saves anyone else some time:
import numpy as np
# Define some test data that you can solve for directly.
first_point = np.array([4, 4])
second_point = np.array([8, 4])
target_point = np.array([6, 6])
# Expected answer
expected_point = np.array([6, 4])
# Create vector for first point on line to perpendicular point.
point_vector = target_point - first_point
# Create vector for first point and second point on line.
line_vector = second_point - first_point
# Create the projection vector that will define the position of the resultant point with respect to the first point.
projection_vector = (np.dot(point_vector, line_vector) / np.dot(line_vector, line_vector)) * line_vector
# Alternative method proposed in another answer if for whatever reason you prefer to use this.
_projection_vector = (np.dot(point_vector, line_vector) / np.linalg.norm(line_vector)**2) * line_vector
# Add the projection vector to the first point
projected_point = first_point + projection_vector
# Test
(projected_point == expected_point).all()
Since you're not stating which language you're using, I'll give you a generic answer:
Just have a loop passing through all the points in your AB segment, "draw a segment" to C from them, get the distance from C to D and from A to D, and apply pithagoras theorem. If AD^2 + CD^2 = AC^2, then you've found your point.
Also, you can optimize your code by starting the loop by the shortest side (considering AD and BD sides), since you'll find that point earlier.
Here is a python implementation based on Corey Ogburn's answer from this thread.
It projects the point q onto the line segment defined by p1 and p2 resulting in the point r.
It will return null if r falls outside of line segment:
def is_point_on_line(p1, p2, q):
if (p1[0] == p2[0]) and (p1[1] == p2[1]):
p1[0] -= 0.00001
U = ((q[0] - p1[0]) * (p2[0] - p1[0])) + ((q[1] - p1[1]) * (p2[1] - p1[1]))
Udenom = math.pow(p2[0] - p1[0], 2) + math.pow(p2[1] - p1[1], 2)
U /= Udenom
r = [0, 0]
r[0] = p1[0] + (U * (p2[0] - p1[0]))
r[1] = p1[1] + (U * (p2[1] - p1[1]))
minx = min(p1[0], p2[0])
maxx = max(p1[0], p2[0])
miny = min(p1[1], p2[1])
maxy = max(p1[1], p2[1])
is_valid = (minx <= r[0] <= maxx) and (miny <= r[1] <= maxy)
if is_valid:
return r
else:
return None

Computing the 3D coordinates on a unit sphere from a 2D point

I have a square bitmap of a circle and I want to compute the normals of all the pixels in that circle as if it were a sphere of radius 1:
The sphere/circle is centered in the bitmap.
What is the equation for this?
Don't know much about how people program 3D stuff, so I'll just give the pure math and hope it's useful.
Sphere of radius 1, centered on origin, is the set of points satisfying:
x2 + y2 + z2 = 1
We want the 3D coordinates of a point on the sphere where x and y are known. So, just solve for z:
z = ±sqrt(1 - x2 - y2).
Now, let us consider a unit vector pointing outward from the sphere. It's a unit sphere, so we can just use the vector from the origin to (x, y, z), which is, of course, <x, y, z>.
Now we want the equation of a plane tangent to the sphere at (x, y, z), but this will be using its own x, y, and z variables, so instead I'll make it tangent to the sphere at (x0, y0, z0). This is simply:
x0x + y0y + z0z = 1
Hope this helps.
(OP):
you mean something like:
const int R = 31, SZ = power_of_two(R*2);
std::vector<vec4_t> p;
for(int y=0; y<SZ; y++) {
for(int x=0; x<SZ; x++) {
const float rx = (float)(x-R)/R, ry = (float)(y-R)/R;
if(rx*rx+ry*ry > 1) { // outside sphere
p.push_back(vec4_t(0,0,0,0));
} else {
vec3_t normal(rx,sqrt(1.-rx*rx-ry*ry),ry);
p.push_back(vec4_t(normal,1));
}
}
}
It does make a nice spherical shading-like shading if I treat the normals as colours and blit it; is it right?
(TZ)
Sorry, I'm not familiar with those aspects of C++. Haven't used the language very much, nor recently.
This formula is often used for "fake-envmapping" effect.
double x = 2.0 * pixel_x / bitmap_size - 1.0;
double y = 2.0 * pixel_y / bitmap_size - 1.0;
double r2 = x*x + y*y;
if (r2 < 1)
{
// Inside the circle
double z = sqrt(1 - r2);
.. here the normal is (x, y, z) ...
}
Obviously you're limited to assuming all the points are on one half of the sphere or similar, because of the missing dimension. Past that, it's pretty simple.
The middle of the circle has a normal facing precisely in or out, perpendicular to the plane the circle is drawn on.
Each point on the edge of the circle is facing away from the middle, and thus you can calculate the normal for that.
For any point between the middle and the edge, you use the distance from the middle, and some simple trig (which eludes me at the moment). A lerp is roughly accurate at some points, but not quite what you need, since it's a curve. Simple curve though, and you know the beginning and end values, so figuring them out should only take a simple equation.
I think I get what you're trying to do: generate a grid of depth data for an image. Sort of like ray-tracing a sphere.
In that case, you want a Ray-Sphere Intersection test:
http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter1.htm
Your rays will be simple perpendicular rays, based off your U/V coordinates (times two, since your sphere has a diameter of 2). This will give you the front-facing points on the sphere.
From there, calculate normals as below (point - origin, the radius is already 1 unit).
Ripped off from the link above:
You have to combine two equations:
Ray: R(t) = R0 + t * Rd , t > 0 with R0 = [X0, Y0, Z0] and Rd = [Xd, Yd, Zd]
Sphere: S = the set of points[xs, ys, zs], where (xs - xc)2 + (ys - yc)2 + (zs - zc)2 = Sr2
To do this, calculate your ray (x * pixel / width, y * pixel / width, z: 1), then:
A = Xd^2 + Yd^2 + Zd^2
B = 2 * (Xd * (X0 - Xc) + Yd * (Y0 - Yc) + Zd * (Z0 - Zc))
C = (X0 - Xc)^2 + (Y0 - Yc)^2 + (Z0 - Zc)^2 - Sr^2
Plug into quadratic equation:
t0, t1 = (- B + (B^2 - 4*C)^1/2) / 2
Check discriminant (B^2 - 4*C), and if real root, the intersection is:
Ri = [xi, yi, zi] = [x0 + xd * ti , y0 + yd * ti, z0 + zd * ti]
And the surface normal is:
SN = [(xi - xc)/Sr, (yi - yc)/Sr, (zi - zc)/Sr]
Boiling it all down:
So, since we're talking unit values, and rays that point straight at Z (no x or y component), we can boil down these equations greatly:
Ray:
X0 = 2 * pixelX / width
Y0 = 2 * pixelY / height
Z0 = 0
Xd = 0
Yd = 0
Zd = 1
Sphere:
Xc = 1
Yc = 1
Zc = 1
Factors:
A = 1 (unit ray)
B
= 2 * (0 + 0 + (0 - 1))
= -2 (no x/y component)
C
= (X0 - 1) ^ 2 + (Y0 - 1) ^ 2 + (0 - 1) ^ 2 - 1
= (X0 - 1) ^ 2 + (Y0 - 1) ^ 2
Discriminant
= (-2) ^ 2 - 4 * 1 * C
= 4 - 4 * C
From here:
If discriminant < 0:
Z = ?, Normal = ?
Else:
t = (2 + (discriminant) ^ 1 / 2) / 2
If t < 0 (hopefully never or always the case)
t = -t
Then:
Z: t
Nx: Xi - 1
Ny: Yi - 1
Nz: t - 1
Boiled farther still:
Intuitively it looks like C (X^2 + Y^2) and the square-root are the most prominent figures here. If I had a better recollection of my math (in particular, transformations on exponents of sums), then I'd bet I could derive this down to what Tom Zych gave you. Since I can't, I'll just leave it as above.

Drawing a triangle in a coordinate plane given its three sides

The length of three sides of the triangle, a, b and c will be given, and I need to find the coordinates of the vertices. The center (probably the circumcenter) can either be the origin or (x,y).
Can anyone point me in the right direction?
I've read brainjam's answer and checked whether his answer is true and he is right.
Calculation:
O(0;0), A(a;0) and B(x;y) are the three points of the triangle. C1 is the circle around A and r1 = c; C2 is the circle around O and r2 = b. B(X;Y) is the intersection of C1 and C2, which means that the point is on both of the circles.
C1: (x - a) * (x - a) + y * y = c * c
C2: x * x + y * y = b * b
y * y = b * b - x * x
(x - a) * (x - a) + b * b - x * x = c * c
x * x - 2 * a * x + a * a + b * b - x * x - c * c = 0
2 * a * x = (a * a + b * b - c * c)
x = (a * a + b * b - c * c) / (2 * a)
y * y = b * b - ((a * a + b * b - c * c) / (2 * a)) * ((a * a + b * b - c * c) / (2 * a))
y = +- sqrt(b * b - ((a * a + b * b - c * c) / (2 * a)) * ((a * a + b * b - c * c) / (2 * a)))
Place the first vertex at the origin (0,0). Place the second vertex at (a,0). To compute the third vertex, find the intersection of the two circles with centers (0,0) and (a,0) and radii b and c.
Update: Lajos Arpad has given the details of computing the location of the third point in this answer. It boils down to (x,y) where x = (b2+a2-c2)/2a and y=±sqrt(b2-x2)
This question and the answers helped me out today in implementing this. It will calculate the unknown vertices, "c" of circle intersections given 2 known points (a, b) and the distances (ac_length, bc_length) to the 3rd unknown vertex, "c".
Here is my resulting python implementation for anyone interested.
I also referenced the following:
http://mathworld.wolfram.com/RadicalLine.html
http://mathworld.wolfram.com/Circle-CircleIntersection.html
Using django's geos module for the Point() object, which could be replaced with shapely, or point objects removed altogether really.
from math import sqrt
from django.contrib.gis.geos import Point
class CirclesSeparate(BaseException):
pass
class CircleContained(BaseException):
pass
def discover_location(point_a, point_b, ac_length, bc_length):
"""
Find point_c given:
point_a
point_b
ac_length
bc_length
point_d == point at which the right-angle to c is formed.
"""
ab_length = point_a.distance(point_b)
if ab_length > (ac_length + bc_length):
raise CirclesSeparate("Given points do not intersect!")
elif ab_length < abs(ac_length - bc_length):
raise CircleContained("The circle of the points do not intersect")
# get the length to the vertex of the right triangle formed,
# by the intersection formed by circles a and b
ad_length = (ab_length**2 + ac_length**2 - bc_length**2)/(2.0 * ab_length)
# get the height of the line at a right angle from a_length
h = sqrt(abs(ac_length**2 - ad_length**2))
# Calculate the mid point (point_d), needed to calculate point_c(1|2)
d_x = point_a.x + ad_length * (point_b.x - point_a.x)/ab_length
d_y = point_a.y + ad_length * (point_b.y - point_a.y)/ab_length
point_d = Point(d_x, d_y)
# get point_c location
# --> get x
c_x1 = point_d.x + h * (point_b.y - point_a.y)/ab_length
c_x2 = point_d.x - h * (point_b.y - point_a.y)/ab_length
# --> get y
c_y1 = point_d.y - h * (point_b.x - point_a.x)/ab_length
c_y2 = point_d.y + h * (point_b.x - point_a.x)/ab_length
point_c1 = Point(c_x1, c_y1)
point_c2 = Point(c_x2, c_y2)
return point_c1, point_c2
When drawing an unknown triangle, it's usually easiest to pick one side (say, the longest) and place it horizontally or vertically. The endpoints of that side make up two of the triangle's vertices, and you can calculate the third by subdividing the triangle into two right triangles (the other two sides are the hypotenuses) and using the inverse sine/cosine functions to figure out the missing angles. By subdividing into right triangles, I mean something that looks like the image here: http://en.wikipedia.org/wiki/File:Triangle.TrigArea.svg Your first side would be AC in that drawing.
Once you have the triangle figured out, it should be easy to calculate it's center and translate it so that it is centered on whatever arbitrary center point you like.
First check the that the triangle is possible:
a+b >= c
b+c >= a
c+a >= b
Then, if it is, solve for the intersection of the two circles. The basic vertices are
{0,0}, {a,0}, {x,y}
where
x = (a^2-b^2+c^2)/(2a)
y = sqrt(c^2-x^2)
Finding the circumcenter is pretty easy from this point.

Why are there 3 conflicting OpenCV camera calibration formulas?

I'm having a problem with OpenCV's various parameterization of coordinates used for camera calibration purposes. The problem is that three different sources of information on image distortion formulae apparently give three non-equivalent description of the parameters and equations involved:
(1) In their book "Learning OpenCV…" Bradski and Kaehler write regarding lens distortion (page 376):
xcorrected = x * ( 1 + k1 * r^2 + k2 * r^4 + k3 * r^6 ) + [ 2 * p1 * x * y + p2 * ( r^2 + 2 * x^2 ) ],
ycorrected = y * ( 1 + k1 * r^2 + k2 * r^4 + k3 * r^6 ) + [ p1 * ( r^2 + 2 * y^2 ) + 2 * p2 * x * y ],
where r = sqrt( x^2 + y^2 ).
Assumably, (x, y) are the coordinates of pixels in the uncorrected captured image corresponding to world-point objects with coordinates (X, Y, Z), camera-frame referenced, for which
xcorrected = fx * ( X / Z ) + cx and ycorrected = fy * ( Y / Z ) + cy,
where fx, fy, cx, and cy, are the camera's intrinsic parameters. So, having (x, y) from a captured image, we can obtain the desired coordinates ( xcorrected, ycorrected ) to produced an undistorted image of the captured world scene by applying the above first two correction expressions.
However...
(2) The complication arises as we look at OpenCV 2.0 C Reference entry under the Camera Calibration and 3D Reconstruction section. For ease of comparison we start with all world-point (X, Y, Z) coordinates being expressed with respect to the camera's reference frame, just as in #1. Consequently, the transformation matrix [ R | t ] is of no concern.
In the C reference, it is expressed that:
x' = X / Z,
y' = Y / Z,
x'' = x' * ( 1 + k1 * r'^2 + k2 * r'^4 + k3 * r'^6 ) + [ 2 * p1 * x' * y' + p2 * ( r'^2 + 2 * x'^2 ) ],
y'' = y' * ( 1 + k1 * r'^2 + k2 * r'^4 + k3 * r'^6 ) + [ p1 * ( r'^2 + 2 * y'^2 ) + 2 * p2 * x' * y' ],
where r' = sqrt( x'^2 + y'^2 ), and finally that
u = fx * x'' + cx,
v = fy * y'' + cy.
As one can see these expressions are not equivalent to those presented in #1, with the result that the two sets of corrected coordinates ( xcorrected, ycorrected ) and ( u, v ) are not the same. Why the contradiction? It seems to me the first set makes more sense as I can attach physical meaning to each and every x and y in there, while I find no physical meaning in x' = X / Z and y' = Y / Z when the camera focal length is not exactly 1. Furthermore, one cannot compute x' and y' for we don't know (X, Y, Z).
(3) Unfortunately, things get even murkier when we refer to the writings in Intel's Open Source Computer Vision Library Reference Manual's section Lens Distortion (page 6-4), which states in part:
"Let ( u, v ) be true pixel image coordinates, that is, coordinates with ideal projection, and ( u ̃, v ̃ ) be corresponding real observed (distorted) image coordinates. Similarly, ( x, y ) are ideal (distortion-free) and ( x ̃, y ̃ ) are real (distorted) image physical coordinates. Taking into account two expansion terms gives the following:
x ̃ = x * ( 1 + k1 * r^2 + k2 * r^4 ) + [ 2 p1 * x * y + p2 * ( r^2 + 2 * x^2 ) ]
y ̃ = y * ( 1 + k1 * r^2 + k2 * r^4 ] + [ 2 p2 * x * y + p2 * ( r^2 + 2 * y^2 ) ],
where r = sqrt( x^2 + y^2 ). ...
"Because u ̃ = cx + fx * u and v ̃ = cy + fy * v , … the resultant system can be rewritten as follows:
u ̃ = u + ( u – cx ) * [ k1 * r^2 + k2 * r^4 + 2 * p1 * y + p2 * ( r^2 / x + 2 * x ) ]
v ̃ = v + ( v – cy ) * [ k1 * r^2 + k2 * r^4 + 2 * p2 * x + p1 * ( r^2 / y + 2 * y ) ]
The latter relations are used to undistort images from the camera."
Well, it would appear that the expressions involving x ̃ and y ̃ coincided with the two expressions given at the top of this writing involving xcorrected and ycorrected. However, x ̃ and y ̃ do not refer to corrected coordinates, according to the given description. I don't understand the distinction between the meaning of the coordinates ( x ̃, y ̃ ) and ( u ̃, v ̃ ), or for that matter, between the pairs ( x, y ) and ( u, v ). From their descriptions it appears their only distinction is that ( x ̃, y ̃ ) and ( x, y ) refer to 'physical' coordinates while ( u ̃, v ̃ ) and ( u, v ) do not. What is this distinction all about? Aren't they all physical coordinates? I'm lost!
Thanks for any input!
There is no one and only formula for camera calibration, they are all valid. Notice the first one contains constants K1, K2 & K3 for r^2, r^4 & r^6, and the other two only have constants for r^2 and r^4? That is because they are all approximate models. The first one is likely to be more accurate since it has more parameters.
Anytime you see:
r = sqrt( x^2 + y^2 )
it is probably safe to assume x = (the x coordinate pixel) - (the camera center in pixels) since r usually means radius from the center.
What are you trying to do by the way? Estimate the camera parameters, correct for lens distortion, or both?

Perpendicular on a line from a given point

How can I draw a perpendicular on a line segment from a given point? My line segment is defined as (x1, y1), (x2, y2), If I draw a perpendicular from a point (x3,y3) and it meets to line on point (x4,y4). I want to find out this (x4,y4).
I solved the equations for you:
k = ((y2-y1) * (x3-x1) - (x2-x1) * (y3-y1)) / ((y2-y1)^2 + (x2-x1)^2)
x4 = x3 - k * (y2-y1)
y4 = y3 + k * (x2-x1)
Where ^2 means squared
From wiki:
In algebra, for any linear equation
y=mx + b, the perpendiculars will all
have a slope of (-1/m), the opposite
reciprocal of the original slope. It
is helpful to memorize the slogan "to
find the slope of the perpendicular
line, flip the fraction and change the
sign." Recall that any whole number a
is itself over one, and can be written
as (a/1)
To find the perpendicular of a given
line which also passes through a
particular point (x, y), solve the
equation y = (-1/m)x + b, substituting
in the known values of m, x, and y to
solve for b.
The slope of the line, m, through (x1, y1) and (x2, y2) is m = (y1 - y2) / (x1 - x2)
I agree with peter.murray.rust, vectors make the solution clearer:
// first convert line to normalized unit vector
double dx = x2 - x1;
double dy = y2 - y1;
double mag = sqrt(dx*dx + dy*dy);
dx /= mag;
dy /= mag;
// translate the point and get the dot product
double lambda = (dx * (x3 - x1)) + (dy * (y3 - y1));
x4 = (dx * lambda) + x1;
y4 = (dy * lambda) + y1;
You know both the point and the slope, so the equation for the new line is:
y-y3=m*(x-x3)
Since the line is perpendicular, the slope is the negative reciprocal. You now have two equations and can solve for their intersection.
y-y3=-(1/m)*(x-x3)
y-y1=m*(x-x1)
You will often find that using vectors makes the solution clearer...
Here is a routine from my own library:
public class Line2 {
Real2 from;
Real2 to;
Vector2 vector;
Vector2 unitVector = null;
public Real2 getNearestPointOnLine(Real2 point) {
unitVector = to.subtract(from).getUnitVector();
Vector2 lp = new Vector2(point.subtract(this.from));
double lambda = unitVector.dotProduct(lp);
Real2 vv = unitVector.multiplyBy(lambda);
return from.plus(vv);
}
}
You will have to implement Real2 (a point) and Vector2 and dotProduct() but these should be simple:
The code then looks something like:
Point2 p1 = new Point2(x1, y1);
Point2 p2 = new Point2(x2, y2);
Point2 p3 = new Point2(x3, y3);
Line2 line = new Line2(p1, p2);
Point2 p4 = getNearestPointOnLine(p3);
The library (org.xmlcml.euclid) is at:
http://sourceforge.net/projects/cml/
and there are unit tests which will exercise this method and show you how to use it.
#Test
public final void testGetNearestPointOnLine() {
Real2 p = l1112.getNearestPointOnLine(new Real2(0., 0.));
Real2Test.assertEquals("point", new Real2(0.4, -0.2), p, 0.0000001);
}
Compute the slope of the line joining points (x1,y1) and (x2,y2) as m=(y2-y1)/(x2-x1)
Equation of the line joining (x1,y1) and (x2,y2) using point-slope form of line equation, would be y-y2 = m(x-x2)
Slope of the line joining (x3,y3) and (x4,y4) would be -(1/m)
Again, equation of the line joining (x3,y3) and (x4,y4) using point-slope form of line equation, would be y-y3 = -(1/m)(x-x3)
Solve these two line equations as you solve a linear equation in two variables and the values of x and y you get would be your (x4,y4)
I hope this helps.
cheers
Find out the slopes for both the
lines, say slopes are m1 and m2 then
m1*m2=-1 is the condition for
perpendicularity.
Matlab function code for the following problem
function Pr=getSpPoint(Line,Point)
% getSpPoint(): find Perpendicular on a line segment from a given point
x1=Line(1,1);
y1=Line(1,2);
x2=Line(2,1);
y2=Line(2,1);
x3=Point(1,1);
y3=Point(1,2);
px = x2-x1;
py = y2-y1;
dAB = px*px + py*py;
u = ((x3 - x1) * px + (y3 - y1) * py) / dAB;
x = x1 + u * px;
y = y1 + u * py;
Pr=[x,y];
end
Mathematica introduced the function RegionNearest[] in version 10, 2014. This function could be used to return an answer to this question:
{x4,y4} = RegionNearest[Line[{{x1,y1},{x2,y2}}],{x3,y3}]
This is mostly a duplicate of Arnkrishn's answer. I just wanted to complete his section with a complete Mathematica code snippet:
m = (y2 - y1)/(x2 - x1)
eqn1 = y - y3 == -(1/m)*(x - x3)
eqn2 = y - y1 == m*(x - x1)
Solve[eqn1 && eqn2, {x, y}]
This is a C# implementation of the accepted answer. It's also using ArcGis to return a MapPoint as that's what we're using for this project.
private MapPoint GenerateLinePoint(double startPointX, double startPointY, double endPointX, double endPointY, double pointX, double pointY)
{
double k = ((endPointY - startPointY) * (pointX - startPointX) - (endPointX - startPointX) * (pointY - startPointY)) / (Math.Pow(endPointY - startPointY, 2)
+ Math.Pow(endPointX - startPointX, 2));
double resultX = pointX - k * (endPointY - startPointY);
double resultY = pointY + k * (endPointX - startPointX);
return new MapPoint(resultX, resultY, 0, SpatialReferences.Wgs84);
}
Thanks to Ray as this worked perfectly for me.
c#arcgis
Just for the sake of completeness, here is a solution using homogeneous coordinates.
The homogeneous points are:
p1 = (x1,y1,1), p2 = (x2,y2,1), p3 = (x3,y3,1)
a line through two points is their cross-product
l_12 := p1 x p2 = (y1-y2, x2-x1, x1*y2 - x2*y1)
The (signed) distance of a point to a line is their dot product.
d := l_12 * p3 = x3*(y1-y2) + y3*(x2-x1) + x1*y2 - x2*y1
The vector from p4 to p3 is d times the normal vector of l_12 divided by the squared length of the normal vector.
n2 := (y1-y2)^2 + (x2-x1)^2
p4 := p3 + d/n2*(y1-y2, x2-x1, 0)
Note: if you divide l_12 by the length of the normal vector
l_12 := l_12 / sqrt((y1-y2)^2 + (x2-x1)^2)
the distance d will be the euclidean distance.
First, calculate the linear function determined by the points
(x1,y2),(x2,y2).
We get:
y1 = mx+b1 where m and b1 are constants.
This step is easy to calculate by the formula of linear function between two points.
Then, calculate the linear function y that goes through (x3,y3).
The function slope is -m, where m is the slope of y1.
Then calculate the const b2 by the coordinates of the point (x3,y3).
We get y2 = -mx+b2 where m and b2 are constants.
The last thing to do is to find the intersection of y1, y2.
You can find x by solving the equation: -mx+b2 = mx+b1, then place x in one of the equations to find y.
This is a vectorized Matlab function for finding pairwise projections of m points onto n line segments. Here xp and yp are m by 1 vectors holding coordinates of m different points, and x1, y1, x2 and y2 are n by 1 vectors holding coordinates of start and end points of n different line segments.
It returns m by n matrices, x and y, where x(i, j) and y(i, j) are coordinates of projection of i-th point onto j-th line.
The actual work is done in first few lines and the rest of the function runs a self-test demo, just in case where it is called with no parameters. It's relatively fast, I managed to find projections of 2k points onto 2k line segments in less than 0.05s.
function [x, y] = projectPointLine(xp, yp, x1, y1, x2, y2)
if nargin > 0
xd = (x2-x1)';
yd = (y2-y1)';
dAB = xd.*xd + yd.*yd;
u = bsxfun(#rdivide, bsxfun(#times, bsxfun(#minus, xp, x1'), xd) + ...
bsxfun(#times, bsxfun(#minus, yp, y1'), yd), dAB);
x = bsxfun(#plus, x1', bsxfun(#times, u, xd));
y = bsxfun(#plus, y1', bsxfun(#times, u, yd));
else
nLine = 3;
nPoint = 2;
xp = rand(nPoint, 1) * 2 -1;
yp = rand(nPoint, 1) * 2 -1;
x1 = rand(nLine, 1) * 2 -1;
y1 = rand(nLine, 1) * 2 -1;
x2 = rand(nLine, 1) * 2 -1;
y2 = rand(nLine, 1) * 2 -1;
tic;
[x, y] = projectPointLine(xp, yp, x1, y1, x2, y2);
toc
close all;
plot([x1'; x2'], [y1'; y2'], '.-', 'linewidth', 2, 'markersize', 20);
axis equal;
hold on
C = lines(nPoint + nLine);
for i=1:nPoint
scatter(x(i, :), y(i, :), 100, C(i+nLine, :), 'x', 'linewidth', 2);
scatter(xp(i), yp(i), 100, C(i+nLine, :), 'x', 'linewidth', 2);
end
for i=1:nLine
scatter(x(:, i)', y(:, i)', 100, C(i, :), 'o', 'linewidth', 2);
end
end
end

Resources