Surf3DDetector.cpp
Go to the documentation of this file.
00001 
00033 #include "Surf3DDetector.h"
00034 #include "ObjectModel.h"
00035 #include "ObjectDetectorMethod.h"
00036 #include "re_msgs/DetectedObject.h"
00037 
00038 #include "DUtils.h"
00039 #include "DUtilsCV.h"
00040 #include "DVision.h"
00041 #include "epnp.h"
00042 
00043 #include <vector>
00044 #include <iomanip>
00045 #include <iostream>
00046 
00047 typedef DUtils::Random Random;
00048 typedef DVision::SurfSet SurfSet;
00049 typedef DVision::PMVS::PLYFile::PLYPoint PLYPoint;
00050 using namespace std;
00051 
00052 // ---------------------------------------------------------------------------
00053 
00056 
00057 #ifdef IF_DEBUG_MODE
00058   #undef IF_DEBUG_MODE
00059 #endif
00060 
00061 #if VOLUME_DEBUG_ENABLED
00062   #define IF_DEBUG_MODE(X) if(debugMode()){ X; }
00063   #define IF_DEBUG_OR_VISUALIZATION_MODE(X) \
00064     if(debugMode() || visualizationMode()){ X; }
00065 #else
00066   #define IF_DEBUG_MODE(X) if(0){}
00067   // this definition enables the use of "else"
00068   #define IF_DEBUG_OR_VISUALIZATION_MODE(X) \
00069     if(visualizationMode()){ X; }
00070 #endif
00071 
00072 // ---------------------------------------------------------------------------
00073 
00074 void Surf3DDetector::detect(ObjectDetectorMethod::DetectionData &data,
00075   ObjectModel &model,
00076   re_msgs::DetectedObject &detection)
00077 {
00078   #if VOLUME_DEBUG_ENABLED
00079     // sets prefix of debug files
00080     {
00081       stringstream ss;
00082       ss << m_debug_dir << "/"
00083         << setw(2) << setfill('0') << m_detect_counter << "_3d_";
00084       m_debug_prefix = ss.str();
00085     }
00086     std::string original_debug_prefix = m_debug_prefix;
00087     m_detect_counter++;
00088   #endif
00089 
00090   if(!data.surfdata.provided)
00091   {
00092     // calculate surfs
00093     data.surfdata.surfset.Extract(data.img, 400, false);
00094     data.surfdata.provided = true;
00095   }
00096 
00097   IF_DEBUG_OR_VISUALIZATION_MODE
00098   (
00099     cv::Mat img = data.img.clone();
00100     DUtilsCV::Drawing::drawKeyPoints(img, data.surfdata.surfset.keys);
00101 
00102     IF_DEBUG_MODE
00103     (
00104       std::string filename = m_debug_prefix + "0_scene_keypoints.png";
00105       cv::imwrite(filename, img);
00106     )
00107 
00108     if(visualizationMode()) visualize(img, "Searching...");
00109   )
00110 
00111   const SurfSet& scene_surfset = data.surfdata.surfset;
00112   vector<int> face_indices;
00113   vector<vector<int> > model_indices;
00114   vector<vector<int> > scene_indices;
00115   vector<vector<float> > distances;
00116   model.detectFaces(scene_surfset, face_indices, model_indices,
00117     scene_indices, distances, 1, 1, 0.8);  //MOD
00118 
00119 
00120   bool found = false;
00121   if(!face_indices.empty())
00122   {
00123     for(unsigned int i = 0; i < face_indices.size(); ++i)
00124     {
00125       int idx = face_indices[i];
00126 
00127       IF_DEBUG_MODE
00128       (
00129         stringstream ss;
00130         ss << original_debug_prefix << "1_it_" << i << "_face_" << idx << "_";
00131         m_debug_prefix = ss.str();
00132         std::string filename = m_debug_prefix + "0_match.png";
00133 
00134         DUtilsCV::Drawing::saveCorrespondenceImage(filename, data.img,
00135           model.Faces[idx].image, scene_surfset.keys,
00136           model.Faces[idx].surf.keys,
00137           scene_indices[i], model_indices[i]);
00138       )
00139 
00140       found = detectWithPnP(scene_surfset, model, model.Faces[idx],
00141         model_indices[i], scene_indices[i], distances[i],
00142         data, 3., false, detection);
00143 
00144       if(found) break;
00145     }
00146   }
00147 
00148   if(!found)
00149   {
00150     detection.points2d.clear();
00151     detection.points3d.clear();
00152     detection.points3d_model.clear();
00153   }
00154 
00155 }
00156 
00157 // ---------------------------------------------------------------------------
00158 
00159 bool Surf3DDetector::detectWithPnP(const SurfSet &scene_surfset,
00160     ObjectModel &model,
00161     ObjectModel::Face &face, const std::vector<int> &model_indices,
00162     const std::vector<int> &scene_indices, const std::vector<float> &distances,
00163     const ObjectDetectorMethod::DetectionData &data,
00164     const double maxReprojectionError, bool doReChecking,
00165     re_msgs::DetectedObject &detection)
00166 {
00167   const int MIN_POINTS = 7;
00168 
00169   if((int)model_indices.size() < MIN_POINTS) return false;
00170 
00171   const int N = 5; // model points
00172   int max_its = 200; //500 max iterations
00173 
00174   const cv::Mat &A = data.params.camera.GetIntrinsicParameters();
00175   const cv::Mat &K = data.params.camera.GetDistortionParameters();
00176 
00177   //assert(A.type() == CV_32F);
00178 
00179   epnp PnP;
00180   PnP.set_maximum_number_of_correspondences(N);
00181   PnP.set_internal_parameters(
00182     A.at<float>(0, 2), A.at<float>(1, 2), A.at<float>(0, 0), A.at<float>(1, 1));
00183 
00184   // stores the correspondence points of the model in a matrix
00185   cv::Mat oP_Nx3 = cv::Mat(model_indices.size(), 3, CV_32F);
00186 
00187   // stores the correspondence points of the scene in a matrix
00188   cv::Mat scene_2d_points_Nx2(model_indices.size(), 2, CV_32F);
00189 
00190   // stores the projected points of the model
00191   vector<cv::Point2f> vec_object_2d_points;
00192   vec_object_2d_points.reserve(model_indices.size());
00193 
00194   // for operating with projected points
00195   cv::Mat projected_distance_xy_Nx2(model_indices.size(), 2, CV_32F);
00196   cv::Mat projected_sq_distance_Nx1(model_indices.size(), 1, CV_32F);
00197   cv::Mat inlier_status_Nx1(model_indices.size(), 1, CV_8UC1);
00198   static vector<unsigned int> i_inliers;
00199   i_inliers.reserve(model_indices.size());
00200 
00201   float *p_oP = oP_Nx3.ptr<float>();
00202   float *p_scene_2d = scene_2d_points_Nx2.ptr<float>();
00203   for(unsigned int i = 0; i < model_indices.size();
00204     ++i, p_oP += 3, p_scene_2d += 2)
00205   {
00206     const PLYPoint &p3d = face.plypoints[ model_indices[i] ];
00207     const cv::KeyPoint kp = scene_surfset.keys[ scene_indices[i] ];
00208 
00209     p_oP[0] = p3d.x;
00210     p_oP[1] = p3d.y;
00211     p_oP[2] = p3d.z;
00212 
00213     p_scene_2d[0] = kp.pt.x;
00214     p_scene_2d[1] = kp.pt.y;
00215   }
00216 
00217   // stores the candidate transformation to the object
00218   double cRo_r[3][3], cto_r[3];
00219   cv::Mat cRo(3, 3, CV_64F, cRo_r);
00220   cv::Mat cto(3, 1, CV_64F, cto_r);
00221 
00222   Random::SeedRandOnce();
00223  // Random::SeedRandOnce(100);
00224 
00225   vector<unsigned int> best_i_inliers;
00226   int current_it = 0;
00227 
00228   while(current_it < max_its)
00229   {
00230     PnP.reset_correspondences();
00231 
00232     int i_corr[N];
00233     int n = 0;
00234     while(n < N)
00235     {
00236       i_corr[n] = Random::RandomInt(0, model_indices.size()-1);
00237       if( (n == 0) || (find(i_corr, i_corr + n, i_corr[n]) == i_corr + n) )
00238       {
00239         int face_idx = model_indices[i_corr[n]];
00240         int scene_idx = scene_indices[i_corr[n]];
00241 
00242         const PLYPoint &p3d = face.plypoints[face_idx];
00243         const cv::KeyPoint kp = scene_surfset.keys[scene_idx];
00244 
00245         PnP.add_correspondence(p3d.x, p3d.y, p3d.z, kp.pt.x, kp.pt.y);
00246 
00247         ++n;
00248       }
00249     }
00250 
00251     PnP.compute_pose(cRo_r, cto_r);
00252 
00253     cv::projectPoints(oP_Nx3, cRo, cto, A, K, vec_object_2d_points);
00254 
00255     cv::Mat object_2d_points_Nx2(oP_Nx3.rows, 2, CV_32F,
00256       &vec_object_2d_points[0]);
00257 
00258     // calculate distance from scene point to reprojected point
00259     projected_distance_xy_Nx2 = object_2d_points_Nx2 - scene_2d_points_Nx2;
00260     cv::pow(projected_distance_xy_Nx2, 2, projected_distance_xy_Nx2);
00261 
00262     cv::reduce(projected_distance_xy_Nx2, projected_sq_distance_Nx1, 1,
00263       CV_REDUCE_SUM);
00264     // projected_sq_distance is now a col with the square distances of
00265     // each projected point to its matched scene point
00266 
00267     // get the inliers
00268     cv::compare(projected_sq_distance_Nx1,
00269       maxReprojectionError * maxReprojectionError, inlier_status_Nx1,
00270       cv::CMP_LE);
00271     // inlier_status is 0 at outlier positions and 255 at inlier positions
00272 
00273     const unsigned char *p_inliers = inlier_status_Nx1.ptr<unsigned char>();
00274     i_inliers.resize(0);
00275     for(unsigned int i = 0; i < model_indices.size(); ++i)
00276     {
00277       if(p_inliers[i] != 0)
00278       {
00279         i_inliers.push_back(i);
00280       }
00281     }
00282 
00283     // check if we have enough inliers
00284     if(i_inliers.size() > best_i_inliers.size() &&
00285       (int)i_inliers.size() >= MIN_POINTS)
00286     {
00287       best_i_inliers = i_inliers;
00288 
00289       // update iterations
00290       double w = (double)best_i_inliers.size() / (double)model_indices.size();
00291       const float p = 0.95;
00292       int its = (int)( log(1 - p) / log(1 - pow(w, N)) );
00293       if(its < max_its) max_its = its;
00294     }
00295 
00296     current_it++;
00297   }
00298   if((int)best_i_inliers.size() >= MIN_POINTS)
00299   {
00300     // we have found the object
00301 
00302     // get the indices of the inliers
00303     vector<int> inlier_model_indices, inlier_scene_indices;
00304     vector<float> inlier_distances;
00305     {
00306       const unsigned int M = best_i_inliers.size();
00307 
00308       inlier_model_indices.resize(M);
00309       inlier_scene_indices.resize(M);
00310       inlier_distances.resize(M);
00311 
00312       for(unsigned int i = 0; i < M; ++i)
00313       {
00314         inlier_model_indices[i] = model_indices[ best_i_inliers[i] ];
00315         inlier_scene_indices[i] = scene_indices[ best_i_inliers[i] ];
00316         inlier_distances[i] = distances[ best_i_inliers[i] ];
00317       }
00318     }
00319 
00320     cv::Mat _image_to_show;
00321     IF_DEBUG_OR_VISUALIZATION_MODE
00322     (
00323       DUtilsCV::Drawing::drawCorrespondences(_image_to_show, data.img,
00324         face.image, scene_surfset.keys, face.surf.keys,
00325         inlier_scene_indices, inlier_model_indices);
00326 
00327       IF_DEBUG_MODE
00328       (
00329         std::string filename;
00330         if(doReChecking)
00331           filename = m_debug_prefix + "1_0_first_pnp.png";
00332         else
00333           filename = m_debug_prefix + "1_1_re_pnp.png";
00334 
00335         cv::imwrite(filename, _image_to_show);
00336       )
00337     )
00338 
00339     if(doReChecking)
00340     {
00341       bool found = detectWithPnP(scene_surfset, model, face,
00342         inlier_model_indices, inlier_scene_indices, inlier_distances,
00343         data, 1, false, detection);
00344 
00345       if(found) return true;
00346     }
00347 
00348     if(visualizationMode())
00349     {
00350       visualize(_image_to_show);
00351     }
00352 
00353     // get the final transformation now
00354     cv::Mat cTo;
00355 
00356     calculatePose(face, inlier_model_indices, scene_surfset,
00357       inlier_scene_indices, data.params.camera, cTo);
00358 
00359     if(cTo.at<double>(2,3) / cTo.at<double>(3,3) <= 0)
00360     {
00361       ROS_DEBUG("cTo behind the camera, rejecting...");
00362     }
00363     else
00364     {
00365       // obj is in front of the camera
00366 
00367       IF_DEBUG_OR_VISUALIZATION_MODE
00368       (
00369         cv::Mat img;
00370         if(img.channels() == 3)
00371           img = data.img.clone();
00372         else
00373           cv::cvtColor(data.img, img, CV_GRAY2BGR);
00374 
00375         model.getVisualizationModel().draw(img, cTo,
00376           data.params.camera.GetIntrinsicParameters());
00377 
00378         IF_DEBUG_MODE
00379         (
00380           string filename = m_debug_prefix + "2_pose.png";
00381           cv::imwrite(filename, img);
00382         )
00383         IF_DEBUG_MODE
00384         (
00385           //MARTA-------------------------------------------------------------------------------
00386           cv::Mat img = _image_to_show;
00387           cv::cvtColor(data.img, img, CV_GRAY2BGR);
00388           string filename = m_debug_prefix + "marta.png";
00389           cv::imwrite(filename, img);
00390           //-----------------------------------------------------------------------------------------
00391         )
00392 
00393         if(visualizationMode()) visualize(img,
00394           model.Name + " located!", true);
00395       )
00396 
00397       // convert pose form camera orientation to robot orientation
00398       cv::Mat cTo_robot;
00399       changeOrientation(cTo, cTo_robot);
00400 
00401       // fill DetectedObject data
00402       convertPose(cTo_robot, detection.pose);
00403      // convert3DPoints(face, inlier_model_indices, cTo_robot, detection.points3d);
00404 
00405       // get all the points from the model and their corresponding ones
00406       // in the scene
00407 
00408       convert3DPoints(face, inlier_model_indices, cTo_robot, detection.points3d);
00409       project2DPoints(face, cTo, data.params.camera,inlier_model_indices, detection.points2d);
00410       get3DModelPoints(face, inlier_model_indices, detection.points3d_model);
00411       getPointsOctave(face,inlier_model_indices,detection.octave);
00412       //convert3DPoints(face, cTo_robot, detection.points3d);
00413       //project2DPoints(face, cTo, data.params.camera, detection.points2d);
00414       //get3DModelPoints(face, detection.points3d_model);
00415       //getPointsOctave(face,detection.octave);
00416 
00417       IF_DEBUG_MODE
00418       (
00419         //DUtilsCV::IO::print(cTo_robot, "--> rTo");
00420         fstream f((m_debug_prefix + "rTo.txt").c_str(), ios::out);
00421         DUtilsCV::IO::print(cTo_robot, "rTo", f);
00422         f.close();
00423         //debug::saveTscene(cTo_robot, detection.points3d,
00424         //  m_debug_prefix + "scene.wrl");
00425 
00426         std::fstream file((m_debug_prefix + "data_marta.txt").c_str(), std::fstream::out);
00427         file<<"keypointsScene=[";
00428         for(unsigned int i = 0; i < inlier_scene_indices.size(); ++i)
00429         {
00430           const cv::KeyPoint &kp = scene_surfset.keys[  inlier_scene_indices[i] ];
00431           float s = ((9.0f/1.2f) * kp.size/10.0f) / 3.0f;
00432           float o = kp.angle * 3.14159265 / 360.f;
00433           file<<s<<" "<<o<<" "<<kp.pt.x<<" "<<kp.pt.y<<" "<<endl;
00434         }
00435         file<<"];\n";
00436 
00437         file<<"points3dM=[\n";
00438         for(unsigned int i = 0; i < inlier_model_indices.size(); ++i)
00439         {
00440           const PLYPoint &p3d = face.plypoints[ inlier_model_indices[i] ];
00441           file<<p3d.x << " " <<p3d.y <<" "<<p3d.z<<endl;
00442         }
00443         file<<"];\n";
00444         file<<"T2=[" <<cTo<<"];\n";
00445 
00446         file.close();
00447       )
00448 
00449       /*
00450       detection.points2d.resize(0);
00451       detection.points2d.reserve(inliers);
00452       detection.points3d_model.resize(0);
00453       detection.points3d_model.reserve(inliers);
00454 
00455       for(unsigned int i = 0; i < inlier_model_indices.size(); ++i)
00456       {
00457         const PLYPoint &ply = face.plypoints[inlier_model_indices[i]];
00458         const cv::KeyPoint &scene_kp = scene_surfset.keys[inlier_scene_indices[i]];
00459 
00460         re_msgs::Pixel p2d;
00461         p2d.x = cvRound(scene_kp.pt.x);
00462         p2d.y = cvRound(scene_kp.pt.y);
00463         detection.points2d.push_back(p2d);
00464 
00465         geometry_msgs::Point p3d;
00466         p3d.x = ply.x;
00467         p3d.y = ply.y;
00468         p3d.z = ply.z;
00469         detection.points3d_model.push_back(p3d);
00470       }
00471       */
00472 
00473       return true;
00474     } // if cTo is ok
00475 
00476   } // if(best_i_inliers.size() >= MIN_POINTS)
00477 
00478   return false;
00479 }
00480 
00481 // ---------------------------------------------------------------------------
00482 
00483 


re_vision
Author(s): Dorian Galvez-Lopez
autogenerated on Sun Jan 5 2014 11:33:06