$search
00001 00013 #include <blort/Recognizer3D/ODetect3D.hh> 00014 #include <ros/console.h> 00015 #include <blort/TomGine/tgPose.h> 00016 #include <blort/blort/pal_util.h> 00017 #include <blort/Recognizer3D/Recognizer3D.h> 00018 00019 namespace P 00020 { 00021 00022 00023 /********************** ODetect3D ************************ 00024 * Constructor/Destructor 00025 */ 00026 ODetect3D::ODetect3D() 00027 : dbg(0) 00028 { 00029 nn_far_enough_threshold = (Def::DO_MIN_DESC_DIST*Def::DO_MIN_DESC_DIST)/100.0; 00030 n_points_to_match = 4; 00031 00032 cameraMatrix = cvCreateMat( 3, 3, CV_32F ); 00033 distCoeffs = cvCreateMat( 4, 1, CV_32F ); 00034 00035 matcherSize = 4096; 00036 matcher = new SiftMatchGPU(4096); 00037 matcher->VerifyContextGL(); 00038 00039 //we assume undistort images!!!! 00040 cvmSet( distCoeffs, 0, 0, 0. ); 00041 cvmSet( distCoeffs, 1, 0, 0. ); 00042 cvmSet( distCoeffs, 2, 0, 0. ); 00043 cvmSet( distCoeffs, 3, 0, 0. ); 00044 } 00045 00046 ODetect3D::~ODetect3D() 00047 { 00048 delete matcher; 00049 if (cameraMatrix!=0) cvReleaseMat(&cameraMatrix); 00050 if (distCoeffs!=0) cvReleaseMat(&distCoeffs); 00051 DeletePairs(matches); 00052 } 00053 00057 void ODetect3D::DeletePairs(Array<KeyClusterPair*> &matches) 00058 { 00059 for (unsigned i=0; i<matches.Size(); i++) 00060 delete matches[i]; 00061 matches.Clear(); 00062 } 00063 00064 00069 void ODetect3D::MatchKeypoints2(Array<KeypointDescriptor *> &keys, Array<CodebookEntry *> &cb, Array<KeyClusterPair* > &matches) 00070 { 00071 double ticksBefore = cv::getTickCount(); 00072 float dist, dist1, dist2; 00073 unsigned idx = 0; 00074 KeypointDescriptor *key; 00075 00076 for (unsigned i=0; i<keys.Size(); i++) 00077 { 00078 if (keys[i]->id != 0) 00079 { 00080 dist1 = dist2 = FLT_MAX; 00081 key = (KeypointDescriptor*)keys[i]; 00082 for (unsigned j=0; j<cb.Size(); j++) 00083 { 00084 if(key->GetType() == cb[j]->model->GetType()) 00085 { 00086 dist = key->DistSqr(key->GetVec(), cb[j]->model->GetVec(), key->GetSize()); 00087 if (dist < dist1) 00088 { 00089 dist2=dist1; 00090 dist1=dist; 00091 idx=j; 00092 } 00093 else 00094 { 00095 if (dist<dist2) dist2=dist; 00096 } 00097 } 00098 } 00099 if(double(dist1)/dist2 < nn_far_enough_threshold) 00100 matches.PushBack(new KeyClusterPair(key, cb[idx])); 00101 } 00102 } 00103 ROS_INFO("odetect3d::matchkeypoints() run: %f ms", 00104 1000*(cv::getTickCount() - ticksBefore)/cv::getTickFrequency()); 00105 } 00106 00111 void ODetect3D::MatchKeypoints(Array<KeypointDescriptor *> &keys, Array<CodebookEntry *> &cb, Array<KeyClusterPair* > &matches) 00112 { 00113 float dist, dist1; 00114 unsigned idx = 0; 00115 KeypointDescriptor *key; 00116 00117 for (unsigned i=0; i<keys.Size(); i++) 00118 { 00119 if (keys[i]->id != 0) //upppps HACK!!!! 00120 { 00121 dist1=FLT_MAX; 00122 key = (KeypointDescriptor*)keys[i]; 00123 for (unsigned j=0; j<cb.Size(); j++) 00124 { 00125 dist = key->Match(cb[j]->model); 00126 if (dist < dist1) 00127 { 00128 dist1=dist; 00129 idx=j; 00130 } 00131 } 00132 if (!IsEqual(dist1,FLT_MAX)) 00133 matches.PushBack(new KeyClusterPair(key, cb[idx], dist1)); 00134 } 00135 } 00136 } 00137 00141 void ODetect3D::MatchKeypointsGPU(Array<KeypointDescriptor *> &keys, Array<CodebookEntry *> &cb, Array<KeyClusterPair* > &matches) 00142 { 00143 if (keys.Size()<4) 00144 return; 00145 00146 int num; 00147 int (*match_buf)[2] = new int[(int)keys.Size()][2]; 00148 00149 if (matcherSize < (int)keys.Size()) matcher->SetMaxSift((int)keys.Size()); 00150 if (matcherSize < (int)cb.Size()) matcher->SetMaxSift((int)cb.Size()); 00151 00152 P::Array<float> desc1(cb.Size()*128); 00153 P::Array<float> desc2(keys.Size()*128); 00154 00155 for (unsigned i=0; i<cb.Size(); i++) 00156 CopyVec(cb[i]->model->vec, &(desc1[i*128]), cb[i]->model->GetSize()); 00157 for (unsigned i=0; i<keys.Size(); i++) 00158 CopyVec(keys[i]->vec, &(desc2[i*128]), keys[i]->GetSize()); 00159 00160 matcher->SetDescriptors(0, (int)cb.Size(), &desc1[0]); //codebook 00161 matcher->SetDescriptors(1, (int)keys.Size(), &desc2[0]); //keys 00162 00163 num = matcher->GetSiftMatch(keys.Size(), match_buf); 00164 00165 for (unsigned i=0; i<(unsigned)num; i++) 00166 matches.PushBack(new KeyClusterPair(keys[match_buf[i][1]], cb[match_buf[i][0]], 0)); 00167 00168 delete[] match_buf; 00169 } 00170 00171 00175 void ODetect3D::GetRandIdx(unsigned size, unsigned num, P::Array<unsigned> &idx) 00176 { 00177 unsigned temp; 00178 idx.Clear(); 00179 for (unsigned i=0; i<num; i++) 00180 { 00181 do{ 00182 temp = rand()%size; 00183 }while(idx.Contains(temp)); 00184 idx.PushBack(temp); 00185 } 00186 } 00187 00191 void ODetect3D::GetInlier(Array<KeyClusterPair*> &matches, PoseCv &pose, int &inl) 00192 { 00193 inl=0; 00194 Vector2 p; 00195 CodebookEntry *cbe; 00196 KeypointDescriptor *k; 00197 CvMat *pos = cvCreateMat( 3, 1, CV_32F ); 00198 00199 bool stop=false; 00200 for (unsigned i=0; i<matches.Size() && !stop; i++) 00201 { 00202 cbe = matches[i]->c; 00203 k = matches[i]->k; 00204 00205 for (unsigned j=0; j<cbe->Size(); j++) 00206 { 00207 cvMatMulAdd( pose.R, cbe->occurrences[j]->pos, pose.t, pos ); 00208 ProjectPoint2Image(pos->data.fl[0], pos->data.fl[1], pos->data.fl[2], cameraMatrix, p.x, p.y); 00209 00210 if (Distance(p,k->p) < Def::DO_RANSAC_INL_DIST) 00211 { 00212 if (pos->data.fl[2]<0) 00213 { 00214 inl=0; 00215 stop=true; 00216 } 00217 else 00218 { 00219 inl++; 00220 } 00221 break; 00222 } 00223 } 00224 } 00225 00226 cvReleaseMat(&pos); 00227 } 00228 00229 00233 void ODetect3D::FitModelRANSAC(Array<KeyClusterPair*> &matches, 00234 PoseCv &pose, unsigned &numInl) 00235 { 00236 if (matches.Size()<n_points_to_match) 00237 { 00238 ROS_WARN("matches.Size(): %d while n_points_to_match is %d", 00239 matches.Size(), n_points_to_match); 00240 return; 00241 } 00242 00243 double eps = n_points_to_match/(double)matches.Size(); 00244 int inl, inls = 0; 00245 Array<unsigned> idx, idx2; 00246 CvMat *modelPoints = cvCreateMat( n_points_to_match, 3, CV_32F ); 00247 CvMat *imgPoints = cvCreateMat( n_points_to_match, 2, CV_32F ); 00248 srand(time(NULL)); 00249 KeyClusterPair* kp; 00250 PoseCv tempPose; 00251 CvMat *rod = cvCreateMat(3,1,CV_32F); 00252 //double ticksBefore = cv::getTickCount(); 00253 int k; 00254 for(k=0; (pow(1. - pow(eps,n_points_to_match),k) >= Def::DO_RANSAC_ETA0 && 00255 k<Def::DO_MAX_RANSAC_TRIALS); ++k) 00256 { 00257 GetRandIdx(matches.Size(), n_points_to_match, idx); 00258 00259 for (unsigned i=0; i<n_points_to_match; i++) 00260 { 00261 kp = matches[idx[i]]; 00262 CvMat *pos = kp->c->occurrences[rand()%kp->c->Size()]->pos; 00263 cvmSet( modelPoints, i, 0, pos->data.fl[0] ); 00264 cvmSet( modelPoints, i, 1, pos->data.fl[1] ); 00265 cvmSet( modelPoints, i, 2, pos->data.fl[2] ); 00266 cvmSet( imgPoints, i, 0, kp->k->p.x); 00267 cvmSet( imgPoints, i, 1, kp->k->p.y); 00268 } 00269 //DEBUG 00270 // ROS_INFO("%f", pow(1. - pow(eps,n_points_to_match),k)); 00271 // ROS_INFO("fitmodelransac run: %f ms", 00272 // 1000*(cv::getTickCount() - ticksBefore)/cv::getTickFrequency()); 00273 00274 cvFindExtrinsicCameraParams2(modelPoints, imgPoints, 00275 cameraMatrix, distCoeffs, rod, tempPose.t); 00276 cvRodrigues2(rod,tempPose.R); 00277 GetInlier(matches,tempPose,inl); 00278 00279 if (inl > inls 00280 // && cvmGet(tempPose.R, 0, 2) < 0.4 && cvmGet(tempPose.R, 0, 2) > -0.4 && 00281 // cvmGet(tempPose.R, 1, 2) < -0.5 && cvmGet(tempPose.R, 1, 2) > -0.99 && 00282 // cvmGet(tempPose.R, 2, 2) < -0.2 && cvmGet(tempPose.R, 2, 2) > -0.8 00283 ) 00284 { 00285 //DEBUG 00286 // mat3 cR; 00287 // vec3 ct; 00288 // cR[0] = cvmGet(tempPose.R,0,0); cR[3] = cvmGet(tempPose.R,0,1); cR[6] = cvmGet(tempPose.R,0,2); 00289 // cR[1] = cvmGet(tempPose.R,1,0); cR[4] = cvmGet(tempPose.R,1,1); cR[7] = cvmGet(tempPose.R,1,2); 00290 // cR[2] = cvmGet(tempPose.R,2,0); cR[5] = cvmGet(tempPose.R,2,1); cR[8] = cvmGet(tempPose.R,2,2); 00291 // 00292 // ct.x = cvmGet(tempPose.t,0,0); 00293 // ct.y = cvmGet(tempPose.t,1,0); 00294 // ct.z = cvmGet(tempPose.t,2,0); 00295 // 00296 // ROS_INFO("ct and cR in inl > inls: [%f %f %f] \n [%f %f %f] \n [%f %f %f] \n [%f %f %f]", 00297 // ct.x, ct.y, ct.z, cR[0], cR[3], cR[6], cR[1], cR[4], cR[7], cR[2], cR[5], cR[8]); 00298 00299 inls = inl; 00300 eps = (double)inls / (double)matches.Size(); 00301 CopyPoseCv(tempPose, pose); 00302 } 00303 } 00304 //DEBUG 00305 // ROS_INFO("fitmodelransac run: %f ms, iterations: %d, eps: %f, escape cond: %f", 00306 // 1000*(cv::getTickCount() - ticksBefore)/cv::getTickFrequency(), 00307 // k, eps, pow(1. - pow(eps,n_points_to_match),k)); 00308 // ROS_INFO("inliers: %d, total #points: %d", inls, matches.Size()); 00309 00310 00311 numInl=inls; 00312 00313 cvReleaseMat(&modelPoints); 00314 cvReleaseMat(&imgPoints); 00315 cvReleaseMat(&rod); 00316 } 00317 00321 bool ODetect3D::GetBestCorner(PoseCv &pose, KeypointDescriptor *k, CodebookEntry *cbe, Point3D &pos, double &minDist) 00322 { 00323 Vector2 p; 00324 00325 double dist; 00326 minDist = DBL_MAX; 00327 CvMat *tempPos = cvCreateMat( 3, 1, CV_32F ); 00328 00329 00330 for (unsigned j=0; j<cbe->Size(); j++) 00331 { 00332 cvMatMulAdd( pose.R, cbe->occurrences[j]->pos, pose.t, tempPos ); 00333 ProjectPoint2Image(tempPos->data.fl[0], tempPos->data.fl[1], tempPos->data.fl[2], cameraMatrix, p.x, p.y); 00334 00335 dist = Distance(p,k->p); 00336 if (dist < minDist) 00337 { 00338 minDist = dist; 00339 pos.x = cbe->occurrences[j]->pos->data.fl[0]; 00340 pos.y = cbe->occurrences[j]->pos->data.fl[1]; 00341 pos.z = cbe->occurrences[j]->pos->data.fl[2]; 00342 } 00343 } 00344 00345 cvReleaseMat(&tempPos); 00346 00347 if (minDist < Def::DO_RANSAC_INL_DIST) 00348 return true; 00349 00350 return false; 00351 } 00352 00356 void ODetect3D::RefinePoseLS(Array<KeyClusterPair*> &matches, PoseCv &pose, unsigned &inl, double &err) 00357 { 00358 mat3 cR; 00359 vec3 ct; 00360 cR[0] = cvmGet(pose.R,0,0); cR[3] = cvmGet(pose.R,0,1); cR[6] = cvmGet(pose.R,0,2); 00361 cR[1] = cvmGet(pose.R,1,0); cR[4] = cvmGet(pose.R,1,1); cR[7] = cvmGet(pose.R,1,2); 00362 cR[2] = cvmGet(pose.R,2,0); cR[5] = cvmGet(pose.R,2,1); cR[8] = cvmGet(pose.R,2,2); 00363 00364 ct.x = cvmGet(pose.t,0,0); 00365 ct.y = cvmGet(pose.t,1,0); 00366 ct.z = cvmGet(pose.t,2,0); 00367 00368 ROS_INFO("ct and cR in RefinePoseLS: [%f %f %f] \n [%f %f %f] \n [%f %f %f] \n [%f %f %f]", 00369 ct.x, ct.y, ct.z, cR[0], cR[3], cR[6], cR[1], cR[4], cR[7], cR[2], cR[5], cR[8]); 00370 00371 00372 double dist, minz=DBL_MAX, maxz=DBL_MIN; 00373 Array<Point3D> modelPoints; 00374 Array<Point2D> imgPoints; 00375 CvMat modelPointsCv; 00376 CvMat imgPointsCv; 00377 CvMat *rod; 00378 err=0; 00379 PoseCv tmpPose; 00380 Vector3 t, p; 00381 00382 inlier.Clear(); 00383 00384 modelPoints.PushBack(Point3D()); 00385 imgPoints.PushBack(Point2D()); 00386 for (unsigned i=0; i<matches.Size(); i++) 00387 { 00388 if (GetBestCorner(pose, matches[i]->k, matches[i]->c, modelPoints.Last(), dist)) 00389 { 00390 err+=dist; 00391 imgPoints.Last().x = (float)matches[i]->k->p.x; 00392 imgPoints.Last().y = (float)matches[i]->k->p.y; 00393 00394 if (modelPoints.Last().z>maxz) 00395 maxz=modelPoints.Last().z; 00396 else if (modelPoints.Last().z<minz) 00397 minz=modelPoints.Last().z; 00398 00399 modelPoints.PushBack(Point3D()); 00400 imgPoints.PushBack(Point2D()); 00401 inlier.PushBack(matches[i]->k); //just store pointers to inlier for drawing.... 00402 } 00403 } 00404 modelPoints.EraseLast(); 00405 imgPoints.EraseLast(); 00406 00407 CopyPoseCv(pose,tmpPose); 00408 if (modelPoints.Size()>4) 00409 { 00410 err/=(double)modelPoints.Size(); 00411 rod = cvCreateMat(3,1,CV_32F); 00412 cvInitMatHeader( &modelPointsCv, modelPoints.Size(), 3, CV_32F, &modelPoints[0].x ); 00413 cvInitMatHeader( &imgPointsCv, imgPoints.Size(), 2, CV_32F, &imgPoints[0].x ); 00414 00415 cvFindExtrinsicCameraParams2(&modelPointsCv, &imgPointsCv, cameraMatrix, distCoeffs, rod, pose.t); 00416 cvRodrigues2(rod,pose.R); 00417 00418 cvReleaseMat(&rod); 00419 } 00420 00421 //up to now we have no keypoint normals, i.e. no visibility 00422 //so for now if least squares fails just copy back the RANSAC pose!!! 00423 p = Vector3(cvmGet(pose.t,0,0),cvmGet(pose.t,1,0),cvmGet(pose.t,2,0)); 00424 t = Vector3(cvmGet(tmpPose.t,0,0),cvmGet(tmpPose.t,1,0),cvmGet(tmpPose.t,2,0)); 00425 if (Distance(p,t) < (maxz-minz) * Def::DISTANCE_RATIO) 00426 { 00427 inl = modelPoints.Size(); 00428 }else 00429 { 00430 CopyPoseCv(tmpPose,pose); 00431 } 00432 } 00433 00437 void ODetect3D::ComputeConfidence(Array<KeypointDescriptor *> &keys, unsigned &numInl, Object3D &object) 00438 { 00439 Vector2 p; 00440 Array<Vector2> cs; 00441 CodebookEntry *cbe; 00442 00443 if (numInl>=4) 00444 { 00445 unsigned numKeys=0; 00446 CvMat *pos = cvCreateMat( 3, 1, CV_32F ); 00447 for (unsigned i=0; i<object.codebook.Size(); i++) 00448 { 00449 cbe=object.codebook[i]; 00450 for (unsigned j=0; j<cbe->occurrences.Size(); j++) 00451 { 00452 cvMatMulAdd( object.pose.R, cbe->occurrences[j]->pos, object.pose.t, pos ); 00453 ProjectPoint2Image(pos->data.fl[0],pos->data.fl[1],pos->data.fl[2], cameraMatrix, p.x, p.y); 00454 cs.PushBack(p); 00455 } 00456 } 00457 cvReleaseMat(&pos); 00458 ConvexHull(cs, object.contour.v); 00459 00460 for (unsigned i=0; i<keys.Size(); i++) 00461 if (object.contour.Inside(keys[i]->p)) 00462 numKeys++; 00463 00464 if (numKeys>4) 00465 { 00466 object.conf = (double)numInl / (double)numKeys; 00467 return; 00468 } 00469 } 00470 00471 object.conf = 0.; 00472 } 00473 00474 00475 00476 /******************************** PUBLIC **************************/ 00480 bool ODetect3D::Detect(Array<KeypointDescriptor *> &keys, Object3D &object) 00481 { 00482 #ifdef DEBUG 00483 struct timespec start0, end0, start1, end1, start2, end2, start3, end3; 00484 clock_gettime(CLOCK_REALTIME, &start1); 00485 clock_gettime(CLOCK_REALTIME, &start0); 00486 #endif 00487 00488 unsigned numInl=0; 00489 DeletePairs(matches); // make sure the vector is empty, we'll keep them for later to draw 00490 00491 if (Def::DO_MATCHER==2) // match keypoints with codebook gpu 00492 MatchKeypointsGPU(keys, object.codebook, matches); 00493 else if (Def::DO_MATCHER==1) // threshold matches 00494 MatchKeypoints(keys, object.codebook, matches); 00495 else // use second nearest neighbour 00496 MatchKeypoints2(keys, object.codebook, matches); 00497 00498 for (unsigned i=0; i<matches.Size(); i++) 00499 KeypointDescriptor::Draw(dbg,*matches[i]->k,CV_RGB(255,255,0)); 00500 00501 #ifdef DEBUG 00502 clock_gettime(CLOCK_REALTIME, &end0); 00503 if (dbg!=0) 00504 for (unsigned i=0; i<matches.Size(); i++) 00505 KeypointDescriptor::Draw(dbg,*matches[i]->k,CV_RGB(255,0,0)); 00506 clock_gettime(CLOCK_REALTIME, &start2); 00507 #endif 00508 00509 FitModelRANSAC(matches, object.pose, numInl); // ransac pose 00510 00511 #ifdef DEBUG 00512 clock_gettime(CLOCK_REALTIME, &end2); 00513 clock_gettime(CLOCK_REALTIME, &start3); 00514 #endif 00515 00516 RefinePoseLS(matches, object.pose, numInl, object.err); // least squares pose 00517 ComputeConfidence(keys, numInl, object); 00518 00519 00520 //DEBUG 00521 // mat3 cR; 00522 // vec3 ct; 00523 // cR[0] = cvmGet(object.pose.R,0,0); cR[3] = cvmGet(object.pose.R,0,1); cR[6] = cvmGet(object.pose.R,0,2); 00524 // cR[1] = cvmGet(object.pose.R,1,0); cR[4] = cvmGet(object.pose.R,1,1); cR[7] = cvmGet(object.pose.R,1,2); 00525 // cR[2] = cvmGet(object.pose.R,2,0); cR[5] = cvmGet(object.pose.R,2,1); cR[8] = cvmGet(object.pose.R,2,2); 00526 // 00527 // ct.x = cvmGet(object.pose.t,0,0); 00528 // ct.y = cvmGet(object.pose.t,1,0); 00529 // ct.z = cvmGet(object.pose.t,2,0); 00530 // 00531 // ROS_INFO("ct and cR in DETECT: [%f %f %f] \n [%f %f %f] \n [%f %f %f] \n [%f %f %f]", 00532 // ct.x, ct.y, ct.z, cR[0], cR[3], cR[6], cR[1], cR[4], cR[7], cR[2], cR[5], cR[8]); 00533 00534 00535 #ifdef DEBUG 00536 clock_gettime(CLOCK_REALTIME, &end3); 00537 clock_gettime(CLOCK_REALTIME, &end1); 00538 cout<<"id="<<object.id<<", conf="<<object.conf<<", err="<<object.err<<", numInl="<<numInl 00539 <<", cbSize="<<object.codebook.Size()<<endl; 00540 cout<<"Pose translation: ["<<cvmGet(object.pose.t,0,0)<<" "<<cvmGet(object.pose.t,1,0)<<" "<<cvmGet(object.pose.t,2,0)<<"]"<<endl; 00541 cout<<"Time for matching keypoints [s]: "<<P::timespec_diff(&end0, &start0)<<endl; 00542 cout<<"Time for RANSAC [s]: "<<P::timespec_diff(&end2, &start2)<<endl; 00543 cout<<"Time for least squares pose [s]: "<<P::timespec_diff(&end3, &start3)<<endl; 00544 cout<<"Time for object detection (matching and RANSAC) [s]: "<<P::timespec_diff(&end1, &start1)<<endl; 00545 #endif 00546 00547 if (numInl>=4) 00548 return true; 00549 00550 object.conf=0.; 00551 object.err=DBL_MAX; 00552 00553 return false; 00554 } 00555 00562 void ODetect3D::SetCameraParameter(CvMat *C) 00563 { 00564 cvCopy(C,cameraMatrix); 00565 } 00566 00572 void ODetect3D::DrawInlier(IplImage *img, CvScalar col) 00573 { 00574 for (unsigned i=0; i<inlier.Size(); i++) 00575 KeypointDescriptor::Draw(img,*inlier[i], col); 00576 } 00577 00578 } 00579