Reputation: 2610
Enviroment
Task at hand
Resolve the relative camera pose between Image A & Image B ( above ) expecting to result the Induced 25 degrees rotation on the Z axis
Implementation
Option A:
Option B:
Result
Neither of the above options is able to properly recover the relative camera pose (expected to be 25deg Rotation on the Z axis)
Any help would be appreciated.
Full Code
#define RAD2DEG(rad) (((rad) * 180)/M_PI)
#define DEG2RAD(deg) (((deg) * M_PI)/180)
#define FOV2FOCAL(pixelssensorsize, fov) ((pixelssensorsize) / (2 * tan((fov) / 2)))// http://books.google.co.il/books?id=bXzAlkODwa8C&pg=PA48&lpg=PA48&dq=expressing+focal+length+in+pixels&source=bl&ots=gY4972kxAC&sig=U1BUeNHhOHmYIrDrO0YDb1DrNng&hl=en&sa=X&ei=45dLU9u9DIyv7QbN2oGIDA&ved=0CGsQ6AEwCA#v=onepage&q=expressing%20focal%20length%20in%20pixels&f=false
// http://nghiaho.com/?page_id=846
void DecomposeRotation(IN const cv::Mat& R, OUT float& fX, OUT float& fY, OUT float& fZ) {// Taken from MatLab
fX = (float)atan2(R.at<double>(2, 1), R.at<double>(2, 2));
fY = (float)atan2(-R.at<double>(2, 0), sqrt(R.at<double>(2, 1)*R.at<double>(2, 1) + R.at<double>(2, 2)*R.at<double>(2, 2)));
fZ = (float)atan2(R.at<double>(1, 0), R.at<double>(0, 0));
}
int _tmain(int argc, _TCHAR* argv[])
{
// 25 deg rotation in the Z axis (800x600)
const cv::Point2f rotZ0[] = { { 109, 250 }, { 175, 266 }, { 204, 279 }, { 221, 253 }, { 324, 281 }, { 312, 319 }, { 328, 352 }, { 322, 365 } };
const cv::Point2f rotZ25[] = { { 510, 234 }, { 569, 622 }, { 593, 278 }, { 616, 257 }, { 716, 303 }, { 698, 340 }, { 707, 377 }, { 697, 390 } };
const cv::Point2f rotZminus15[] = { { 37, 260 }, { 106, 275 }, { 135, 286 }, { 152, 260 }, { 258, 284 }, { 248, 324 }, { 266, 356 }, { 260, 370 } };
const double dFOV = DEG2RAD(45);
const cv::Point2d res(800, 600);
const cv::Point2d pntPriciplePoint(res.x / 2, res.y / 2);
const cv::Point2d pntFocal(FOV2FOCAL(res.x, dFOV), FOV2FOCAL(res.y, dFOV));
//transfer the vector of points to the appropriate opencv matrix structures
const int numPoints = sizeof(rotZ0) / sizeof(rotZ0[0]);
std::vector<cv::Point2f> vecPnt1(numPoints);
std::vector<cv::Point2f> vecPnt2(numPoints);
for (int i = 0; i < numPoints; i++) {
vecPnt2[i] = rotZ0[i];
//vecPnt2[i] = rotZminus15[i];
vecPnt1[i] = rotZ25[i];
}
//// Normalize points
//for (int i = 0; i < numPoints; i++) {
// vecPnt1[i].x = (vecPnt1[i].x - pntPriciplePoint.x) / pntFocal.x;
// vecPnt1[i].y = (vecPnt1[i].y - pntPriciplePoint.y) / pntFocal.y;
// vecPnt2[i].x = (vecPnt2[i].x - pntPriciplePoint.x) / pntFocal.x;
// vecPnt2[i].y = (vecPnt2[i].y - pntPriciplePoint.y) / pntFocal.y;
//}
try {
// http://docs.opencv.org/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html
cv::Mat matK = cv::Mat::zeros(3, 3, CV_64F);
matK.at<double>(0, 0) = pntFocal.x;
matK.at<double>(1, 1) = pntFocal.y;
matK.at<double>(0, 2) = pntPriciplePoint.x;
matK.at<double>(1, 2) = pntPriciplePoint.y;
matK.at<double>(2, 2) = 1;
float x, y, z;
cv::Mat R1, R2, R3, R4;
cv::Mat t;
cv::Mat matE;
#if 1 // Option [A]
cv::Mat matF = cv::findFundamentalMat(vecPnt1, vecPnt2);
matE = matK.t() * matF * matK; // http://en.wikipedia.org/wiki/Essential_matrix
cv::Mat _tmp;
cv::Mat U;
cv::Mat Vt;
cv::SVD::compute(matE, _tmp, U, Vt);
cv::Matx33d W(0, -1, 0,
1, 0, 0,
0, 0, 1);
R1 = U*cv::Mat(W)*Vt; // See http://stackoverflow.com/questions/14150152/extract-translation-and-rotation-from-fundamental-matrix for details
R2 = U*cv::Mat(W)*Vt.t();
R3 = U*cv::Mat(W).t()*Vt;
R4 = U*cv::Mat(W).t()*Vt.t();
#else // Option [B]
matE = cv::findEssentialMat(vecPnt1, vecPnt2, pntFocal.x, pntPriciplePoint);// http://docs.opencv.org/trunk/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html
cv::decomposeEssentialMat(matE, R1, R2, t);
int iInliers = cv::recoverPose(matE, vecPnt1, vecPnt2, R4, t);// , pntFocal.x, pntPriciplePoint);
R3 = cv::Mat::zeros(3, 3, CV_64F);
#endif
DecomposeRotation(R1, x, y, z);
std::cout << "Euler Angles R1 (X,Y,Z): " << RAD2DEG(x) << ", " << RAD2DEG(y) << ", " << RAD2DEG(z) << std::endl;
DecomposeRotation(R2, x, y, z);
std::cout << " R2 (X,Y,Z): " << RAD2DEG(x) << ", " << RAD2DEG(y) << ", " << RAD2DEG(z) << std::endl;
DecomposeRotation(R3, x, y, z);
std::cout << " R3 (X,Y,Z): " << RAD2DEG(x) << ", " << RAD2DEG(y) << ", " << RAD2DEG(z) << std::endl;
DecomposeRotation(R4, x, y, z);
std::cout << " R4 (X,Y,Z): " << RAD2DEG(x) << ", " << RAD2DEG(y) << ", " << RAD2DEG(z) << std::endl;
//cv::Mat res = matFrom.t() * matF * matTo;// Results in a null vector ( as it should ) http://en.wikipedia.org/wiki/Fundamental_matrix_(computer_vision)
//res = matFrom.t() * matE * matTo;// Results in a null vector ( as it should )
}
catch (cv::Exception e) {
_ASSERT(FALSE);
}
return 0;
}
Execution results
Option A:
Euler Angles R1 (X,Y,Z): -26.2625, 8.70029, 163.643
R2 (X,Y,Z): 16.6929, -29.9901, -3.81642
R3 (X,Y,Z): 5.59033, -20.841, -19.9316
R4 (X,Y,Z): -5.76906, 7.25413, -179.086
Option B:
Euler Angles R1 (X,Y,Z): -13.8355, 3.0098, 171.451
R2 (X,Y,Z): 2.22802, -22.3479, -11.332
R3 (X,Y,Z): 0, -0, 0
R4 (X,Y,Z): 2.22802, -22.3479, -11.332
Upvotes: 1
Views: 4072
Reputation: 49
I think that none of your results is equal to 90 deg is because of coordinate system. The coordinate system in which you rotate the camera by 90 deg about z axis is defined by yourself. You can imagine a camera pose as a vector pointing to the scene, and the R matrix decomposed from essential matrix denotes the rotation of the vector. The result is in another coordinate system. You can check my hypothesis by checking if the two camera vectors have a vector angle of 90 deg.
Upvotes: 0
Reputation: 511
First of all, calibrate your camera instead of using predefined values. It would always make a big impact. The relative pose computed by 8-pt or 5-pt are subject to a lot of noise and by no means imply the final word. Having said that, it would be a good idea to reconstruct the points and then bundle adjust the entire scene. Refine your extrinsics and you should come up with a better pose.
Upvotes: 2