00001
00002 #include <ros/ros.h>
00003 #include <opencv2/core/core.hpp>
00004
00005 #include <blort/Recognizer3D/Recognizer3D.h>
00006 #include <blort/Recognizer3D/SDraw.hh>
00007 #include <blort/Recognizer3D/cvgeometry.h>
00008 #include <blort/TomGine/tgModelLoader.h>
00009 #include <blort/TomGine/tgCollission.h>
00010 #include <blort/blort/pal_util.h>
00011
00012 using namespace blortRecognizer;
00013
00014 CameraParameter::CameraParameter(const sensor_msgs::CameraInfo &cam_info)
00015 {
00016 w = cam_info.width;
00017 h = cam_info.height;
00018 fx =cam_info.K.at(0);
00019 cx = cam_info.K.at(2);
00020 fy = cam_info.K.at(4);
00021 cy = cam_info.K.at(5);
00022 if (!cam_info.D.empty())
00023 {
00024 k1 = cam_info.D.at(0);
00025 k2 = cam_info.D.at(1);
00026 k3 = cam_info.D.at(4);
00027 p1 = cam_info.D.at(2);
00028 p2 = cam_info.D.at(3);
00029 }
00030 else
00031 {
00032 k1 = 0.0;
00033 k2 = 0.0;
00034 k3 = 0.0;
00035 p1 = 0.0;
00036 p2 = 0.0;
00037 }
00038 }
00039
00040 void Recognizer3D::Convert(P::PoseCv& p1, TomGine::tgPose& p2){
00041
00042 mat3 cR;
00043 vec3 ct;
00044
00045 cR[0] = cvmGet(p1.R,0,0); cR[3] = cvmGet(p1.R,0,1); cR[6] = cvmGet(p1.R,0,2);
00046 cR[1] = cvmGet(p1.R,1,0); cR[4] = cvmGet(p1.R,1,1); cR[7] = cvmGet(p1.R,1,2);
00047 cR[2] = cvmGet(p1.R,2,0); cR[5] = cvmGet(p1.R,2,1); cR[8] = cvmGet(p1.R,2,2);
00048
00049 ct.x = cvmGet(p1.t,0,0);
00050 ct.y = cvmGet(p1.t,1,0);
00051 ct.z = cvmGet(p1.t,2,0);
00052
00053 p2.SetPose(cR,ct);
00054 }
00055
00056 Recognizer3D::Recognizer3D(const blortRecognizer::CameraParameter& camParam,
00057 std::string config_root, bool display, bool training)
00058 {
00059 do_undistort = true;
00060 this->config_root = config_root;
00061 pIntrinsicDistort = cvCreateMat(3,3, CV_64FC1);
00062 pDistortion = cvCreateMat(1,4, CV_64FC1);
00063 C = cvCreateMat(3,3, CV_32F);
00064
00065 m_cp = camParam;
00066
00067 cvmSet(pIntrinsicDistort, 0, 0, camParam.fx);
00068 cvmSet(pIntrinsicDistort, 0, 1, 0.);
00069 cvmSet(pIntrinsicDistort, 0, 2, camParam.cx);
00070 cvmSet(pIntrinsicDistort, 1, 0, 0.);
00071 cvmSet(pIntrinsicDistort, 1, 1, camParam.fy);
00072 cvmSet(pIntrinsicDistort, 1, 2, camParam.cy);
00073 cvmSet(pIntrinsicDistort, 2, 0, 0.);
00074 cvmSet(pIntrinsicDistort, 2, 1, 0.);
00075 cvmSet(pIntrinsicDistort, 2, 2, 1.);
00076
00077 cvmSet(pDistortion, 0, 0, camParam.k1);
00078 cvmSet(pDistortion, 0, 1, camParam.k2);
00079 cvmSet(pDistortion, 0, 2, camParam.k3);
00080 cvmSet(pDistortion, 0, 3, 0.0);
00081
00082
00083 cvmSet(C, 0, 0, camParam.fx);
00084 cvmSet(C, 0, 1, 0.);
00085 cvmSet(C, 0, 2, camParam.cx);
00086 cvmSet(C, 1, 0, 0.);
00087 cvmSet(C, 1, 1, camParam.fy);
00088 cvmSet(C, 1, 2, camParam.cy);
00089 cvmSet(C, 2, 0, 0.);
00090 cvmSet(C, 2, 1, 0.);
00091 cvmSet(C, 2, 2, 1.);
00092
00093 m_detect.SetCameraParameter(C);
00094
00095 pMapX = cvCreateMat (camParam.h, camParam.w, CV_32FC1 );
00096 pMapY = cvCreateMat (camParam.h, camParam.w, CV_32FC1 );
00097 cvInitUndistortMapExact(pIntrinsicDistort, pDistortion, pMapX, pMapY);
00098
00099 m_gauss_kernel = 5;
00100 m_gauss_dev = 1.5;
00101
00102 m_display = display;
00103
00104 m_model_loaded = false;
00105 if(training)
00106 {
00107 initTrainingModel();
00108 }
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120 }
00121
00122 Recognizer3D::~Recognizer3D()
00123 {
00124 cvReleaseMat(&pIntrinsicDistort);
00125 cvReleaseMat(&pDistortion);
00126 cvReleaseMat(&C);
00127 cvReleaseMat(&pMapX);
00128 cvReleaseMat(&pMapY);
00129 }
00130
00131 void Recognizer3D::setCameraParameter(const blortRecognizer::CameraParameter& camParam)
00132 {
00133 m_cp = camParam;
00134
00135 cvmSet(pIntrinsicDistort, 0, 0, camParam.fx);
00136 cvmSet(pIntrinsicDistort, 0, 1, 0.);
00137 cvmSet(pIntrinsicDistort, 0, 2, camParam.cx);
00138 cvmSet(pIntrinsicDistort, 1, 0, 0.);
00139 cvmSet(pIntrinsicDistort, 1, 1, camParam.fy);
00140 cvmSet(pIntrinsicDistort, 1, 2, camParam.cy);
00141 cvmSet(pIntrinsicDistort, 2, 0, 0.);
00142 cvmSet(pIntrinsicDistort, 2, 1, 0.);
00143 cvmSet(pIntrinsicDistort, 2, 2, 1.);
00144
00145 cvmSet(pDistortion, 0, 0, camParam.k1);
00146 cvmSet(pDistortion, 0, 1, camParam.k2);
00147 cvmSet(pDistortion, 0, 2, camParam.k3);
00148 cvmSet(pDistortion, 0, 3, 0.0);
00149
00150
00151 cvmSet(C, 0, 0, camParam.fx);
00152 cvmSet(C, 0, 1, 0.);
00153 cvmSet(C, 0, 2, camParam.cx);
00154 cvmSet(C, 1, 0, 0.);
00155 cvmSet(C, 1, 1, camParam.fy);
00156 cvmSet(C, 1, 2, camParam.cy);
00157 cvmSet(C, 2, 0, 0.);
00158 cvmSet(C, 2, 1, 0.);
00159 cvmSet(C, 2, 2, 1.);
00160
00161 m_detect.SetCameraParameter(C);
00162
00163 pMapX = cvCreateMat (camParam.h, camParam.w, CV_32FC1 );
00164 pMapY = cvCreateMat (camParam.h, camParam.w, CV_32FC1 );
00165 cvInitUndistortMapExact(pIntrinsicDistort, pDistortion, pMapX, pMapY);
00166 }
00167
00168 bool Recognizer3D::recognize(IplImage* tFrame, std::map<std::string, boost::shared_ptr<TomGine::tgPose> > & poses,
00169 std::map<std::string, double> & confs)
00170 {
00171
00172 std::map<std::string, bool> select;
00173 return recognize(tFrame, poses, confs, select);
00174 }
00175
00176 bool Recognizer3D::recognize(IplImage* tFrame, std::map<std::string, boost::shared_ptr<TomGine::tgPose> > & poses,
00177 std::map<std::string, double> & confs, const std::map<std::string, bool> & select)
00178 {
00179 P::PoseCv cvPose;
00180 bool detected = false;
00181
00182 if(!m_model_loaded || m_sift_models[0]->codebook.Empty())
00183 {
00184 ROS_DEBUG("[Recognizer3D::recognize] Warning: no sift points in codebook of object (did you load the model before?) -- Possible GPU library error.");
00185 return false;
00186 }
00187
00188 IplImage* tImg = 0;
00189 IplImage* grey = 0;
00190
00191 tImg = cvCreateImage( cvGetSize ( tFrame ), 8, 3 );
00192 grey = cvCreateImage( cvGetSize ( tFrame ), 8, 1 );
00193
00194
00195 double ticksBefore = cv::getTickCount();
00196 if(do_undistort)
00197 {
00198 cvRemap(tFrame, tImg, pMapX, pMapY);
00199 }else{
00200 cvCopy(tFrame, tImg);
00201 }
00202 ROS_INFO("Recognizer3D::recognize: undistort time: %.01f ms", 1000*(cv::getTickCount() - ticksBefore)/cv::getTickFrequency());
00203
00204
00205
00206 cvConvertImage(tImg, grey);
00207
00208
00209 ticksBefore = cv::getTickCount();
00210 sift.Operate(grey, m_image_keys);
00211 ROS_INFO("Recognizer3D::recognize: extract sift time: %.01f ms", 1000*(cv::getTickCount() - ticksBefore)/cv::getTickFrequency());
00212
00213 m_detect.SetDebugImage(tImg);
00214
00215 if(m_display)
00216 {
00217 sift.Draw(tImg, m_image_keys);
00218 }
00219
00220
00221
00222 ticksBefore = cv::getTickCount();
00223 for(size_t i = 0; i < m_sift_models.size(); ++i)
00224 {
00225 bool detectResult = false;
00226
00227 if((select.count(m_sift_models[i]->file_name) && select.at(m_sift_models[i]->file_name)) || select.empty())
00228 {
00229 ROS_ERROR_STREAM("Recognizer3D::recognize: filename: " << m_sift_models[i]->file_name);
00230 detectResult = m_detect.Detect(m_image_keys, *m_sift_models[i]);
00231
00232 if(detectResult)
00233 {
00234 if(m_sift_models[i]->conf > 0.03)
00235 {
00236 confs[m_sift_models[i]->file_name] = m_sift_models[i]->conf;
00237 if(m_display)
00238 {
00239
00240 P::SDraw::DrawPoly(tImg, m_sift_models[i]->contour.v, CV_RGB(0,255,0),2);
00241 m_detect.DrawInlier(tImg, CV_RGB(0,255,0));
00242 }
00243 CopyPoseCv(m_sift_models[i]->pose, cvPose);
00244 Convert(cvPose, *poses[m_sift_models[i]->file_name]);
00245 ROS_DEBUG("[Recognizer3D::recognize] object found (conf: %f)\n", m_sift_models[i]->conf);
00246 detected = true;
00247 }
00248 else
00249 {
00250 if(m_display)
00251
00252 P::SDraw::DrawPoly(tImg, m_sift_models[i]->contour.v, CV_RGB(128,0,128),2);
00253
00254 ROS_DEBUG("[Recognizer3D::recognize] No object (conf: %f)\n", m_sift_models[i]->conf);
00255 }
00256 }
00257 else
00258 {
00259 confs[m_sift_models[i]->file_name] = m_sift_models[i]->conf;
00260
00261 if(m_display)
00262 P::SDraw::DrawPoly(tImg, m_sift_models[i]->contour.v, CV_RGB(128,0,128),2);
00263
00264 ROS_DEBUG("[Recognizer3D::recognize] No object (conf: %f)\n", m_sift_models[i]->conf);
00265 }
00266 }
00267 }
00268 ROS_ERROR("Recognizer3D::recognize: %.01f ms\n", 1000*(cv::getTickCount() - ticksBefore)/cv::getTickFrequency());
00269
00270 if(m_display)
00271 {
00272 display_image = cv::Mat(tImg, true);
00273 }
00274
00275 cvReleaseImage(&tImg);
00276 cvReleaseImage(&grey);
00277
00278
00279
00280
00281 return detected;
00282 }
00283
00284 bool Recognizer3D::learnSifts(IplImage* tFrame, const TomGine::tgModel& m1, const TomGine::tgPose& pose)
00285 {
00286 P::Array<P::KeypointDescriptor*> m_tmp_keys;
00287
00288 mat3 R, Rt;
00289 vec3 t;
00290 TomGine::tgModel m2 = m1;
00291 m_lastsiftexlist.clear();
00292
00293
00294 pose.GetPose(R,t);
00295 Rt = R.transpose();
00296 for(unsigned int i=0; i<m2.m_vertices.size(); i++)
00297 {
00298 m2.m_vertices[i].pos = (R * m2.m_vertices[i].pos) + t;
00299 m2.m_vertices[i].normal = R * m2.m_vertices[i].normal;
00300 }
00301
00302 IplImage* tImg = 0;
00303 IplImage* grey = 0;
00304 float dcpfx = 1/m_cp.fx;
00305 float dcpfy = 1/m_cp.fy;
00306
00307 tImg = cvCreateImage ( cvGetSize ( tFrame ), 8, 3 );
00308 grey = cvCreateImage ( cvGetSize ( tFrame ), 8, 1 );
00309
00310
00311 cvRemap(tFrame, tImg, pMapX, pMapY );
00312
00313
00314 cvConvertImage(tImg, grey);
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325 sift.Operate(grey, m_image_keys);
00326
00327 for(unsigned int i=0; i<m_image_keys.Size(); i++)
00328 {
00329 vec3 point, normal;
00330 std::vector<vec3> pl;
00331 std::vector<vec3> nl;
00332 std::vector<double> zl;
00333 float u,v,x,y;
00334
00335 u = (float)m_image_keys[i]->p.x;
00336 v = (float)m_image_keys[i]->p.y;
00337 x = (u-m_cp.cx) * dcpfx;
00338 y = (v-m_cp.cy) * dcpfy;
00339
00340
00341 TomGine::tgRay ray;
00342 ray.start = vec3(0.0f,0.0f,0.0f);
00343 ray.dir = vec3(x,y,1.0f);
00344 ray.dir.normalize();
00345
00346 if( TomGine::tgCollission::IntersectRayModel(pl, nl, zl, ray, m2)
00347 && !pl.empty()
00348 && !zl.empty())
00349 {
00350
00351 unsigned int idx_min = 0;
00352 float z_min = zl[0];
00353 for(unsigned int idx=0; idx<zl.size(); idx++){
00354 if(zl[idx] < z_min){
00355 idx_min = idx;
00356 z_min = zl[idx];
00357 }
00358 }
00359
00360 if(z_min > 0.0f){
00361
00362 point = (Rt * (pl[idx_min] - t));
00363 normal = (Rt * nl[idx_min]);
00364 vec3 r = (Rt * ray.dir) * zl[idx_min];
00365
00366 Siftex s;
00367 s.pos = point;
00368 s.normal = normal;
00369 s.viewray = r;
00370
00371 normal.normalize();
00372 r.normalize();
00373
00374 if( (r * normal) < -0.1f)
00375 {
00376
00377 m_siftexlist.push_back(s);
00378 m_lastsiftexlist.push_back(s);
00379 m_image_keys[i]->SetPos(point.x, point.y, point.z);
00380 m_tmp_keys.PushBack(m_image_keys[i]);
00381 }
00382 }
00383 }
00384
00385 }
00386
00387 if(m_tmp_keys.Size() > 0)
00388 {
00389 m_sift_model_learner.AddToModel(m_tmp_keys, *m_sift_models[0]);
00390 ROS_INFO("[Recognizer3D::learnSifts] added %d sifts to model\n", m_tmp_keys.Size());
00391 m_model_loaded = true;
00392 }
00393
00394 if(m_display){
00395 display_image = cv::Mat(tImg, true);
00396 }
00397
00398 cvReleaseImage(&tImg);
00399 cvReleaseImage(&grey);
00400
00401 return true;
00402 }
00403
00404 bool Recognizer3D::loadModelFromFile(const std::string sift_file)
00405 {
00406 ROS_INFO("[Recognizer3D::loadModelFromFile] loading sift model from '%s'\n", sift_file.c_str());
00407 m_sift_models.push_back(boost::shared_ptr<P::Object3D>(new P::Object3D()));
00408 m_model_loaded = m_sift_model_learner.LoadModel(blort_ros::addRoot(sift_file, config_root), *m_sift_models.back());
00409
00410
00411 return true;
00412 }
00413
00414 void Recognizer3D::initTrainingModel()
00415 {
00416 ROS_INFO("[Recognizer3D::initTrainingModel() creating an empty model for training");
00417 m_sift_models.push_back(boost::shared_ptr<P::Object3D>(new P::Object3D()));
00418 }
00419
00420 bool Recognizer3D::saveModelToFile(const char* sift_file)
00421 {
00422 ROS_INFO("[Recognizer3D::saveModelToFile] saving sift model to '%s'\n", sift_file);
00423 m_sift_model_learner.SaveModel(blort_ros::addRoot(sift_file, config_root).c_str(), *m_sift_models[0]);
00424 return true;
00425 }
00426
00427 void Recognizer3D::setNNThreshold(double nn_threshold)
00428 {
00429 m_detect.setNNThreshold(nn_threshold);
00430 }
00431
00432 void Recognizer3D::setRansacNPointsToMatch(unsigned int n)
00433 {
00434 m_detect.setNPointsToMatch(n);
00435 }