I’m having troubles with rotation.
What I want to do is this:
Rotate an image
Detect features on the rotated image (points)
Rotate back the points so I can have the points coordinates corresponding to the initial image
I’m a bit stuck on the third step.
I manage to rotated the image with the following code:
cv::Mat M(2, 3, CV_32FC1);
cv::Point2f center((float)dst_img.rows / 2.0f, (float)dst_img.cols / 2.0f);
M = cv::getRotationMatrix2D(center, rotateAngle, 1.0);
cv::warpAffine(dst_img, rotated, M, cv::Size(rotated.cols, rotated.rows));
I try to rotate back the points with this code:
float xp = r.x * std::cos( PI * (-rotateAngle) / 180 ) - r.y * sin(PI * (rotateAngle) / 180);
float yp = r.x * sin(PI * (-rotateAngle) / 180) + r.y * cos(PI * (rotateAngle) / 180);
It is not to fare to be working but the points don’t go back well on the image. There is an offset.
Thank you for your help
If M is the rotation matrix you get from cv::getRotationMatrix2D, to rotate a cv::Point p with this matrix you can do this:
cv::Point result;
result.x = M.at<double>(0,0)*p.x + M.at<double>(0,1)*p.y + M.at<double>(0,2);
result.y = M.at<double>(1,0)*p.x + M.at<double>(1,1)*p.y + M.at<double>(1,2);
If you want to rotate a point back, generate the inverse matrix of M or use cv::getRotationMatrix2D(center, -rotateAngle, scale) to generate a matrix for reverse rotation.
For a rotation matrix, its transpose is its inverse. So you can just do M.t() * r to move it back to your original frame, where r is a cv::Mat (you might have to convert it to a cv::Mat from a cv::Point2f or whatever, or just write out the matrix multiplication explicitly).
Here's the code to do it explicitly (should be correct, but warning, it's entirely untested):
cv::Point2f p;
p.x = M.at<float>(0, 0) * r.x + M.at<float>(1, 0) * r.y;
p.y = M.at<float>(0, 1) * r.x + M.at<float>(1, 1) * r.y;
// p contains r rotated back to the original frame.
I had the same problem.
For a transform M and point pp in the rotated image, we wish to find the point pp_org in the coordanates of the original image. Use the following lines:
cv::Mat_<double> iM;
cv::invertAffineTransform(M, iM);
cv::Point2f pp_org = iM*pp;
Where the operator * in the above line is defined as:
cv::Point2f operator*(cv::Mat_<double> M, const cv::Point2f& p)
{
cv::Mat_<double> src(3/*rows*/,1 /* cols */);
src(0,0)=p.x;
src(1,0)=p.y;
src(2,0)=1.0;
cv::Mat_<double> dst = M*src; //USE MATRIX ALGEBRA
return cv::Point2f(dst(0,0),dst(1,0));
}
Note: M is the rotation matrix you used to go from the original to the rotated image
You need to rotate your points accorning to center point of your image.
Here x and y are your points which you want to rotate, imageCenter_x aand _y is center point of your image.
Below is my code.
angle = angle * (M_PI / 180);
float axis_x = x - imageCenter_x;
float axis_y = y - imageCenter_y;
x = axis_x * cos(angle) + axis_y * sin(angle);
y = (-axis_x) * sin(angle) + axis_y * cos(angle);
x = x + imageCenter_x;
y = y + imageCenter_y;
Related
I have a camera set up with the coordinates of 0, 0, 1000 and a cube at 0, 0, 0. There is a camera position vector, rotation vector and target vector.
When finding the target, in 2d space I would use:
newx = cos(angle); // this will be very small so i would multiply it by 100 or something idk
newy = sin(angle); // same and so on
So in 3d space I'm assuming that I would use:
newx = cos(angle);
newy = sin(angle);
newz = tan(angle);
But because I'm using the mouse to find the x and y direction the z rotation is always 0:
float x_diff = (WIDTH/2) - mousePos.x;
x_diff /= WIDTH;
float y_diff = (HEIGHT/2)- mousePos.y;
y_diff /= HEIGHT;
cameraRotation.x += /* too small of a number so multiply by 5 */ 5 * (FOV * x_diff);
cameraRotation.y += 5 * (FOV * y_diff);
cameraRotation.z += ???;
and so the target z will always be 0.
I could be doing this whole thing completely wrong I don't know.
But to sum it, up i need help calculating the cameras target (FOV: 90) for its rotation in 3D space.
I cannot understand the math behind this problem, I am trying to create an FPS camera where I can look freely with my mouse input.
I am trying to rotate and position my lookat point with 180 degrees of freedom. I understand the easier solution is to glRotate the world to fit my perspective, but I do not want this approach. I am fairly unfamiliar with the trigonometry involved here and cannot figure out how to solve this problem the way I want to...
here is my attempt to do this so far...
code to get mouse coordinates relative to the center of the window, then process it in my camera object
#define DEG2RAD(a) (a * (M_PI / 180.0f))//convert to radians
static void glutPassiveMotionHandler(int x, int y) {
glf centerX = WinWidth / 2; glf centerY = WinHeight / 2;//get windows origin point
f speed = 0.2f;
f oldX = mouseX; f oldY = mouseY;
mouseX = DEG2RAD(-((x - centerX)));//get distance from 0 and convert to radians
mouseY = DEG2RAD(-((y - centerY)));//get distance from 0 and convert to radians
f diffX = mouseX - oldX; f diffY = mouseY - oldY;//get difference from last frame to this frame
if (mouseX != 0 || mouseY != 0) {
mainCamera->Rotate(diffX, diffY);
}
Code to rotate the camera
void Camera::Rotate(f angleX, f angleY) {
Camera::refrence = Vector3D::NormalizeVector(Camera::refrence * cos(angleX)) + (Camera::upVector * sin(angleY));//rot up
Camera::refrence = Vector3D::NormalizeVector((Camera::refrence * cos(angleY)) - (Camera::rightVector * sin(angleX)));//rot side to side
};
Camera::refrence is our lookat point, processing the lookat point is handled as follows
void Camera::LookAt(void) {
gluLookAt(
Camera::position.x, Camera::position.y, Camera::position.z,
Camera::refrence.x, Camera::refrence.y, Camera::refrence.z,
Camera::upVector.x, Camera::upVector.y, Camera::upVector.z
);
};
The camera is defined by a position point (position) a target point (refrence) and a up-vector upVector. If you want to change the orientation of the camera, then you've to rotate the direction vector from the position (position) to the target (refrence) rather then the target point by a Rotation matrix.
Note, since the 2 angles are angles which should change an already rotated view, you've to use a rotation matrix, to rotate the vectors which point in an arbitrary direction.
Write a function which set 3x3 rotation matrix around an arbitrary axis:
void RotateMat(float m[], float angle_radians, float x, float y, float z)
{
float c = cos(angle_radians);
float s = sin(angle_radians);
m[0] = x*x*(1.0f-c)+c; m[1] = x*y*(1.0f-c)-z*s; m[2] = x*z*(1.0f-c)+y*s;
m[3] = y*x*(1.0f-c)+z*s; m[4] = y*y*(1.0f-c)+c; m[5] = y*z*(1.0f-c)-x*s;
m[6] = z*x*(1.0f-c)-y*s; m[7] = z*y*(1.0f-c)+x*s; m[8] = z*z*(1.0f-c)+c };
}
Write a function which rotates a 3 dimensional vector by the matrix:
Vector3D Rotate(float m[], const Vector3D &v)
{
Vector3D rv;
rv.x = m[0] * v.x + m[3] * v.y + m[6] * v.z;
rv.y = m[1] * v.x + m[4] * v.y + m[7] * v.z;
rv.z = m[2] * v.x + m[5] * v.y + m[8] * v.z;
return rv;
}
Calculate the vector form the position to the target:
Vector3D los = Vector3D(refrence.x - position.x, refrence.y - position.y, refrence.z - position.z);
Rotate all the vectors around the z axis of the world by angleX:
float rotX[9];
RotateMat(rotX, angleX, Vector3D(0, 0, 1));
los = Rotate(rotX, los);
upVector = Rotate(rotX, upVector);
Rotate all the vectors around the current y axis of the view by angleY:
float rotY[9];
RotateMat(rotY, angleY, Vector3D(los.x, los.y, 0.0));
los = Rotate(rotY, los);
upVector = Rotate(rotY, upVector);
Calculate the new target point:
refrence = Vector3D(position.x + los.x, position.y + los.y, position.z + los.z);
U_Cam_X_angle is left right rotation.. U_Cam_Y_angle is up down rotation.
view_radius is the view distance (zoom) to U_look_point_x, U_look_point_y and U_look_point_z.
This is ALWAYS a negative number! This is because you are always looking in positive direction. Deeper in the screen is more positive.
This is all in radians.
The last three.. eyeX, eyeY and eyeZ is where the camera is in 3D space.
This code is in VB.net. Find a converter online for VB to C++ or do it manually.
Public Sub set_eyes()
Dim sin_x, sin_y, cos_x, cos_y As Single
sin_x = Sin(U_Cam_X_angle + angle_offset)
cos_x = Cos(U_Cam_X_angle + angle_offset)
cos_y = Cos(U_Cam_Y_angle)
sin_y = Sin(U_Cam_Y_angle)
cam_y = Sin(U_Cam_Y_angle) * view_radius
cam_x = (sin_x - (1 - cos_y) * sin_x) * view_radius
cam_z = (cos_x - (1 - cos_y) * cos_x) * view_radius
Glu.gluLookAt(cam_x + U_look_point_x, cam_y + U_look_point_y, cam_z + U_look_point_z, _
U_look_point_x, U_look_point_y, U_look_point_z, 0.0F, 1.0F, 0.0F)
eyeX = cam_x + U_look_point_x
eyeY = cam_y + U_look_point_y
eyeZ = cam_z + U_look_point_z
End Sub
Many of us are familiar with the approach to rotating a 2D vector around the origin given an angle theta:
newX = x * cos(theta) - y * sin(theta);
newY = x * sin(theta) + y * cos(theta);
I'm now trying to rotate coordinates in image UV space, which looks like this:
(Image borrowed from this SO question.)
Here the units of the u axis are wider than those of the v axis, so the approach above leads to the coordinates rotating around an ellipse as opposed to a circle. I need the rotation of the vector to act as though the coordinates were square, meaning the aspect ratio needs to be accounted for. I thought it'd be as simple as stretching the coordinates to a square space, rotating, then stretching back, although it still appears that the vectors are rotating elliptically:
newX = (x * cos(theta) * Aspect - y * sin(theta)) / Aspect;
newY = x * sin(theta) * Aspect + y * cos(theta);
Any help is appreciated, thanks in advance!
The general version for rotation and aspect ratio is:
(center_c, center_y) being the center of rotation
(aspect_x, aspect_y) being the aspect_ratio
tmp_x = (x-center_x)/aspect_x
tmp_y = (y-center_y)/aspect_y
tmp_x = tmp_x * cos(theta) - tmp_y * sin(theta)
tmp_x = tmp_x * sin(theta) + tmp_y * cos(theta)
new_x = aspect_x*tmp_x-center_x
new_y = aspect_y*tmp_x-center_y
Hope that helps.
Is there a way to calculate the XYZ position in front of a quaternion (XYZW) rotation, preferably using GLM?
I know the Quat rotation and the Position of the object I want to calculate the position in front of.
I know how to calculate the position in front of a rotation matrix where you have a Front vector, Up vector and Right vector, but in this case I only have XYZW values (where W is always 0, I never see it becomming 1..?)
In very short:
The data I have: Quat (X Y Z W) and Position(X Y Z) and I want to calculate PositionInFront(Position, Quat, Distance, &X, &Y, &Z)
How to accomplish this goal?
I tried a cast to 3x3matrix and perform the Up,Right,Front (because a 3x3 matrix cast is these values, right?) calculations but they do not return the correct positions.
Or would it be possible to determine the objects Z Angle? (rotation around world Z / height axis only)
It seemed that there were 2 more quaternion structures for the vehicle which I forgot to use. and those 3 are the complete set needed for the Front,Right,Up calculation formula:
float offX = 10.0f;
float offY = 0.0f;
float offZ = 0.0f;
float x = offX * info.Rotation.Front.x + offY * info.Rotation.Right.x + offZ * info.Rotation.Up.x + info.Pos.x;
float y = offX * info.Rotation.Front.y + offY * info.Rotation.Right.y + offZ * info.Rotation.Up.y + info.Pos.y;
float z = offX * info.Rotation.Front.z + offY * info.Rotation.Right.z + offZ * info.Rotation.Up.z + info.Pos.z;
float Angle = (atan2(x-info.Pos.x, y-info.Pos.y) * 180.0f / PI);
The problem is when I face my camera down the z axis for example and pitch this works fine however, after I have finished the pitch and would like to yaw on this new axis it begins to roll for some unknown reason =s.
void FrustumCamera::xAxisRotation(float angle)
{
// angle = angle * (double)degToRad;
Vector3<float> x = m_orientation.getXAxis();
Vector3<float> y = m_orientation.getYAxis();
Vector3<float> z = m_orientation.getZAxis();
y.rotateAroundAxis(x,angle);
x = m_orientation.getXAxis();
z.rotateAroundAxis(x,angle);
m_orientation.setYAxis(y);
m_orientation.setZAxis(z);
}
void FrustumCamera::yAxisRotation(float angle)
{
// angle = angle * (double)degToRad;
Vector3<float> x = m_orientation.getXAxis();
Vector3<float> y = m_orientation.getYAxis();
Vector3<float> z = m_orientation.getZAxis();
x.rotateAroundAxis(y,angle);
y = m_orientation.getYAxis();
z.rotateAroundAxis(y,angle);
m_orientation.setXAxis(x);
m_orientation.setZAxis(z);
}
void FrustumCamera::zAxisRotation(float angle)
{
Vector3<float> x = m_orientation.getXAxis();
Vector3<float> y = m_orientation.getYAxis();
Vector3<float> z = m_orientation.getZAxis();
x.rotateAroundAxis(z,angle);
z = m_orientation.getYAxis();
y.rotateAroundAxis(z,angle);
m_orientation.setXAxis(x);
m_orientation.setYAxis(y);
}
template <class Type>
void Vector3<Type>::rotateAroundAxis(Vector3<Type> axis, const float angle)
{
float radians = static_cast<Type>(angle * degToRad);
Type sinAngle = static_cast<Type>(sin(radians));
Type cosAngle = 0.0;
if (angle == 90 || angle == -90)
cosAngle = 0.0;
else
cosAngle = cos(radians);
normalise(axis); // normalise the axis
Type oneMinusCos = 1 - cosAngle; // (1 - cos(theta))
// construct the rotation matrix
Type tempMatrix[3][3];
tempMatrix[0][0] = (axis.x * axis.x) * oneMinusCos + cosAngle;
tempMatrix[0][1] = (axis.x * axis.y) * oneMinusCos + axis.z * sinAngle;
tempMatrix[0][2] = (axis.x * axis.z) * oneMinusCos - axis.y * sinAngle;
tempMatrix[1][0] = (axis.x * axis.y) * oneMinusCos - axis.z * sinAngle;
tempMatrix[1][1] = (axis.y * axis.y) * oneMinusCos + cosAngle;
tempMatrix[1][2] = (axis.y * axis.z) * oneMinusCos + axis.x * sinAngle;
tempMatrix[2][0] = (axis.x * axis.z) * oneMinusCos + axis.y * sinAngle;
tempMatrix[2][1] = (axis.y * axis.z) * oneMinusCos - axis.x * sinAngle;
tempMatrix[2][2] = (axis.z * axis.z) * oneMinusCos + cosAngle;
Vector3<Type> temp(*this);
Vector3<Type> result;
result.x = (temp.x * tempMatrix[0][0]) + (temp.y * tempMatrix[1][0]) + (temp.z * tempMatrix[2][0]);
result.y = (temp.x * tempMatrix[0][1]) + (temp.y * tempMatrix[1][1]) + (temp.z * tempMatrix[2][1]);
result.z = (temp.x * tempMatrix[0][2]) + (temp.y * tempMatrix[1][2]) + (temp.z * tempMatrix[2][2]);
*this = result;
}
void OpenGLRenderer::startDraw(unsigned long mask)
{
//sortBuffer(); // sort draw queue
clearBuffers(mask); // clear buffers
loadIdentity();
glTranslatef(-1*m_frustumCamera->getViewMatrix().getTranslationAxis().x,-1*m_frustumCamera->getViewMatrix().getTranslationAxis().y,-1*m_frustumCamera->getViewMatrix().getTranslationAxis().z);
glMultMatrixf(m_frustumCamera->getViewMatrix().getMatrix());
glTranslatef(m_frustumCamera->getViewMatrix().getTranslationAxis().x,m_frustumCamera->getViewMatrix().getTranslationAxis().y,m_frustumCamera->getViewMatrix().getTranslationAxis().z);// load identity
//
// push matrix stack
matrixStackPush();
}
You might be experiencing Gimbal Lock; this can happen if you pitch all the way up or down so your look vector becomes parallel with your up vector, In which case a yaw will be the same as a roll.
This can be a downside of constructing rotations piecemeal via Euler angles. You may want to look into quaternions. (Note that you cant rotate with Euler angles; they are just a representation for rotation (you need to convert it to matrix or quats), but the way you are tackling it is very much an 'Euler angle' way of thinking about it)
The strength of matrix multiplication is that any sequence of multiple rotations can be represented (and concatenated) as a single rotation matrix. What you need to be doing is something like this:
void Transformable::yaw(float angle)
{
float4x4 rot; // temp rotation matrix
float3 translate(&_transform._41); // save our translation
float3 up(&_transform._21); // y axis
// build the rotation matrix for rotation around y
MatrixRotationAxis(&rot, &up, angle);
// multiply our transform by the rotation matrix
// note that order of multiplication matters and depends on
// if your matrices are column-major or row-major
MatrixMultiply(&_transform, &_transform, &rot);
// write back our original translation
memcpy(&_transform._41, &translate, sizeof(float3));
// might want to reorthogonalise every now and then
// to make sure basis vectors are orthonormal
// or you will probably get matrix creep after a few operations
}
instead of trying to rotate one basis vector at a time. In this case _transform would be a 4x4 homogenous matrix representing the transformation matrix. (rotation and translation). The topleft 3x3 submatrix is simply the basis vectors of the orientation space.