My understanding of the WPF transformation classes is that the Matrix class represents a 3x3 row-major matrix of 2D homogenised coordinates where the final column is always (0,0,1). I understand that the reason for this design is to facilitate translations to be represented as matrix multiplications, in the same way as rotate, scale and skew transformations, rather than separately as vectors, which would have to be the case if 2x2 matrices were used.
My expectation therefore is that when multiplying a Vector by a Matrix that contains a translation, the resultant vector should be translated. This does not seem to be happening for me when using the WPF matrix classes, so what am I doing wrong?
Matrix m = new Matrix();
m.Translate(12, 34);
Vector v = new Vector(100, 200);
Vector r = Vector.Multiply(v, m);
// Confirm that the matrix was translated correctly
Debug.WriteLine(m);
// Confirm that the vector has been translated
Debug.WriteLine(r);
Results:
1,0,0,1,12,34 // Matrix contains translation as expected
100,200 // Vector is unchanged - not expected
I see now. The distinction between a Vector and a Point is important. I should be using Points and Point.Multiply instead, and then the results are what I was expecting. A vector is the difference between two points, which is unaffected by a translation, whereas a point is a specific location which is affected.
Related
I need an inverse perspective transform written in Pascal/Delphi/Lazarus. See the following image:
I think I need to walk through destination pixels and then calculate the corresponding position in the source image (To avoid problems with rounding errors etc.).
function redraw_3d_to_2d(sourcebitmap:tbitmap, sourceaspect:extended, point_a, point_b, point_c, point_d:tpoint, megapixelcount:integer):tbitmap;
var
destinationbitmap:tbitmap;
x,y,sx,sy:integer;
begin
destinationbitmap:=tbitmap.create;
destinationbitmap.width=megapixelcount*sourceaspect*???; // I dont how to calculate this
destinationbitmap.height=megapixelcount*sourceaspect*???; // I dont how to calculate this
for x:=0 to destinationbitmap.width-1 do
for y:=0 to destinationbitmap.height-1 do
begin
sx:=??;
sy:=??;
destinationbitmap.canvas.pixels[x,y]=sourcebitmap.canvas.pixels[sx,sy];
end;
result:=destinationbitmap;
end;
I need the real formula... So an OpenGL solution would not be ideal...
Note: There is a version of this with proper math typesetting on the Math SE.
Computing a projective transformation
A perspective is a special case of a projective transformation, which in turn is defined by four points.
Step 1: Starting with the 4 positions in the source image, named (x1,y1) through (x4,y4), you solve the following system of linear equations:
[x1 x2 x3] [λ] [x4]
[y1 y2 y3]∙[μ] = [y4]
[ 1 1 1] [τ] [ 1]
The colums form homogenous coordinates: one dimension more, created by adding a 1 as the last entry. In subsequent steps, multiples of these vectors will be used to denote the same points. See the last step for an example of how to turn these back into two-dimensional coordinates.
Step 2: Scale the columns by the coefficients you just computed:
[λ∙x1 μ∙x2 τ∙x3]
A = [λ∙y1 μ∙y2 τ∙y3]
[λ μ τ ]
This matrix will map (1,0,0) to a multiple of (x1,y1,1), (0,1,0) to a multiple of (x2,y2,1), (0,0,1) to a multiple of (x3,y3,1) and (1,1,1) to (x4,y4,1). So it will map these four special vectors (called basis vectors in subsequent explanations) to the specified positions in the image.
Step 3: Repeat steps 1 and 2 for the corresponding positions in the destination image, in order to obtain a second matrix called B.
This is a map from basis vectors to destination positions.
Step 4: Invert B to obtain B⁻¹.
B maps from basis vectors to the destination positions, so the inverse matrix maps in the reverse direction.
Step 5: Compute the combined Matrix C = A∙B⁻¹.
B⁻¹ maps from destination positions to basis vectors, while A maps from there to source positions. So the combination maps destination positions to source positions.
Step 6: For every pixel (x,y) of the destination image, compute the product
[x'] [x]
[y'] = C∙[y]
[z'] [1]
These are the homogenous coordinates of your transformed point.
Step 7: Compute the position in the source image like this:
sx = x'/z'
sy = y'/z'
This is called dehomogenization of the coordinate vector.
All this math would be so much easier to read and write if SO were to support MathJax… ☹
Choosing the image size
The above aproach assumes that you know the location of your corners in the destination image. For these you have to know the width and height of that image, which is marked by question marks in your code as well. So let's assume the height of your output image were 1, and the width were sourceaspect. In that case, the overall area would be sourceaspect as well. You have to scale that area by a factor of pixelcount/sourceaspect to achieve an area of pixelcount. Which means that you have to scale each edge length by the square root of that factor. So in the end, you have
pixelcount = 1000000.*megapixelcount;
width = round(sqrt(pixelcount*sourceaspect));
height = round(sqrt(pixelcount/sourceaspect));
Use Graphics32, specifically TProjectiveTransformation (to use with the Transform method). Don't forget to leave some transparent margin in your source image so you don't get jagged edges.
I have an application where I want to scale, rotate, and translate some 3D points.
I'm used to seeing 3x3 rotation matrices, and storing translation in a separate array of values. But the .Net Matrix3D structure ( https://msdn.microsoft.com/en-us/library/System.Windows.Media.Media3D.Matrix3D%28v=vs.110%29.aspx) is 4x4 and has a row of "offsets" - OffsetX, OffsetY, OffsetZ, which are apparently used for translation. But how, exactly, are they intended to be applied?
Say I have a Vector3D with X, Y, Z values, say 72, 24, 4. And say my Matrix3D has
.707 0 -.707 0
0 1 0 0
.707 0 .707 0
100 100 0 1
i.e., so the OffsetX and OffsetY values are 100.
Is there any method or operator for Matrix3D that will apply this as a translation to my points? Transform() doesn't seem to. If my code has . . .
Vector3D v = new Vector3D(72, 24, 0);
Vector3D vectorResult = new Vector3D();
vectorResult = MyMatrix.Transform(v);
vectorResult has 8.484, 24, -8.484, and it has the same values if the offsets are 0.
Obviously I can manually apply the translation individually for each axis, but I thought since it's part of the structure there might be some method or operator where you give it a point and it applies the entire matrix including translation. Is there?
A 4x4 matrix represents a transform in 3D space using homogeneous coordinates. In this representation, a w component is added to the vector. This component differs based on what a vector should represent. Transforming a vector with the matrix is simple multiplication:
transformed = vector * matrix
(where both vectors are row-vectors).
The w component is only considered by the matrix' last row - the part where the translation is stored. So if you want to transform points, this component needs to be 1. If you want to transform directions, this component needs to be 0 (because direction vectors do not change if you translate them).
This difference is expressed with two different structures in WPF. The Vector3D represents a direction (with w component 0) and the Point3D represents a point (with w component 1). So if you make v a Point3D, everything should work as you expect.
I am developing a game in XNA (C#), I am wondering how to use 2 versions of transformation. In my idea, the works of this functions are:
(Assume that vectors are originated from Matrix.Identity)
Vector2 resultVec = Vector2.Transform(sourceVector, destinationMatrix); is used for Position vectors transformation.
Vector2 resultVec = Vector2.TransformNormal(sourceVector, destinationMatrix); used for transforming Velocity vectors.
Is that true?. Who knows the explanation in detail, please help!
The simple answer is that -
Vector2.Transform() applies the entire Matrix to the vector while
Vector2.TransformNormal() only applies the Scale and Rotational parts of the Matrix to the vector.
With transformation, functions will multiply the source vector with the produced matrices.
Transform() is used for vectors representing the positions in 2D or 3D space. This will, in detail, take the Transpose (T operator) of the Invert matrix represents your Coordinate.
In Math: retVec = T(M ^ -1) x srcVec.
TransformNormal() used for direction, tangent vectors. This reserves the matrix.
In Math: retVect = srcVec x M.
To transform a vector from one matrix/coordinate to another (say M1 to M2): retVec = Transform by M1 -> then transform by invert of M2:
Vector2 retVec = Vector2.Transform(vectorInSource, M1);
Matrix invertDestMatrix = Matrix.Invert(M2);
outVect= Vector2.Transform(retVec , invertDestMatrix);
I'm currently trying to wrap my head around WPF, and I'm at the stage of converting between coordinate spaces with Matrix3D structures.
After realising WPF has differences between Point3D and Vector3D (thats two hours I'll never get back...) I can get a translation matrix set up. I'm now trying to introduce a rotation matrix, but it seems to be giving innacurate results. Here is my code for my world coordinate transformation...
private Point3D toWorldCoords(int x, int y)
{
Point3D inM = new Point3D(x, y, 0);
//setup matrix for screen to world
Screen2World = Matrix3D.Identity;
Screen2World.Translate(new Vector3D(-200, -200, 0));
Screen2World.Rotate(new Quaternion(new Vector3D(0, 0, 1), 90));
//do the multiplication
Point3D outM = Point3D.Multiply(inM, Screen2World);
//return the transformed point
return new Point3D(outM.X, outM.Y, m_ZVal);
}
The translation appears to be working fine, the rotation by 90 degrees however seems to return floating point inaacuracies. The Offset row of the matrix seems to be off by a slight factor (0.000001 either way) which is producing aliasing on the renders. Is there something I'm missing here, or do I just need to manually round the matrix up?
Cheers
Even with double precision mathematics there will be rounding errors with matrix multiplication.
You are performing 4 multiplications and then summing the results for each element in the new matrix.
It might be better to set your Screen2World matrix up as the translation matrix to start with rather than multiplying an identity matrix by your translation and then by the rotation. That's two matrix multiplications rather than one and (more than) twice the rounding error.
I have been developing (for the last 3 hours) a small project I'm doing in C# to help me choose a home.
Specifically, I am putting crime statistics in an overlay on Google maps, to find a nice neighborhood.
Here is an example:
http://otac0n.com/Demos/prospects.html
Now, I manually found the Lat and Lng to match the corners of the map displated in the example, but I have a few more maps to overlay.
My new application allows me to choose a landmark and point at the image to tie the Pixel to a LatLng. Something like:
locations.Add(new LocationPoint(37.6790f, -97.3125f, "Kellogg and I-135"));
// and later...
targetPoint.Pixel = FindPixel(mouseEvent.Location);
So, I've gathered a list of pixel/latlng combinations, and now would like to transform the image (using affine or non-affine transformations).
The goal here is to make every street line up. Given a good map, the only necessary transformation would be a rotation to line the map up north-to-south (and for now I would be happy with that). But I'm not sure where to start.
Does anybody have any experience doing image transformations in C#? How would I find the proper rotation to make the map level?
After the case of well-made maps is resolved, I would eventually like to be able to overlay hand drawn maps. This would obviously entail heavy distortion of the final image, and may be beyond the scope of this first iteration. However, I would not like to develop a system that would be un-expandable to this system in the future.
I'm unsure of what exactly do you want to accomplish, but if you want to fit more than three points on one map to more than three points on another one, there are basically two ways you can go:
You could try to create a triangular mesh over your points, and then apply a different affine transformation within each triangle, and get a piecewise linear transformation. To get the meshing right, you'll probably need to do something like a Delaunay triangulation of the points, for which qhull should probably be your preferred option.
You can go for a higher order transform, such as quad distortion, but it will probably be hard to find a solution that works for any number of points in a generic position. Find yourself a good finite element method book, and read the chapter(s) on higher order isoparametric elements, either lagrangian or serendipity ones, which will provide you with well-behaved mappings of many point to many points. Here are a couple of links(1 and 2) to set you on your way. But be aware that the math content is intensive...
In 2D space affine transformation can be specified by two sets of three nonlinear 2D points. In C# you can use the following routine to compute appropriate Matrix:
public static Matrix fit(PointF[] src, PointF[] dst) {
Matrix m1 = new Matrix(new RectangleF(0, 0, 1, 1), src);
m1.Invert();
Matrix m2 = new Matrix(new RectangleF(0, 0, 1, 1), dst);
m2.Multiply(m1);
return m2;
}
It works for both array arguments having 3 elements.
If you only need rotation and translation, then you can use the following routine:
public static Matrix fitOrt(PointF src1, PointF src2, PointF dst1, PointF dst2) {
return fit(new PointF[] { src1, src2, ort(src1, src2) },
new PointF[] { dst1, dst2, ort(dst1, dst2) });
}
public static PointF ort(PointF p, PointF q) {
return new PointF(p.X + q.Y - p.Y, p.Y - q.X + p.X);
}
If you would like to find the best approximation between two sets of multiple points then you can start with this http://elonen.iki.fi/code/misc-notes/affine-fit/
Beautiful.
So, thanks To Jamie's direction, I have found this:
Delaunay Triangulation in .NET 2.0
http://local.wasp.uwa.edu.au/~pbourke/papers/triangulate/morten.html
At this point, this is pretty much simplified to lerping.