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