I'm having a really hard time understanding what you're doing or why, so I'm going to try to break down your code as I understand it, pointing out along the way why I think what you're doing doesn't make sense. This isn't meant to be demeaning or anything, it's my problem in that I haven't done enough (any) CV work to make sense of it.
Here goes:
%%%%OpenCV%%%%%`
E = cv.findEssentialMat(points1, points2, 'CameraMatrix',K, 'Method','Ransac');
[R, t] = cv.recoverPose(E, points1, points2,'CameraMatrix',K);
Okay, great - give some key points between two frames and see how they shift, then estimate your (change in) position given those points and the camera matrix. I understand this.
ry= asin(R(1,3));
u=[t(1,1);t(3,1);ry];
Okay you lost me. You are given a perfectly good rotation matrix R
, and then... what? You're trying to find the rotation about the y-axis? It looks like you're trying to use the definition of a rotation matrix, given on the Wikipedia page as:
$$
R_y(\theta) = \left[\begin{array}{ccc}
\cos\theta & 0 & \sin\theta \\
0 & 1 & 0 \\
-\sin\theta & 0 & \cos\theta \\
\end{array}\right]
$$
But, the problem here is those zeros - you don't have them in your output $R$ matrix. You do not have a matrix that is strictly a rotation about the $y$ axis. What's more is the fact that you said,
I want to estimate the pose of a robot defined by (x,y,theta).
So, what rotation are you expecting? If you rotate about the $y$ axis, then what you're saying is that you want to rotate points in the x-z plane. But, if you don't have any z-axis points, then all you're doing is rotating the x-axis points and you're not rotating the y-axis points at all. Verify this by looking at the second row of that matrix definition:
$\left[\begin{array}{ccc}
0&1&0 \\
\end{array}\right]$ - it exactly preserves the second row (y-values) of your points matrix.
Maybe this is what you want though, because the points you keep from the translation vector are the first and third, the $x$ and $z$ values. But again, you said you want to keep the $x$ and $y$ values, and this is where my lack of understanding of your inputs is hurting me. Maybe you are providing the inputs points1
and points2
as a 3xn matrix of points, [x;0;z], and everything is processing correctly. However, I did note that you can also pass a 2xn matrix of points, so again I'm not sure what your data set is or how you're expecting the output to look.
But beyond that, I'll skip the OpenGV section as it's commented out and go to:
theta=xLast(3)+u(3);
So here it looks like you're attempting a successive rotation by adding the previous rotation angle ry
, from xLast
, to the current value of rotation, ry
.
(Side note here - I would call the rotation something like dTheta
to show it's a difference value, like dx/dt, for example, but that's a nit-picky kind of point.)
if(theta>pi)
theta=theta-2*pi;
elseif(theta<-pi)
theta = theta+2*pi;
end
Bounds checking, okay.
s = sin(xLast(3));
c = cos(xLast(3));
Setting up for... a rotation matrix??
% actual value added with the new control vector
xnow=[xLast(1:2)+[c s; -s c]*u(1:2);theta];
And now mashing up the new rotation matrix with the previous information.
I mentioned the term "successive rotations" a bit ago, but you should read more about the homogeneous transform (PDF). Basically, you're allowed to do successive transforms just by multiplying the two together.
First, compose the matrix:
$$
H = \left[\begin{array}{ccc}
R & t \\
\left[\begin{array}{ccc}
0 & 0 & 0 \\
\end{array}\right] & 1 \\
\end{array}\right]
$$
Any time you get a new update, just post-multiply the new matrix. So, for example, on your first iteration, you'll get the pose of the second frame relative to the first:
$$
^1H_2 = \left[\begin{array}{ccc}
^1R_2 & ^1t_2 \\
\left[\begin{array}{ccc}
0 & 0 & 0 \\
\end{array}\right] & 1 \\
\end{array}\right]
$$
Your second iteration will give you the third frame relative to the second:
$$
^2H_3 = \left[\begin{array}{ccc}
^2R_3 & ^2t_3 \\
\left[\begin{array}{ccc}
0 & 0 & 0 \\
\end{array}\right] & 1 \\
\end{array}\right]
$$
BUT, what you really care about is the third frame relative to the first, so just multiply the two transforms together:
$$
^1H_3 = (^1H_2)(^2H_3) \\
$$
Want to get the fourth frame relative to the first? Easy -
$$
^1H_4 = (^1H_3)(^3H_4) \\
$$
And so on. You'll get:
$$
^1H_n = (^1H_{n-1})(^{n-1}H_n) \\
$$
The incremental adjustment, $^{n-1}H_n$, is the output of each iteration because you get $^{n-1}R_n$, the incremental rotation, and $^{n-1}t_n$, the incremental translation.
All this is to say that (I think) you should stop re-inventing the wheel. You dissolve a rotation matrix into an angle just to re-create a rotation matrix later. If you want to get the rotation matrix and translation vector at the end, just pull the appropriate parts: R = H(1:3,1:3);
and t = H(1:3,4);
. If you want, you can pull the individual components dX = t(1);
, dY = t(2);
, and dZ = t(3);
. I use the delta variable names dX
, etc. as a reminder that these are all relative translations from the first frame.
Regarding orientation, you should really be looking at a more proper conversion of the rotation matrix. You could use Euler angles or quaternions, but you really should not be trying to pull a single rotation angle from a single value in a matrix.
So, if I had your code to write again, I would probably go:
function [ xnow] = estimate_pose_test( points1, points2, K,xLast )
%%%%OpenCV%%%%%
E = cv.findEssentialMat(points1, points2, 'CameraMatrix',K, 'Method','Ransac');
[R, t] = cv.recoverPose(E, points1, points2,'CameraMatrix',K);
xnow = xLast*[R,t; zeros(1,3),1];
This keeps xnow
and xLast
as the 4x4 transform, but again if you really wanted the x/y/z values they're just the 3x1 vector starting at (1,4) in the homogeneous transform. Also, as mentioned, you should really be using a different method of displaying the rotation angle. You can keep the rotation matrix for internal stuff, but maybe Euler angles or Tait-Bryan angles would be the best for displaying a value to a user.
PS - I would guess the X
you get from the OpenGV code is actually the full homogeneous transform matrix, so you save a step by not needing to make it yourself (not that it's hard).
K
matrix? How are you gettingpoints1
andpoints2
? I'm not seeing the kind of documentation I would expect offhand (function X takes Y inputs of type A and gives Z outputs of type B), so it's hard to really troubleshoot what you're doing. It looks like you're updating your pose continuously for the OpenCV method but not OpenGV; is this true? Can you please post the data set and exact code you're using? $\endgroup$