0

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.

enter image description here

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);
mash
  • 467
  • 7
  • 14
  • use your own pattern, own camera, and make it interactive. then you can build an intuition for what's going on. – Christoph Rackwitz Dec 18 '21 at 11:33
  • Yes I agree building that intuition will be helpful but I want to see if mathematically this is the correct way to do that conversion to Euler angles and if not, get pointed to a resource that might explain a better way. – mash Dec 20 '21 at 14:51
  • 1
    you'll benefit from working on the readability of the code. `theta = ...`, factor that out into a function, say `theta = magnitude(rvec);` same for the division, factor out and say `axis = normalize(rvec)` -- and mind the handedness. the link you gave only mentions that once, and they present the OpenGL frame which is left-handed. OpenCV is right-handed. – Christoph Rackwitz Dec 20 '21 at 16:07
  • Ended up using the method described [here](https://stackoverflow.com/a/55033361/1052396) – mash Feb 28 '22 at 19:04

0 Answers0