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
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
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
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);
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;
00172 int max_its = 200;
00173
00174 const cv::Mat &A = data.params.camera.GetIntrinsicParameters();
00175 const cv::Mat &K = data.params.camera.GetDistortionParameters();
00176
00177
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
00185 cv::Mat oP_Nx3 = cv::Mat(model_indices.size(), 3, CV_32F);
00186
00187
00188 cv::Mat scene_2d_points_Nx2(model_indices.size(), 2, CV_32F);
00189
00190
00191 vector<cv::Point2f> vec_object_2d_points;
00192 vec_object_2d_points.reserve(model_indices.size());
00193
00194
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
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
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
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
00265
00266
00267
00268 cv::compare(projected_sq_distance_Nx1,
00269 maxReprojectionError * maxReprojectionError, inlier_status_Nx1,
00270 cv::CMP_LE);
00271
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
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
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
00301
00302
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
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
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
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
00398 cv::Mat cTo_robot;
00399 changeOrientation(cTo, cTo_robot);
00400
00401
00402 convertPose(cTo_robot, detection.pose);
00403
00404
00405
00406
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
00413
00414
00415
00416
00417 IF_DEBUG_MODE
00418 (
00419
00420 fstream f((m_debug_prefix + "rTo.txt").c_str(), ios::out);
00421 DUtilsCV::IO::print(cTo_robot, "rTo", f);
00422 f.close();
00423
00424
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
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473 return true;
00474 }
00475
00476 }
00477
00478 return false;
00479 }
00480
00481
00482
00483