It looks like btTransform::getOpenGLMatrix is changing orientation.
The sign of x is flipped, but I don't find anything about this in the docs for getOpenGLMatrix.
auto t = btTransform( btQuaternion(0.7,0,0,0.7), bt(0,0,0));
glm::mat4 ogl_t;
t.getOpenGLMatrix(glm::value_ptr(ogl_t));
glm::vec3 scale;
glm::quat orientation;
glm::vec3 translation;
glm::vec3 skew;
glm::vec4 perspective;
glm::decompose(ogl_t,scale,orientation,translation,skew,perspective); // returns true
assert(fabs(orientation.x - 0.7 ) < 0.02); // fails because x is -0.7
It can be the same orientation.
Let's look at Quaternion's definition [x y z w]: -
// RotationAngle is in radians
x = RotationAxis.x * sin(RotationAngle / 2)
y = RotationAxis.y * sin(RotationAngle / 2)
z = RotationAxis.z * sin(RotationAngle / 2)
w = cos(RotationAngle / 2)
Example : [x=0.7,y=0,z=0,w=0.7] is the same as [x=-0.7,y=0,z=0,w=-0.7]
Thus, your experimental result is not an evidence that orientation is changed.
Read more :
http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-17-quaternions/ (long article)
https://math.stackexchange.com/questions/765363/can-different-quaternions-represent-the-same-orientation (proof)
Related
I'm trying to better understand the calibrateCamera and SolvePnP functions in OpenCV, specifically the rotation vectors returned by these functions which I believe is an axis-angle rotation vector (NOT as I had thought initially the yaw,pitch,roll angles). I would like to know the rotation around the x,y and z axis of my checkerboard image. The OpenCV functions return a rotation vector in the form rot = [a,b,c]
Using this answer
as a guide I calculate the angle theta with theta = sqrt(a^2,b^2,c^2) and the rotation axis v = [a/theta, b/theta, c/theta];
Then I take these values and use the Axis-Angle To Euler conversion on euclideanspace.com. shown here:
heading = atan2(y * sin(angle)- x * z * (1 - cos(angle)) , 1 - (y^2 + z^2 ) * (1 - cos(angle)))
attitude = asin(x * y * (1 - cos(angle)) + z * sin(angle))
bank = atan2(x * sin(angle)-y * z * (1 - cos(angle)) , 1 - (x^2 + z^2) * (1 - cos(angle)))
I'm using one of the example OpenCV checkerboard images (Left01.jpg), shown below (note the frame axes in the upper left corner with red = x, green = y, blue = z
Using this image I get a rotation vector from calibrateCamera of [0.166,0.294,0.014]
Running these values through the calculations discussed and converting to degrees I get:
heading = 16.7 deg
attitude = 1.7 deg
bank = 9.3 deg
I believe these correspond to yaw,pitch,roll? The 16.7 degree heading seems high looking at the image, but it's hard to tell. Does this make sense? What would be the correct way to figure out the euler angles (angles around each axis) given the OpenCV rotation vector? Snippets of my code are shown below.
double RMSError = calibrateCamera(
objectPointsArray,
imagePointsArray,
img.size(),
intrinsics,
distortion,
rotation,
translation,
CALIB_ZERO_TANGENT_DIST |
CALIB_FIX_K3 | CALIB_FIX_K4 | CALIB_FIX_K5 |
CALIB_FIX_ASPECT_RATIO);
Mat rvec = rotation.at(0);
//try and get the rotation angles here
//https://stackoverflow.com/questions/12933284/rodrigues-into-eulerangles-and-vice-versa
float theta = sqrt(pow(rvec.at<double>(0),2) + pow(rvec.at<double>(1),2) + pow(rvec.at<double>(2),2));
Mat axis = (Mat_<double>(1, 3) << rvec.at<double>(0) / theta, rvec.at<double>(1) / theta, rvec.at<double>(2) / theta);
float x_ = axis.at<double>(0);
float y_ = axis.at<double>(1);
float z_ = axis.at<double>(2);
//this is yaw,pitch,roll respectively...maybe
float heading = atan2(y_ * sin(theta) - x_ * z_ * (1 - cos(theta)), 1 - (pow(y_,2) + pow(z_,2)) * (1 - static_cast<double>(cos(theta))));
float attitude = asin(x_ * y_ * (1 - cos(theta) + z_ * sin(theta)));
float bank = atan2(x_ * sin(theta) - y_ * z_ * (1 - cos(theta)), 1 - (pow(x_, 2) + pow(z_, 2)) * (1 - static_cast<double>(cos(theta))));
float headingDeg = heading * (180 / 3.14);
float attitudeDeg = attitude * (180 / 3.14);
float bankDeg = bank * (180 / 3.14);
I have a 3D scene in which in the imaginary sphere I position few objects, now I want to rotate them within device motion.
I use spherical coordinate system and calculate position in sphere like below:
x = ρ * sinϕ * cosθ
y = ρ * sinϕ * sinθ
z = ρ * cosϕ.
Also, I use angles (from 0 to 2_M_PI) for performing rotation horizontally (in z-x)
As result all works perfect until I want to use Quaternion from motion matrix.
I can extract values like pitch, yaw, roll
GLKQuaternion quat = GLKQuaternionMakeWithMatrix4(motionMatrix);
CGFloat adjRoll = atan2(2 * (quat.y * quat.w - quat.x * quat.z), 1 - 2 * quat.y * quat.y - 2 * quat.z * quat.z);
CGFloat adjPitch = atan2(2 * (quat.x * quat.w + quat.y * quat.z), 1 - 2 * quat.x * quat.x - 2 * quat.z * quat.z);
CGFloat adjYaw = asin(2 * quat.x * quat.y + 2 * quat.w * quat.z);
or try also
CMAttitude *currentAttitude = [MotionDataProvider sharedProvider].attitude; //from CoreMotion
CGFloat roll = currentAttitude.roll;
CGFloat pitch = currentAttitude.pitch;
CGFloat yaw = currentAttitude.yaw;
*the values that i got is different for this methods
The problem is that pitch, yaw, roll is not applicable in this format to my scheme.
How can I convert pitch, yaw, roll or quaternion or motionMatrix to required angles in x-z for my rotation model? Am I on correct way of things doing, or I missed some milestone point?
How to get rotation around y axis from received rotation matrix/quaternion from CoreMotion, converting current z and x to 0, so displayed object can be rotated only around y axis?
I use iOS, by the way, but guess this is not important here.
I am trying to implement oilfy filter using openCV, and I came across this code.
The code uses gd2 lib. But as my application already uses OpenCV for image processing, its is not recommended to use another lib.
I couldn't understand what the following code does
for (y = 0; y < maskHeight; y++)
{
for (x = 0; x < maskWidth; x++)
{
index = y * maskWidth + x;
rTable[index] = (double) gdImageRed(imageptr,gdImageGetPixel(imageptr,w + x - maskWidth / 2, h + y - maskHeight / 2));
gTable[index] = (double) gdImageGreen(imageptr,gdImageGetPixel(imageptr,w + x - maskWidth / 2, h + y - maskHeight / 2));
bTable[index] = (double) gdImageBlue(imageptr,gdImageGetPixel(imageptr,w + x - maskWidth / 2, h + y - maskHeight / 2));
}
}
Can someone, help me with understanding the oilfy algorithm or tell me how to convert the code into OpenCV?
Any openCV code for oilfy effect will be of much help.
Check out this link -
https://libgd.github.io/manuals/2.2.3/files/gd-c.html#gdImageGetPixel
gdImageGetPixel returns the color value at that pixel in integer format.This contains combination of RGB. The pixel is indicated with gdImagePtr object followed by x and y co-ordinates of the pixel in the image.
gdImageRed returns the red color intensity value in that color, similarly gdImageBlue and gdImageGreen.
I need to rotate a single point expressed in cartesian XYZ coordinates about the Z axis. The following 2 attempts are not working properly - I believe the first one is more correct..
I tried to rotate the points using the math on this website: http://farside.ph.utexas.edu/teaching/336k/newton/node153.html
// Rotate the XYZ coordinate for the pin image
if ( [satName isEqualToString:#"pin"] ) {
double x = xyz.x;
double y = xyz.y;
double radians = self.timeSinceOpenGlStarted;
x = x * cos(radians) + y * sin(radians);
y = -x * sin(radians) + y * cos(radians);
xyz.x = x;
xyz.z = y;
}
I also tried this function by extracting the points after GLKMatrix4Rotate:
// This function rotates XYZ a certain of radians about the origin and gives back XYZ
- (GLKVector4)rotateXYZCoordinates:(XYZ*)coords {
// Get the current modelview matrix
GLKMatrix4 currMat = self.effect.transform.modelviewMatrix;
// Print the coords before
NSLog(#"Before: %f %f %f",coords->x,coords->y,coords->z);
NSLog(#"Rotation Before: %f %f %f",currMat.m00,currMat.m10,currMat.m20);
// Construct the rows in the new matrix
float d = sqrt( pow(currMat.m00,2) + pow(currMat.m10,2) + pow(currMat.m20,2) );
GLKVector4 columnToInsert0 = GLKVector4Make(d, 0, 0, coords->x);
GLKVector4 columnToInsert1 = GLKVector4Make(0, d, 0, coords->y);
GLKVector4 columnToInsert2 = GLKVector4Make(0, 0, d, coords->z);
GLKVector4 columnToInsert3 = GLKVector4Make(0, 0, 0, 1);
// Build the new Matrix
GLKMatrix4 noTranslationInfo = GLKMatrix4SetRow(currMat, 0, columnToInsert0);
noTranslationInfo = GLKMatrix4SetRow(noTranslationInfo, 1, columnToInsert1);
noTranslationInfo = GLKMatrix4SetRow(noTranslationInfo, 2, columnToInsert2);
noTranslationInfo = GLKMatrix4SetRow(noTranslationInfo, 3, columnToInsert3);
// Throw the world translation coordinates in the matrix
noTranslationInfo.m30 = ( noTranslationInfo.m30 );
noTranslationInfo.m31 = ( noTranslationInfo.m31 );
noTranslationInfo.m32 = ( noTranslationInfo.m32 );
// Now rotate the matrix so many angles
noTranslationInfo = GLKMatrix4Rotate(noTranslationInfo, self.timeSinceOpenGlStarted, 0, 0, 1);
// Latch the output
coords->x = noTranslationInfo.m30;
coords->y = noTranslationInfo.m31;
coords->z = noTranslationInfo.m32;
// Print the coords After
NSLog(#"AFter: %f %f %f",coords->x,coords->y,coords->z);
NSLog(#"Rotation After: %f %f %f",noTranslationInfo.m00,noTranslationInfo.m10,noTranslationInfo.m20);
}
I have a globe spinning along the Z axis and a billboarded sprite specified at a specific spherical coordinate ( representing a lat/lon location ) and need the ability to have the point rotate along with the earth or not.
What am I doing wrong? How do I calculate a new X and Y coordinate ( Z is constant ) to rotate an XYZ point around the Z axis when I know the number of radians I want to rotate? Thanks!
UPDATE: Now I've tried this:
// Rotate the XYZ coordinate for the pin image
/* http://www.blitzbasic.com/Community/posts.php?topic=70536
;rotate offset around Z axis
newx# = x# * Cos#(zr#) - y# * Sin#(zr#)
newy# = x# * Sin#(zr#) + y# * Cos#(zr#)
x# = newx#
y# = newy#
;rotate offset around X axis
newy# = y# * Cos#(xr#) - z# * Sin#(xr#)
newz# = y# * Sin#(xr#) + z# * Cos#(xr#)
y# = newy#
z# = newz#
;rotate offset around Y axis
newx# = z# * Sin#(-yr#) + x# * Cos#(-yr#)
newz# = z# * Cos#(-yr#) - x# * Sin#(-yr#)
x# = newx#
z# = newz#
*/
if ( [satName isEqualToString:#"pin"] && self.shouldAnimate == YES ) {
//NSLog(#"ONE %f %f %f %f",xyz.x,xyz.y,xyz.z,sqrt(pow(xyz.x, 2)+pow(xyz.y,2)+pow(xyz.z,2)));
double x = xyz.x;
double y = xyz.y;
double z = xyz.z;
NSLog(#"%f",self.timeSinceOpenGlStarted); // Values like: 32521.473728
double zr = self.timeSinceOpenGlStarted;
double yr = 0.0f;
double xr = 0.0f;
// Rotations must be in this order: Z then X then Y
// Rotate around Z
x = x * cos(zr) - y * sin(zr);
y = x * sin(zr) + y * cos(zr);
// Rotate around X
y = y * cos(xr) - z * sin(xr);
z = y * sin(xr) + z * cos(xr);
// Rotate around Y
x = z * sin(-yr) + x * cos(-yr);
z = z * cos(-yr) + x * sin(-yr);
// Get the coordinates back
xyz.x = x;
xyz.y = y;
xyz.z = z;
//NSLog(#"TWO %f %f %f %f",xyz.x,xyz.y,xyz.z,sqrt(pow(xyz.x, 2)+pow(xyz.y,2)+pow(xyz.z,2)));
}
The problem is that my image dances around the lat/lon it should be at - it almost does a figure 8.
I either don't understand what you want to achieve or these methods of yours are a bit strange. If you need to rotate a single point around centre (0,0,0) around Z axis (on the XY plane) then you should use something like this:
float x, y;
float currentAngle;
float radius = sqrt(x*x + y*y);
x = radius*cos(currentAngle);
y = radius*sin(currentAngle);
To make it even easier you can simply use radius (which should be constant in your case) and the angle in radians. In this case you only need last 2 lines of this snippet.
It looks like you are adding each frame to your angle. You can compute an "delta angle" just the angle to rotate from the previous frame, or to use the angle as it is now but apply the rotation to the initial orientation, not to last frame's result.
I have a project that uses a tilemap. I have a separate tilemap for low-res (29x29 Tilesize) and high-res (58x58). I have these methods to calculate tileCoord to position and back again.
- (CGPoint)tileCoordForPosition:(CGPoint)position {
int x = position.x / _tileMap.tileSize.width;
int y = ((_tileMap.mapSize.height * _tileMap.tileSize.height) - position.y) / _tileMap.tileSize.height;
return ccp(x, y);
}
- (CGPoint)positionForTileCoord:(CGPoint)tileCoord {
int x = (tileCoord.x * _tileMap.tileSize.width) + _tileMap.tileSize.width/2;
int y = (_tileMap.mapSize.height * _tileMap.tileSize.height) - (tileCoord.y * _tileMap.tileSize.height) - _tileMap.tileSize.height/2;
return ccp(x, y);
}
I got this from RayWenderLich and I do honeslty not understand how it works, and why it has to be so complicated. But this doesn't work when I use retina tilemaps, only on 480x320. Can someone clever come up with a way to make this work for HD? Does not have to work on low-res either, I do not plan on supporting sub-iOS 7.
I want the output to be in the low-res coordinate scale tho, as you might know, cocos2d does the resizing to HD for you. (By multiplying by two)
i think this will work
- (CGPoint)tileCoordForPosition:(CGPoint)position {
int x = position.x/29;
int y = ((11*29)-position.y) / 29;
return ccp(x, y);
}
- (CGPoint)positionForTileCoord:(CGPoint)tileCoord {
double x = tileCoord.x * 29 + 14.5;
double y = (11*29) - (tileCoord.y * 29) - 14.5;
return ccp(x, y);
}
Here you're trying to compute your map X coordinate:
int x = position.x / _tileMap.tileSize.width;
The problem here is that (as of v0.99.5-rc0, cocos2d generally uses points for positions, but CCTMXTiledMap always uses pixels for tileSize. On a low-res device, 1 point = 1 pixel, but on a Retina device, 1 point = 2 pixels. Thus on a Retina device, you need to multiply by 2.
You can use the CC_CONTENT_SCALE_FACTOR() macro to fix this:
int x = CC_CONTENT_SCALE_FACTOR() * position.x / _tileMap.tileSize.width;
Here you're trying to compute yoru map Y coordinate:
int y = ((_tileMap.mapSize.height * _tileMap.tileSize.height) - position.y) / _tileMap.tileSize.height;
The extra math here is trying to account for the difference between Cocos2D's normal coordinate system and your map's flipped coordinate system. In standard Cartesian coordinates, the origin is at the lower left and Y coordinates increase as you move up. In a flipped coordinate system, the origin is at the upper left and Y coordinates increase as you move down. Thus you must subtract your position's Y coordinate from the height of the map (in scene units, which are points) to flip it to map coordinates.
The problem again is that _tileMap.tileSize is in pixels, not points. You can again fix that by using CC_CONTENT_SCALE_FACTOR():
CGFloat tileHeight = _tileMap.tileSize.height / CC_CONTENT_SCALE_FACTOR();
int y = ((_tileMap.mapSize.height * tileHeight) - position.y) / tileHeight;