If have a quesstion regarding matrix multiplication.
What's the information stored in the fourth row of a View Projection Matrix?
I thought rotation and scaling information is stored in the upper 3x3 Matrix, translation then in the fourth column with the last element set to 1.
Im struggling because i get following results for my VP Matrix:
When applying no rotation and no translation (note all values are rounded):
0.34 0 0 0
0 0.61 0 0
0 0 -1 -0.2
0 0 -1 0
Applying translation by -100:
0.34 0 0 0
0 0.61 0 -61.73
0 0 -1 -0.2
0 0 -1 0
Translation by -100, then rotate 30° on positive X-Axis, afterwards rotate 180° on positive Y-Axis:
-0.34 0 -3 0
0 0.53 0.3 -53.46
0 -0.5 0.86 49.8
0 -0.5 0.8 50
It doesnt look right to me. The funny part: It works. So whats the information of this line?
0 -0.5 0.8 50
Thanks for helping!
To me, your matrix looks a bit odd. Normally, the fourth row would contain the 4th component of the homogeneous coordinate frame, that is, something like [x,y,z]/w which would need to add up to 1 across the row for affine transformation. I guess your matrix works because the odd numbers in your fourth row are factored into the upper 3x3 part of the matrix. Did you try to change the order of your matrix concatenation, such as M'=M1*M0 vs. M'=M0*M1. A very good explanation of homogeneous coordinates is given by Jim Blinn in his Dirty Pixels and articles.
Also, this website contains a good walkthrough regarding homogeneous transforms
Related
I´m trying to create a view matrix for my program to be able to move and rotate the camera in OpenGL.
I have a camera struct that has the position and rotation vectors in it. From what I understood, to create the view matrix, you need to multiply the transform matrix with the rotation matrix to get the expected result.
So far I tried creating matrices for rotation and for transformation and multiply them like this:
> Transformation Matrix T =
1 0 0 -x
0 1 0 -y
0 0 1 -z
0 0 0 1
> Rotation Matrix Rx =
1 0 0 0
0 cos(-x) -sin(-x) 0
0 sin(-x) cos(-x) 0
0 0 0 1
> Rotation Matrix Ry =
cos(-y) 0 sin(-y) 0
0 1 0 0
-sin(-y) 0 cos(-y) 0
0 0 0 1
> Rotation Matrix Rz =
cos(-z) -sin(-z) 0 0
sin(-z) cos(-z) 0 0
0 0 1 0
0 0 0 1
View matrix = Rz * Ry * Rx * T
Notice that the values are negated, because if we want to move the camera to one side, the entire world is moving to the opposite side.
This solution seems to almost be working. The problem that I have is that when the camera is not at 0, 0, 0, if I rotate the camera, the position is changed. What I think is that if the camera is positioned at, let´s say, 0, 0, -20 and I rotate the camera, the position should remain at 0, 0, -20 right?
I feel like I´m missing something but I can´t seem to know what. Any help?
Edit 1:
It´s an assignment for university, so I can´t use any built-in functions!
Edit 2:
I tried changing the order of the operations and putting the translation in the left side, so T * Rz * Ry * Rx, but then the models rotate around themselves, and not around the camera.
Using a Kalman filter to predict motion in 2D space, we usually create the transition matrix with the following equations:
x(k+1) = x(k) + vt + (1/2)at^2
or simply
x(k+1) = x(k) + vt
with x: position, v: velocity, a: (constant) acceleration.
This results in a transition matrix that looks like this (for 2D space):
1 0 t 0
0 1 0 t
0 0 1 0
0 0 0 1
But the OpenCV examples suggest we use the following matrix when setting up the kalman filter in C++:
1 0 1 0
0 1 0 1
0 0 1 0
0 0 0 1
How can OpenCV interpret this correctly, knowing that a Kalman filter can be used for any dimension and unit?
I don't think it can. Instead of t, I used dt, where dt is the period of the measurements.
I am trying to do translation, rotation and scaling with subpixel precision in openCV.
This is the link for doing translation with subpixel pecision:
Translate image by very small step by OpenCV in C++
So, I need to do the same for scaling and rotation, as an example when I rotate image by 2 degree it works but when I rotate it by 1 or below 1 degree it doesn't work, and the result of rotation by 2 degree is the same as rotation by 2.1 degree!
In the provided link it is mentioned that I could increase the precision by changing the following code inside imgproc.hpp
enum InterpolationMasks {
INTER_BITS = 5,
INTER_BITS2 = INTER_BITS * 2,
INTER_TAB_SIZE = 1 << INTER_BITS,
INTER_TAB_SIZE2 = INTER_TAB_SIZE * INTER_TAB_SIZE
};
Here is an example for rotation:
Source image is the following:
0 0 0 0
0 255 255 0
0 255 255 0
0 0 0 0
I am doing rotation with respect to image center.
For rotation by 1 degree the result is same as source image!
And for rotation by 2 degree the result is same as rotation by 2.1 degree (which it should not be)!
Here is a code:
Mat rotateImage(Mat sourceImage, double rotationDegree){
Mat rotationMatrix, rotatedImage;
double rowOfImgCenter, colOfImgCenter;
rowOfImgCenter = scaledImage.rows / 2.0 - 0.5;
colOfImgCenter = scaledImage.cols / 2.0 - 0.5;
Point2d imageCenter(colOfImgCenter, rowOfImgCenter);
rotationMatrix = getRotationMatrix2D(imageCenter, rotationDegree, 1.0);
warpAffine(scaledImage, rotatedImage, rotationMatrix, scaledImage.size(), INTER_AREA);
return rotatedImage;
}
When I check the provided translation code, it works with 1e-7 precision but when I do the translation in column by 1e-8 it gives me the source image instead of translating it (which is not correct), when I do the code in matlab it gives me the following result which is correct (I want to have a same result with good accuracy in c++):
0 0 0 0
0 2.5499999745e+02 255 2.549999976508843e-06
0 2.5499999745e+02 255 2.549999976508843e-06
0 0 0 0
Also for rotation when I rotate the image by 1 degree the result should look like this (this is what I've got in matlab and want the same result in c++)
(I had to remove some numbers (reduce the accuracy) such that the matrix could fit in here)
0 0 1.1557313 0
1.1557313 2.5497614e+02 2.549761e+02 0
0 2.5497614e+02 2.549761e+02 1.1557313
0 1.1557313 0 0
Now my question is that how can I increase the subpixel precision in openCV?
or
Are there any ideas or codes to do the image scaling and rotation by subpixel precision (like the code provided for image translation in the mentioned link)?
I would appreciate any ideas.
I am writing a Tetris Clone, it is almost done, except for the collisions. For example In order to move the Piece Z I use a method:
void PieceZ::movePieceDown()
{
drawBlock (x1,y1++);
drawBlock (x2,y2++);
drawBlock (x3,y3++);
drawBlock (x4,y4++);
}
and in order to rotate a Piece I use a setter (because coordinates are private). For rotation I use a 90 degree clockwise rotation matrix. For example if I want to move (x1,y1) and (x2, y2) is my origin, to get x and y of a new block:
newX = (y1-y2) + x2;
newY = (x2-x1) + y2 + 1;
That works to some extent, it starts out as:
0 0 0 0
0 1 1 0
0 0 1 1
0 0 0 0
Then as planned it rotates to:
0 0 0 1
0 0 1 1
0 0 1 0
0 0 0 0
And then it rotates to Piece S:
0 0 0 0
0 0 1 1
0 1 1 0
0 0 0 0
And then it just alternates between the second and the third stages.
My calculations are wrong but I can't figure out where, I just need a little hint.
Ok here is how it should go (somewhat):
Determine where you want to rotate the piece (this could be the upper or lower corner or the center) and call it origin
Calculate the new x newX = y - origin.y;
Calculate the new y newY = -x + origin.x;
This should work (I got this idea from wikipedia and rotation matrixes: https://en.wikipedia.org/wiki/Transformation_matrix)
# Iwillnotexist Idonotexist presented his code for image perspective transformation (rotations around 3 axes): link
I'm looking for a function (or math) to make an inverse perspective transformation.
Let's make an assumption, that my "input image" is a result of his warpImage() function, and all angles (theta, phi and gamma), scale and fovy are also known.
I'm looking for a function (or math) to compute inverse transformation (black border doesn't matter) to get an primary image.
How can I do this?
The basic idea is you need to find the inverse transformation. In the linked question they have F = P T R1 R2 where P is the projective transformation, T is a translation, and R1, R2 are two rotations.
Denote F* as the inverse transformation. We can the inverse as F* = R2* R1* T* P*. Note the order changes. Three of these are easy R1* is just another rotation but with the angle negated. So the first inverse rotation would be
cos th sin th 0 0
R1* = -sin th cos th 0 0
0 0 1 0
0 0 1
Note the signs on the two sin terms are reversed.
The inverse of a translation is just a translation in the opposite direction.
1 0 0 0
T*= 0 1 0 0
0 0 1 h
0 0 0 1
You can check these calculating T* T which should be the identity matrix.
The trickiest bit is the projective component we have
cot(fv/2) 0 0 0
P = 0 cot(fv/2) 0 0
0 0 -(f+n)/(f-n) -2 f n / (f-n)
0 0 -1 0
The inverse of this is
tan(fv/2) 0 0 0
P*= 0 tan(fv/2) 0 0
0 0 0 -2
0 0 (n-f)/(f n) (f+n)/(f n)
Wolfram alpha inverse with v=fv
You then need to multiply these together in the reverse order to get the final matrix.
I also had issues to back-transform my image.
You need to store the points
ptsInPt2f and ptsOutPt2f
which are computed in the the 'warpMatrix' method.
To back-transform, simply use the same method
M = getPerspectiveTransform(ptsOutPt2f, ptsInPt2f);
but with reversed param order (output as first argument, input as second).
Afterwards a simple crop will get rid of all the black.