00001
00018 #include <iostream>
00019
00020 #include <stdlib.h>
00021 #include <time.h>
00022 #include <vector>
00023 #include <MathHelpers/Resectionsolver/resectionsolver.h>
00024 #include <iostream>
00025 #include <unistd.h>
00026 #include <QObject>
00027 #include <math.h>
00028 #include <Transformation/transformationfile_manager_XML.h>
00029 #include <Transformation/transformationfile_manager_data.h>
00030 #include <Transformation/transformation_data.h>
00031 #ifndef Q_MOC_RUN
00032 #include <Eigen/Dense>
00033 #include <ros/ros.h>
00034 #include <ros/init.h>
00035 #include <boost/shared_ptr.hpp>
00036 #include <boost/algorithm/string.hpp>
00037 #endif
00038 #include <CameraUtils/marker_manager.h>
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051 using namespace std;
00052 string workspacePath;
00053
00054 bool test_averageframe(string filename)
00055 {
00056 std::ifstream input(filename);
00057 std::string line;
00058 unsigned int lineNumber = 1;
00059 std::vector<Eigen::Quaterniond> rotationVector;
00060 std::vector<Eigen::Vector3d> translationVector;
00061 while(std::getline( input, line ))
00062 {
00063 std::vector<std::string> strs;
00064 boost::split(strs, line, boost::is_any_of(";"));
00065 if (strs.size() == 7)
00066 {
00067 std::vector<double> numericValues;
00068 bool success = true;
00069 for (unsigned int i = 0; i < strs.size(); i++)
00070 {
00071 try
00072 {
00073 std::string temp = strs.at(i);
00074 boost::algorithm::trim(temp);
00075 numericValues.push_back(boost::lexical_cast<double>(temp));
00076 }
00077 catch (boost::bad_lexical_cast const&)
00078 {
00079 ROS_ERROR_STREAM("Line " << lineNumber << ": " <<strs.at(i) << " is not a number.");
00080 success = false;
00081 break;
00082 }
00083 }
00084 if (success)
00085 {
00086 Eigen::Quaterniond rotation(numericValues.at(3),numericValues.at(0),numericValues.at(1),numericValues.at(2));
00087 Eigen::Vector3d translation(numericValues.at(4),numericValues.at(5),numericValues.at(6));
00088 rotationVector.push_back(rotation);
00089 translationVector.push_back(translation);
00090 }
00091 }
00092 else
00093 {
00094 ROS_ERROR_STREAM("Line " << lineNumber << ": Expected 7 items, got " << strs.size());
00095 }
00096 lineNumber ++;
00097 }
00098 if (rotationVector.size() > 0)
00099 {
00100 Eigen::Vector3d averageTranslation = translationVector.at(0);
00101 Eigen::Quaterniond averageRotation = rotationVector.at(0);
00102
00103 for (unsigned int i = 1; i < rotationVector.size(); i++)
00104 {
00105 Eigen::Quaterniond tempRotation = rotationVector.at(i);
00106 Eigen::Vector3d tempTranslation = translationVector.at(i);
00107 averageTranslation = averageTranslation + tempTranslation;
00108 averageRotation = averageRotation.slerp((double)i/(i+1.0), tempRotation);
00109 }
00110 averageTranslation = averageTranslation * 1.0/(double)rotationVector.size();
00111 ROS_INFO_STREAM("Position X=" << averageTranslation(0) << " Y=" << averageTranslation(1) << " Z=" << averageTranslation(2));
00112 ROS_INFO_STREAM("Rotation w=" << averageRotation.w() << " x=" << averageRotation.x() << " y=" << averageRotation.y() << " z=" << averageRotation.z());
00113 }
00114 return true;
00115 }
00116
00117 bool test_markerDetection()
00118 {
00119 bool success = false;
00120 Marker_Manager markerManager(4.0, 3.0);
00121
00122
00123
00124 return success;
00125 }
00126
00127 bool test_serialisation(Abstract_TransformationFile_Manager * manager)
00128 {
00129 double pan, tilt;
00130 bool success = false;
00131 unsigned int testCount = 3;
00132 Eigen::Matrix4d m1_array[testCount];
00133 double pan_array[testCount];
00134 double tilt_array[testCount];
00135 for (unsigned int k = 0; k < testCount; k++)
00136 {
00137 Eigen::Matrix4d m1, m2;
00138 pan = rand() % 1000;
00139 tilt = rand() & 1000;
00140 pan_array[k] = pan;
00141 tilt_array[k] = tilt;
00142 double roll = fmod((double)rand(),2.0*M_PI);
00143 double pitch = fmod((double)rand(),2.0*M_PI);
00144 double yaw = fmod((double)rand(),2.0*M_PI);
00145 ROS_INFO_STREAM("Roll: " << roll << " pitch: " << pitch << " yaw: " << yaw);
00146 Eigen::Affine3d tr1 = Eigen::AngleAxisd(roll, Eigen::Vector3d::UnitZ()) * Eigen::AngleAxisd(pitch, Eigen::Vector3d::UnitX()) * Eigen::AngleAxisd(yaw, Eigen::Vector3d::UnitZ()) * Eigen::Translation3d(rand() % 1000, rand()% 1000, rand()% 1000);
00147 roll = fmod((double)rand(),2.0*M_PI);
00148 pitch = fmod((double)rand(),2.0*M_PI);
00149 yaw = fmod((double)rand(),2.0*M_PI);
00150 ROS_INFO_STREAM("Roll: " << roll << " pitch: " << pitch << " yaw: " << yaw);
00151 Eigen::Affine3d tr2 = Eigen::AngleAxisd(roll, Eigen::Vector3d::UnitZ()) * Eigen::AngleAxisd(pitch, Eigen::Vector3d::UnitX()) * Eigen::AngleAxisd(yaw, Eigen::Vector3d::UnitZ()) * Eigen::Translation3d(rand()% 1000, rand()% 1000, rand()% 1000);
00152 m1 = tr1.matrix();
00153 m2 = tr2.matrix();
00154 m1_array[k] = m1;
00155 manager->writeToFile(m1, m2, pan, tilt);
00156 }
00157
00158 std::vector<Transformation_Data> dataCollection = manager->readFromFile();
00159 if (dataCollection.size() >= testCount)
00160 {
00161 success = true;
00162 for (unsigned int k = 0; k < testCount; k++)
00163 {
00164 Eigen::Matrix4d m1;
00165 m1 = m1_array[k];
00166 pan = pan_array[k];
00167 tilt = tilt_array[k];
00168 Transformation_Data data = dataCollection[k];
00169 success &= (fabs(pan - data.pan) < 0.00001);
00170 if (success) {cout << "Pan correct" << endl;}
00171 else {ROS_ERROR_STREAM("Pan incorrect. Expected " << pan << ", got " << data.pan << " difference " << fabs(pan - data.pan));return success;}
00172 success &= (fabs(tilt - data.tilt) < 0.00001);
00173 if (success) {cout << "Tilt correct" << endl;}
00174 else {ROS_ERROR_STREAM("Tilt incorrect. Expected " << tilt << ", got " << data.tilt << " difference " << fabs(tilt - data.tilt));return success;}
00175 for (unsigned int i = 0; i < 4; i++)
00176 {
00177 for (unsigned int j = 0; j < 4; j++)
00178 {
00179 success &= (fabs(m1(i,j) - data.PTU_Frame(i,j)) < 0.001);
00180 if (!success) {ROS_ERROR_STREAM("PTU frame incorrect. Expected " << m1(i,j) << ", got " << data.PTU_Frame(i,j) << " difference " << fabs(m1(i,j) - data.PTU_Frame(i,j)));return success;}
00181 }
00182 }
00183 if (success) {cout << "PTU frame correct" << endl;}
00184 }
00185 }
00186 else
00187 {
00188 ROS_ERROR_STREAM("Not enough dataNodes found. Expected " << testCount << ", got " << dataCollection.size());
00189 }
00190 return success;
00191 }
00192
00193 bool test_resectionsolver()
00194 {
00195 Eigen::Vector3d top, temp;
00196 Eigen::Vector2d base1, base2, base3;
00197 double angle12, angle23, angle31;
00198 double side1, side2, side3, sideBase;
00199
00200 bool success;
00201
00202
00203 top[0] = (rand() % 1000 + 1) /100.0;
00204 top[1] = (rand() % 1000 + 1) /100.0;
00205 top[2] = (rand() % 1000 + 1) /500.0;
00206
00207 base1[0] = (rand() % 1000 + 1) /100.0;
00208 base1[1] = (rand() % 1000 + 1) /100.0;
00209 base2[0] = (rand() % 1000 + 1) /100.0;
00210 base2[1] = (rand() % 1000 + 1) /100.0;
00211 base3[0] = (rand() % 1000 + 1) /100.0;
00212
00213 base3[1] = (base1[0]*base3[0]-base2[0]*base3[0]-base1[0]*base2[0]+base2[0]*base2[0]-base1[1]*base2[1]+base2[1]*base2[1])/(base2[1]-base1[1]);
00214
00215
00216
00217 temp = Eigen::Vector3d(base1.x(), base1.y(), 0.0f);
00218 side1 = (top - temp).norm();
00219 temp = Eigen::Vector3d(base2.x(), base2.y(), 0.0f);
00220 side2 = (top - temp).norm();
00221 temp = Eigen::Vector3d(base3.x(), base3.y(), 0.0f);
00222 side3 = (top - temp).norm();
00223 sideBase = (base1 - base2).norm();
00224 angle12 = acos((-sideBase*sideBase + side1*side1 + side2*side2)/(2*side1*side2));
00225
00226 sideBase = (base2 - base3).norm();
00227 angle23 = acos((-sideBase*sideBase + side3*side3 + side2*side2)/(2*side3*side2));
00228
00229 sideBase = (base3 - base1).norm();
00230 angle31 = acos((-sideBase*sideBase + side1*side1 + side3*side3)/(2*side1*side3));
00231
00232 cout << "Testing vectors [" << base1.x() << ", " << base1.y() << "] ";
00233 cout << "[" << base2.x() << ", " << base2.y() << "] ";
00234 cout << "[" << base3.x() << ", " << base3.y() << "]" << endl;
00235 cout << "with top-point [" << top.x() << ", " << top.y() << ", " << top.z() << "]" << endl;
00236 cout << "Distances " << side1 << ", " << side2 << ", " << side3 << "" << endl;
00237 cout << "Angles " << angle12 << ", " << angle23 << ", " << angle31 << "" << endl;
00238
00239
00240 boost::shared_ptr<Calibration_Object> calibrationObject(new Calibration_Object());
00241 calibrationObject->top_angle_ab = angle12;
00242 calibrationObject->top_angle_bc = angle23;
00243 calibrationObject->top_angle_ca = angle31;
00244 calibrationObject->side_a = (base1 - base2).norm();
00245 calibrationObject->side_b = (base2 - base3).norm();
00246 calibrationObject->side_c = (base1 - base3).norm();
00247
00248 boost::shared_ptr<FeasibilityChecker> feasibilityChecker(new FeasibilityChecker(calibrationObject, Eigen::Vector3d(0.0,0.0,1.0), 0.15));
00249 ResectionSolver solver(calibrationObject, feasibilityChecker);
00250 solver.solve(base1, base2, base3);
00251 cout << "Results:" << endl;
00252 success = false;
00253 if (solver.solutions_a.size() == 0) {cout << "No solutions found." << endl;}
00254 for (unsigned int i = 0; i < solver.solutions_a.size(); i++)
00255 {
00256 if (abs(solver.solutions_b[i] - side1) <= 0.0001f && abs(solver.solutions_c[i] - side2) <= 0.0001f && abs(solver.solutions_a[i] - side3) <= 0.0001f)
00257 {
00258
00259 cout << "[" << solver.solutions_b[i] << ", " << solver.solutions_c[i] << ", " << solver.solutions_a[i]<< "]" << endl;
00260 success = true;
00261 }
00262 else
00263 {
00264 cout << "[" << solver.solutions_b[i] << ", " << solver.solutions_c[i] << ", " << solver.solutions_a[i] << "]" << endl;
00265
00266 }
00267 }
00268 if (success) {
00269 cout << "Distance test successful" << endl;
00270 success = false;
00271 for (unsigned int i = 0; i < solver.solutions.size(); i++)
00272 {
00273 if (abs(solver.solutions[i].x() - top.x()) <= 0.0001f && abs(solver.solutions[i].y() - top.y()) <= 0.0001f && abs(solver.solutions[i].z() - top.z()) <= 0.0001f)
00274 {
00275
00276 cout << "[" << solver.solutions[i][0] << ", " <<solver.solutions[i][1] << ", " << solver.solutions[i][2]<< "]" << endl;
00277 success = true;
00278 }
00279 else
00280 {
00281 cout << "[" << solver.solutions[i][0] << ", " <<solver.solutions[i][1] << ", " << solver.solutions[i][2]<< "]" << endl;
00282
00283 }
00284 }
00285 if (success) {cout << "Top-point test successful!" << endl;}
00286 }
00287
00288 return success;
00289 }
00290
00291 bool is_numeric(string string_)
00292 {
00293 int sizeOfString = string_.size();
00294 int iteration = 0;
00295 bool isNumeric = true;
00296
00297 while(iteration < sizeOfString)
00298 {
00299 if(!isdigit(string_[iteration]))
00300 {
00301 isNumeric = false;
00302 break;
00303 }
00304
00305 iteration++;
00306 }
00307 return isNumeric;
00308 }
00309
00310 bool start_test(string args)
00311 {
00312 bool testFound = false;
00313 if (args.substr(0,9) == "resection")
00314 {
00315 string numerArg = args.substr(9);
00316 numerArg.erase(std::remove(numerArg.begin(), numerArg.end(), ' '), numerArg.end());
00317 srand (time(NULL));
00318 if (is_numeric(numerArg) && numerArg.size() > 0) {
00319 unsigned int numbers = atoi(numerArg.c_str());
00320 unsigned int success = 0;
00321 for (unsigned int i = 0; i < numbers; i++)
00322 {
00323 if (test_resectionsolver()) {success++;}
00324 clock_t time_end;
00325 time_end = clock() + 20 * CLOCKS_PER_SEC/1000;
00326 while (clock() < time_end)
00327 {
00328 }
00329 cout << endl;
00330 }
00331 cout << success << "/" << numbers << " were successful." << endl;
00332 }
00333 else
00334 {
00335 int inp;
00336 do
00337 {
00338 test_resectionsolver();
00339 inp = cin.get();
00340 }
00341 while (inp != 32);
00342 }
00343 testFound = true;
00344 }
00345 else if (args.substr(0,13) == "serialization")
00346 {
00347 string numerArg = args.substr(13);
00348 numerArg.erase(std::remove(numerArg.begin(), numerArg.end(), ' '), numerArg.end());
00349 srand (time(NULL));
00350 if (numerArg.size() > 0) {
00351 std::string writer = numerArg.c_str();
00352 Abstract_TransformationFile_Manager * manager;
00353 if (writer == "XML")
00354 {
00355 manager = new TransformationFile_Manager_XML(workspacePath + "/test.xml");
00356 }
00357 else
00358 {
00359 manager = new TransformationFile_Manager_Data(workspacePath + "/test.data");
00360 }
00361 if (test_serialisation(manager))
00362 {
00363 ROS_INFO("Test was successful.");
00364 }
00365 else
00366 {
00367 ROS_INFO("Test failed.");
00368 }
00369 }
00370 testFound = true;
00371 }
00372 else if (args.substr(0,15) == "markerdetection")
00373 {
00374 test_markerDetection();
00375 testFound = true;
00376 }
00377 else if (args.substr(0,12) == "averageframe")
00378 {
00379 string filename = args.substr(13);
00380 filename.erase(std::remove(filename.begin(), filename.end(), ' '), filename.end());
00381 if (filename.size() > 0) test_averageframe(filename);
00382 testFound = true;
00383 }
00384 else
00385 {
00386 cout << "Testcase '" << args << "'not declared!" << endl;
00387
00388 }
00389 return testFound;
00390 }
00391
00392 int main(int argc, char *argv[])
00393 {
00394 string inp = "";
00395 char *arg[0];
00396 int x = 0;
00397 ros::init(x, arg, "calibrationTool_tests");
00398 ros::NodeHandle nh(ros::this_node::getName());
00399 string myWorkspace;
00400 nh.getParam("test_workspace", myWorkspace);
00401 ROS_INFO_STREAM("Using workspace " << myWorkspace);
00402 workspacePath = myWorkspace;
00403 std::cout << "Please choose a test to run: " << std::endl;
00404
00405 std::getline(std::cin, inp);
00406 string args_ = inp;
00407 while (args_ != "exit")
00408 {
00409 if (!start_test(args_))
00410 {
00411 std::cout << "Available tests are: " << std::endl;
00412 std::cout << " resection <count>" << std::endl;
00413 std::cout << " serialization XML|DATA" << std::endl;
00414 std::cout << " markerdetection" << std::endl;
00415 std::cout << " averageframe <filename>" << std::endl;
00416 }
00417 std::cout << "Please choose a test to run: " << std::endl;
00418 std::getline(std::cin, inp);
00419 args_ = inp;
00420 }
00421
00422 return 0;
00423 }