$search
00001 00035 #define NO_ROS 0 00036 00037 #include "cv.h" 00038 #include "highgui.h" 00039 #include <stdio.h> 00040 #include <ctype.h> 00041 #include <Eigen/Eigen> 00042 #include <assert.h> 00043 #include <iostream> 00044 #include <set> 00045 #include <opencv2/core/eigen.hpp> 00046 #include <cmath> 00047 #include <ros/ros.h> 00048 #include "sensor_msgs/Image.h" 00049 #include "cv_bridge/CvBridge.h" 00050 #include "camera_self_filter/mask.h" 00051 #include "Timer.h" 00052 #include <fstream> 00053 #include <iostream> 00054 //#include <boost/math/distributions/beta.hpp> 00055 00056 using std::cout; 00057 using std::endl; 00058 00059 00060 /*** 00061 * Retrives rotation and translation minimzing the error of the rigid transformation between two sets of points. 00062 * Modified opencv version. 00063 */ 00064 static void 00065 icvGetRTMatrix( const CvPoint2D32f* a, const CvPoint2D32f* b, 00066 int count, CvMat* M ) 00067 { 00068 00069 00070 double sa[16], sb[4], m[4], *om = M->data.db; 00071 CvMat A = cvMat( 4, 4, CV_64F, sa ), B = cvMat( 4, 1, CV_64F, sb ); 00072 CvMat MM = cvMat( 4, 1, CV_64F, m ); 00073 00074 int i; 00075 00076 memset( sa, 0, sizeof(sa) ); 00077 memset( sb, 0, sizeof(sb) ); 00078 00079 for( i = 0; i < count; i++ ) 00080 { 00081 sa[0] += a[i].x*a[i].x + a[i].y*a[i].y; 00082 sa[1] += 0; 00083 sa[2] += a[i].x; 00084 sa[3] += a[i].y; 00085 00086 sa[4] += 0; 00087 sa[5] += a[i].x*a[i].x + a[i].y*a[i].y; 00088 sa[6] += -a[i].y; 00089 sa[7] += a[i].x; 00090 00091 sa[8] += a[i].x; 00092 sa[9] += -a[i].y; 00093 sa[10] += 1; 00094 sa[11] += 0; 00095 00096 sa[12] += a[i].y; 00097 sa[13] += a[i].x; 00098 sa[14] += 0; 00099 sa[15] += 1; 00100 00101 sb[0] += a[i].x*b[i].x + a[i].y*b[i].y; 00102 sb[1] += a[i].x*b[i].y - a[i].y*b[i].x; 00103 sb[2] += b[i].x; 00104 sb[3] += b[i].y; 00105 } 00106 00107 cvSolve( &A, &B, &MM, CV_SVD ); 00108 00109 om[0] = om[4] = m[0]; 00110 om[1] = -m[1]; 00111 om[3] = m[1]; 00112 om[2] = m[2]; 00113 om[5] = m[3]; 00114 00115 } 00116 00117 /*** 00118 * Retrives rotation and translation minimzing the error of the rigid transformation between two sets of points. 00119 * 00120 */ 00121 cv::Mat cvEstimateRigidTransformFrom2( const cv::Mat& A, const cv::Mat& B) { 00122 cv::Mat M = cv::Mat(2, 3, CV_64F); 00123 00124 CvPoint2D32f* a = (CvPoint2D32f*) A.data; 00125 CvPoint2D32f* b = (CvPoint2D32f*) B.data; 00126 CvMat matM = M; 00127 icvGetRTMatrix(a,b, 2, &matM); 00128 return M; 00129 } 00130 00131 00132 /*** 00133 * Extracts corner features from an image and tracks them in subsequent images. 00134 * The features are clustered such that each feature cluster consists of features with similar trajectories, i.e. 00135 * which can be explained by the same sequence of rigid transforms. 00136 */ 00137 00138 class FeatureTracker{ 00139 public: 00140 00141 //Parameters for feature detection 00142 static const int MAX_CORNERS = 500; 00143 static const double quality = 0.01; 00144 static const double min_distance = 10; 00145 static const int WIN_SIZE = 10; 00146 00147 //number of points used to calculate RT 00148 const static int num_points_to_select = 3; 00149 00150 cv::Mat vis_image; 00151 cv::Mat vis_image_orig; 00152 cv::Mat last_image; 00153 std::vector<std::vector<cv::Point2f> > corner_trajectories; 00154 std::vector<std::vector<cv::Point2f> > corner_trajectories_filtered_and_transposed; 00155 00156 Eigen::VectorXi good_corners; 00157 00158 //executed tracking steps 00159 int num_tracking_steps; 00160 00161 // colormap for disparities, RGB order 00162 static unsigned char colormap[]; 00163 00164 static const float residual_error_comp = 0.1 ;// 0.1; //deduct half a pixel from the residuals at each timestep 00165 00166 FeatureTracker():num_tracking_steps(0){} 00167 00168 /*** 00169 * Find corners using OpnecCV's goodFeaturesToTrack. 00170 */ 00171 std::vector<cv::Point2f> findCorners(cv::Mat& first_image, cv::Mat* mask = 0); 00172 00173 /*** 00174 * Execute one tracking step: 00175 * Calculate sparse optical flow from all corners in old image 00176 */ 00177 bool tracking_step(cv::Mat& new_image); 00178 00179 /*** 00180 * Caluculates residuals as squared reprojection error between rigid transform trajectory predicted by hypothesis and actual trajectory. 00181 */ 00182 bool calcResiduals(const std::vector<Eigen::Matrix3f>& RTs, const std::vector<std::vector<cv::Point2f> >& corner_trajectories_t, Eigen::VectorXf& residuals ); 00183 00184 bool filterTrajectories(); 00185 00189 int draw(Eigen::VectorXf& prob_dist); 00190 00191 bool selectRandomFeatures(std::vector<int>& features_idx, const Eigen::VectorXf& mask); 00192 00193 /*** 00194 * generates a rotation translation trajectory hypothesis for all features marked in mask in a RANSAC like fashion. 00195 */ 00196 bool generateHypothesis(const Eigen::VectorXf& mask, std::vector<Eigen::Matrix3f>& RTs ); 00197 00198 bool writeClustersToFile(int& idx,cv::Point2f& feature,std::ofstream& a_file); 00199 00200 /*** Top-level function: 00201 * Samples a number of hypothesis sets, i.e. samples sets of possible feature clusters. 00202 * Hypothesis sets are scored and best one is returned/visualized. 00203 */ 00204 bool evluateTrajectories(); 00205 00206 00207 /*** 00208 * Sample recursively possible feature-to-cluster associations (hypotheses) by generating a hypothesis 00209 * on the input features set, calculate outliers and generate another hypothesis, ... and so on until a 00210 * hypothesis exists for each feature. 00211 */ 00212 float sampleHypothesisSet(std::vector<int>& feature_assocoation); 00213 00214 }; 00215 00216 /*** 00217 * Find corners using OpnecCV's goodFeaturesToTrack. 00218 */ 00219 std::vector<cv::Point2f> FeatureTracker::findCorners(cv::Mat& first_image, cv::Mat* mask){ 00220 num_tracking_steps = 0; 00221 cv::Mat first_image_grey; 00222 cv::cvtColor(first_image, first_image_grey, CV_BGR2GRAY); 00223 std::vector<cv::Point2f> corners; 00224 cv::goodFeaturesToTrack(first_image_grey,corners, MAX_CORNERS, quality,min_distance); 00225 00226 good_corners = Eigen::VectorXi::Ones(corners.size()); 00227 cv::cornerSubPix(first_image_grey, corners, cv::Size(WIN_SIZE, WIN_SIZE), cv::Size(-1,-1), cv::TermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03)); 00228 corner_trajectories.push_back(corners); 00229 last_image = first_image_grey; 00230 00231 //visulization 00232 vis_image_orig =first_image; 00233 vis_image = vis_image_orig.clone(); 00234 for (unsigned int i = 0; i< corners.size(); i++){ 00235 int color_idx = ((num_tracking_steps * 11) % 256) * 3; 00236 cv::circle(vis_image, corners[i], 3, cv::Scalar(colormap[color_idx], colormap[color_idx +1], colormap[color_idx +2],0), -1); 00237 } 00238 00239 return corners; 00240 } 00241 00242 /*** 00243 * Execute one tracking step: 00244 * Calculate sparse optical flow from all corners in old image 00245 */ 00246 bool FeatureTracker::tracking_step(cv::Mat& new_image){ 00247 num_tracking_steps++; 00248 cv::Mat new_image_grey; 00249 cv::cvtColor(new_image, new_image_grey, CV_BGR2GRAY); 00250 std::vector<cv::Point2f> new_corners; 00251 std::vector<unsigned char> status; 00252 std::vector<float> error; 00253 cv::calcOpticalFlowPyrLK(last_image, new_image_grey, corner_trajectories.back(), new_corners, status, error, cv::Size(WIN_SIZE,WIN_SIZE), 3, cv::TermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03)); 00254 00255 last_image = new_image_grey; 00256 00257 corner_trajectories.push_back(new_corners); 00258 for (unsigned int i = 0; i< good_corners.rows(); i++){ 00259 good_corners[i] = good_corners[i] & status[i]; 00260 } 00261 printf("num good corners %d %d new _corner_size %d \n", good_corners.sum(), good_corners.rows(), corner_trajectories.back().size()); 00262 00263 //visulization 00264 vis_image_orig =new_image; 00265 vis_image = vis_image_orig.clone(); 00266 std::vector<cv::Point2f>& old_corners = corner_trajectories[num_tracking_steps - 1]; 00267 for (unsigned int i = 0; i< new_corners.size(); i++){ 00268 if (!good_corners[i]) continue; 00269 int color_idx = ((num_tracking_steps * 11) % 256) * 3; 00270 // cv::circle(vis_image, new_corners[i], 3, cv::Scalar(colormap[color_idx], colormap[color_idx +1], colormap[color_idx +2],0), -1); 00271 // cv::line(vis_image,new_corners[i], old_corners[i], cv::Scalar(0,0,255,0), 1); 00272 // cv::line(vis_image,new_corners[i], old_corners[i], cv::Scalar(colormap[color_idx], colormap[color_idx +1], colormap[color_idx +2]), 1); 00273 00274 } 00275 00276 return true; 00277 00278 00279 } 00280 00281 00282 /*** 00283 * Caluculates residuals as squared reprojection error between rigid transform trajectory predicted by hypothesis and actual trajectory. 00284 */ 00285 bool FeatureTracker::calcResiduals(const std::vector<Eigen::Matrix3f>& RTs, const std::vector<std::vector<cv::Point2f> >& corner_trajectories_t, Eigen::VectorXf& residuals ){ 00286 00287 residuals = Eigen::VectorXf(corner_trajectories_t.size()); 00288 for (unsigned int t = 0; t < corner_trajectories_t.size(); t++){ 00289 const std::vector<cv::Point2f>& current_trajectory = corner_trajectories_t[t]; 00290 // printf("RTs.size() %d current_trajectory.size() %d\n",RTs.size(),current_trajectory.size()); 00291 assert(RTs.size() == current_trajectory.size() - 1); 00292 float residual = 0; 00293 for (unsigned int c = 0; c < current_trajectory.size() - 1; c++){ 00294 Eigen::Vector3f old_corner (current_trajectory[c].x, current_trajectory[c].y, 1.0); 00295 Eigen::Vector3f new_corner (current_trajectory[c+1].x, current_trajectory[c+1].y, 1.0); 00296 Eigen::Vector3f res = new_corner - (RTs[c] * old_corner); 00297 // cout<<"res for traj "<<t<<": vec\n"<<res<<endl; 00298 00299 residual += std::max(0.0f,res.squaredNorm() - residual_error_comp); 00300 00301 } 00302 residuals[t] = residual; 00303 } 00304 return true; 00305 } 00306 00307 00308 bool FeatureTracker::filterTrajectories(){ 00309 00310 std::vector<std::vector<cv::Point2f> > corner_trajectories_filtered; 00311 printf("corner_trajectories size %d corner_trajectories[0].size() %d good _corners %d\n", corner_trajectories.size(), corner_trajectories[0].size(), good_corners.rows()); 00312 int num_good_features = good_corners.sum(); 00313 00314 //filter out bad features 00315 for (unsigned int j=0; j < corner_trajectories.size(); j++){ 00316 std::vector<cv::Point2f> features_filtered; 00317 features_filtered.reserve(num_good_features); 00318 for (unsigned int i=0; i < good_corners.rows(); i++){ 00319 if (good_corners[i]){ 00320 features_filtered.push_back(corner_trajectories[j][i]); 00321 } 00322 } 00323 corner_trajectories_filtered.push_back(features_filtered); 00324 } 00325 00326 //transpose 00327 corner_trajectories_filtered_and_transposed.clear(); 00328 corner_trajectories_filtered_and_transposed.reserve(good_corners.rows()); 00329 for (unsigned int i=0; i < good_corners.rows(); i++){ 00330 std::vector<cv::Point2f> features_trans; 00331 features_trans.reserve(corner_trajectories_filtered.size()); 00332 for (unsigned int j=0; j < corner_trajectories_filtered.size(); j++){ 00333 features_trans.push_back(corner_trajectories_filtered[j][i]); 00334 } 00335 corner_trajectories_filtered_and_transposed.push_back(features_trans); 00336 } 00337 00338 printf("corner_trajectories_filtered size %d \n", corner_trajectories_filtered.size()); 00339 00340 return true; 00341 00342 } 00343 00344 00348 int FeatureTracker::draw(Eigen::VectorXf& prob_dist){ 00349 float pos = (float) rand() / RAND_MAX; 00350 int idx = 0; 00351 float accumulator = 0.0f; 00352 for (;;){ 00353 accumulator += prob_dist[idx]; 00354 if (accumulator > pos) break; 00355 idx++; 00356 } 00357 return idx; 00358 00359 } 00360 00361 00362 //TODO: This needs to be done more efficiently... 00363 bool FeatureTracker::selectRandomFeatures(std::vector<int>& features_idx, const Eigen::VectorXf& mask){ 00364 00365 float variance = 200.0f * 200.0f; //pixel size of objects 00366 //select random but depending on gaussian distance 00367 //first create map 00368 int num_non_masked_elements = mask.sum(); 00369 if (num_non_masked_elements < 3){ 00370 printf("num non masked elements %d\n", num_non_masked_elements); 00371 return false; 00372 } 00373 int* map_array = new int[num_non_masked_elements]; 00374 int counter = 0; 00375 for (int i = 0; i < mask.rows() ; i++){ 00376 if (mask[i] > 0.0){ 00377 map_array[counter] = i; 00378 counter++; 00379 } 00380 00381 00382 } 00383 00384 //we assume 3 points are selected... 00385 int idx1 = rand() % num_non_masked_elements; 00386 Eigen::VectorXf prob_dist(num_non_masked_elements); 00387 cv::Point2f current_point = corner_trajectories_filtered_and_transposed[map_array[idx1]].back(); 00388 for(int i=0; i<num_non_masked_elements; i++){ 00389 if (i==idx1){ 00390 prob_dist[i] = 0.0; 00391 continue; 00392 } 00393 cv::Point2f other = corner_trajectories_filtered_and_transposed[map_array[i]].back(); 00394 float dist_sqr = pow((other.x - current_point.x ),2) + pow((other.y - current_point.y ),2); 00395 printf("dist sqr %d %f\n", i, dist_sqr ); 00396 float dist_sqr_n = dist_sqr / variance; 00397 prob_dist[i] = exp( -0.5 * dist_sqr_n); 00398 00399 } 00400 00401 cout<<"prob_dist\n"<<prob_dist<<endl; 00402 float normalizer = prob_dist.sum(); 00403 00404 //take care of the case where numbers are really low 00405 if (normalizer < 0.0000000001){ 00406 return false; 00407 } 00408 00409 prob_dist = prob_dist / normalizer; 00410 cout<<"prob_dist_n\n"<<prob_dist<<endl; 00411 int idx2 = draw(prob_dist); 00412 00413 assert(map_array[idx1] < mask.rows()); 00414 assert(map_array[idx2] < mask.rows()); 00415 features_idx.clear(); 00416 features_idx.push_back(map_array[idx1]); 00417 features_idx.push_back(map_array[idx2]); 00418 00419 00420 delete [] map_array; 00421 return true; 00422 } 00423 00424 00425 /*** 00426 * generates a rotation translation trajectory hypothesis for all features marked in mask in a RANSAC like fashion. 00427 */ 00428 bool FeatureTracker::generateHypothesis(const Eigen::VectorXf& mask, std::vector<Eigen::Matrix3f>& RTs ){ 00429 00430 00431 int num_elements = mask.sum(); 00432 printf("in generateHypothesis num_elements %d\n",num_elements); 00433 if (num_elements < 3) return false; 00434 00435 std::vector<int> features_idx; 00436 if (!selectRandomFeatures(features_idx, mask)) return false; 00437 00438 RTs.reserve(num_tracking_steps); 00439 printf("num_tracking_steps %d\n",num_tracking_steps); 00440 for (int i = 1; i< num_tracking_steps+1; i++){ 00441 printf("step gen %d \n", i); 00442 cv::Mat new_points (features_idx.size(), 1, CV_32FC2); 00443 cv::Mat old_points (features_idx.size(), 1, CV_32FC2); 00444 for (int j = 0; j < features_idx.size(); j++){ 00445 cv::Point2f& new_point = corner_trajectories_filtered_and_transposed[features_idx[j]][i]; 00446 new_points.ptr<float>()[j * 2] = new_point.x; 00447 new_points.ptr<float>()[j * 2 + 1] = new_point.y; 00448 cv::Point2f& old_point = corner_trajectories_filtered_and_transposed[features_idx[j]][i-1]; 00449 old_points.ptr<float>()[j * 2] = old_point.x; 00450 old_points.ptr<float>()[j * 2 + 1] = old_point.y; 00451 } 00452 // cv::Mat RT_cv = cv::estimateRigidTransform(old_points, new_points, false); 00453 cv::Mat RT_cv = cvEstimateRigidTransformFrom2(old_points, new_points); 00454 Eigen::Matrix3f RT = Eigen::Matrix3f::Identity(); 00455 Eigen::Matrix<float, 2,3> rt_temp; 00456 cv::cv2eigen(RT_cv, rt_temp); 00457 RT.block<2,3>(0,0) = rt_temp; 00458 RTs.push_back(RT); 00459 } 00460 cout<<"last hyp tf \n"<<RTs.back()<<endl; 00461 return true; 00462 00463 00464 } 00465 00466 bool FeatureTracker::writeClustersToFile(int& idx,cv::Point2f& feature,std::ofstream& a_file){ 00467 00468 00469 //std::stringstream ss; 00470 //ss<<ros::Time::now(); 00471 //std::ofstream a_file ( ss.str().c_str() ); 00472 a_file<< feature.x << " " << feature.y << " " << idx << std::endl; 00473 00474 00475 00476 } 00477 00478 00479 /*** Top-level function: 00480 * Samples a number of hypothesis sets, i.e. samples sets of possible feature clusters. 00481 * Hypothesis sets are scored and best one is returned/visualized. 00482 */ 00483 bool FeatureTracker::evluateTrajectories(){ 00484 00485 int num_samples = 15; 00486 int num_hypotheses = 10; 00487 filterTrajectories(); 00488 Eigen::VectorXf scores = Eigen::VectorXf::Zero(num_samples); 00489 std::vector<std::vector<int > > feature_assocoations; 00490 00491 //create hypothesis set samples 00492 for (int i = 0; i<num_samples; i++){ 00493 std::vector<int> feature_assocoation; 00494 scores[i] = sampleHypothesisSet(feature_assocoation); 00495 feature_assocoations.push_back(feature_assocoation); 00496 // if(feature_assocoation.size() != 1){ 00497 // cv::imshow("tracker_temp", vis_image); 00498 // cvWaitKey(1500); 00499 // } 00500 } 00501 00502 //find best hypothesis... 00503 int best_hypthesis_set_idx; 00504 scores.minCoeff(&best_hypthesis_set_idx); 00505 00506 //..which becomes final feature-to-cluster association. 00507 std::vector<int>& final_feature_association = feature_assocoations[best_hypthesis_set_idx]; 00508 00509 vis_image = vis_image_orig.clone(); 00510 00511 //only for logging purposes 00512 std::stringstream ss; 00513 ss<<ros::Time::now(); 00514 std::ofstream a_file ( ss.str().c_str() ); 00515 00516 for (int i = 0; i < corner_trajectories_filtered_and_transposed.size(); i++){ 00517 int idx = final_feature_association[i]; 00518 00519 writeClustersToFile(idx,corner_trajectories_filtered_and_transposed[i].back(),a_file); 00520 00521 00522 if (idx >= 0){ 00523 cv::circle(vis_image, corner_trajectories_filtered_and_transposed[i].back(), 9, cv::Scalar( colormap[3*idx], colormap[3*idx+1], colormap[3*idx+2],0), 5); 00524 00525 00526 // }else{ 00527 // cv::circle(vis_image, corner_trajectories_filtered_and_transposed[i].back(), 9, cv::Scalar( 0 , 0, 0, 0), 5, 1); 00528 } 00529 } 00530 00531 a_file.close(); 00532 00533 return true; 00534 00535 } 00536 00537 00538 /*** 00539 * Sample recursively possible feature-to-cluster associations (hypotheses) by generating a hypothesis 00540 * on the input features set, calculate outliers and generate another hypothesis, ... and so on until a 00541 * hypothesis exists for each feature. 00542 */ 00543 float FeatureTracker::sampleHypothesisSet(std::vector<int>& feature_assocoation){ 00544 int num_hypotheses = 10; 00545 float mask_threshold = 80; 00546 00547 Eigen::MatrixXf residualMatrix (corner_trajectories_filtered_and_transposed.size(), num_hypotheses); 00548 00549 std::vector<std::vector<Eigen::Matrix3f> > hypothesis; 00550 00551 //create identity Matrix as first hypothesos 00552 std::vector<Eigen::Matrix3f> RTs_I; 00553 RTs_I.resize(num_tracking_steps, Eigen::Matrix3f::Identity()); 00554 printf ("num_tracking_steps %d RTs_I.size() %d \n", num_tracking_steps, RTs_I.size()); 00555 hypothesis.push_back(RTs_I); 00556 00557 Eigen::VectorXf mask = Eigen::VectorXf::Ones(corner_trajectories_filtered_and_transposed.size()); 00558 bool points_left; 00559 int i=1; 00560 for (; i<num_hypotheses; i++){ 00561 Eigen::VectorXf residuals; 00562 std::vector<Eigen::Matrix3f>& last_hypothesis = hypothesis[i-1]; 00563 printf("last_hypothesis size %d\n", last_hypothesis.size()); 00564 00565 //calculate the residuals incurred by current hypothesis (i.e. error between features' actual RT and the hypothetical RT). 00566 calcResiduals(last_hypothesis, corner_trajectories_filtered_and_transposed , residuals); 00567 00568 //store residuals 00569 residualMatrix.col(i-1) = residuals; 00570 00571 // cout<<"residuals\n"<<residuals<<endl; 00572 // cout<<"residuals_mat \n"<<residualMatrix<<endl; 00573 00574 //find inliers and mark them in binary mask 00575 Eigen::VectorXf mask_bin = (residuals.array() - mask_threshold).matrix(); 00576 for (int i = 0; i< mask_bin.rows(); i++){ 00577 mask_bin[i] = (mask_bin[i] > 0.0f) ? 1.0f : 0.0f; 00578 } 00579 00580 Eigen::ArrayXf mask_array= mask.array(); 00581 Eigen::ArrayXf mask_array_bin= mask_bin.array(); 00582 00583 00584 mask = mask_array.min(mask_array_bin); 00585 00586 // mask = mask.array().min(mask_bin.array()); 00587 00588 std::vector<Eigen::Matrix3f> new_hypothesis; 00589 00590 //for the outliers, generate a new hypothesis 00591 points_left = generateHypothesis(mask, new_hypothesis ); 00592 if (!points_left) break; 00593 printf("generated new hyp of size %d\n", new_hypothesis.size()); 00594 hypothesis.push_back(new_hypothesis); 00595 00596 } 00597 //calc last residuals if all hypothesis had to be used 00598 int& actual_num_hypothesis = i; 00599 printf("actual_num_hypothesis %d num_hypotheses %d\n", actual_num_hypothesis,num_hypotheses); 00600 if (actual_num_hypothesis == num_hypotheses){ 00601 Eigen::VectorXf residuals; 00602 printf("ypothesis.back() size %d\n", hypothesis.back().size()); 00603 calcResiduals(hypothesis.back(), corner_trajectories_filtered_and_transposed ,residuals ); 00604 // cout<<"last residuals\n"<<residuals; 00605 residualMatrix.col(residualMatrix.cols()-1) = residuals; 00606 }else{ 00607 // cout<<"residuals_mat \n"<<residualMatrix<<endl; 00608 Eigen::MatrixXf residualMatrix2 = residualMatrix.block(0,0, residualMatrix.rows(), actual_num_hypothesis); 00609 residualMatrix = residualMatrix2; 00610 // cout<<"residuals_mat \n"<<residualMatrix<<endl; 00611 } 00612 00613 00614 cout<<"residuals_mat \n"<<residualMatrix<<endl; 00615 00616 Eigen::VectorXf summed_residuals = residualMatrix.colwise().sum(); 00617 00618 cout<<"summed_residuals \n"<<summed_residuals<<endl; 00619 00620 Eigen::VectorXf summed_residuals_per_h = Eigen::VectorXf::Zero(residualMatrix.cols()); 00621 00622 00623 //Finally run the process again and assign each feature to its best possible RT hypothesis (or mark it as complete outlier). 00624 std::vector<int> best_feature_h_idx; 00625 best_feature_h_idx.resize(corner_trajectories_filtered_and_transposed.size(),0); 00626 Eigen::VectorXf feature_per_hyp_count = Eigen::VectorXf::Ones(residualMatrix.cols()); 00627 feature_per_hyp_count *= 0.0000001f; 00628 int num_outliers = 0; 00629 for (int i = 0; i < corner_trajectories_filtered_and_transposed.size(); i++){ 00630 int idx; 00631 residualMatrix.row(i).minCoeff(&idx); 00632 float residual_value = residualMatrix(i,idx); 00633 00634 //check if feature was an outlier 00635 if (mask[i] > 0.0f){ 00636 num_outliers++; 00637 best_feature_h_idx[i] = -1; 00638 continue; 00639 } 00640 00641 best_feature_h_idx[i] = idx; 00642 feature_per_hyp_count[idx]++; 00643 summed_residuals_per_h[idx] += residualMatrix(i,idx); 00644 // if (idx >= 0 && feature_per_hyp_count[idx] > 2.1){ 00645 // cv::circle(vis_image, corner_trajectories_filtered_and_transposed[i].back(), 9, cv::Scalar( colormap[3*idx], colormap[3*idx+1], colormap[3*idx+2],0), 5); 00646 // }else{ 00647 // cv::circle(vis_image, corner_trajectories_filtered_and_transposed[i].back(), 9, cv::Scalar( 0 , 0, 0, 0), 5, 1); 00648 // } 00649 // 00650 // 00655 } 00656 00657 vis_image = vis_image_orig.clone(); 00658 for (int i = 0; i < corner_trajectories_filtered_and_transposed.size(); i++){ 00659 int idx = best_feature_h_idx[i]; 00660 if (idx >= 0 && feature_per_hyp_count[idx] > 5.1){ 00661 cv::circle(vis_image, corner_trajectories_filtered_and_transposed[i].back(), 9, cv::Scalar( colormap[3*idx], colormap[3*idx+1], colormap[3*idx+2],0), 5); 00662 }else{ //stupid feature 00663 best_feature_h_idx[i] = -1; 00664 } 00665 } 00666 00667 00668 cout<<"num feature_per_hyp_count \n"<<feature_per_hyp_count<<endl; 00669 summed_residuals.array() /= feature_per_hyp_count.array(); 00670 00671 cout<<"summed_residuals \n"<<summed_residuals<<endl; 00672 00673 cout<<"summed_residuals_per_h \n"<<summed_residuals_per_h<<endl; 00674 00675 summed_residuals_per_h.array() /= feature_per_hyp_count.array(); 00676 cout<<"summed_residuals_per_h \n"<<summed_residuals_per_h<<endl; 00677 00678 cout<<"total average residual error "<<summed_residuals_per_h.sum()<<endl; 00679 00680 feature_assocoation = best_feature_h_idx; 00681 float outlier_penalty = num_outliers * 100.0; 00682 printf("outlier num %d penalty %f\n", num_outliers, outlier_penalty); 00683 return summed_residuals_per_h.sum() ; 00684 00685 00686 } 00687 00688 unsigned char FeatureTracker::colormap[36] = 00689 { 00690 255,0,0, 00691 0,255,0, 00692 0,0,255, 00693 255,255,0, 00694 255,0,255, 00695 0,255,255, 00696 127,0,0, 00697 0,127,0, 00698 0,0,127, 00699 127,127,0, 00700 127,0,127, 00701 0,127,127, 00702 }; 00703 00704 //unsigned char FeatureTracker::colormap[768] = 00705 // { 150, 150, 150, 00706 // 107, 0, 12, 00707 // 106, 0, 18, 00708 // 105, 0, 24, 00709 // 103, 0, 30, 00710 // 102, 0, 36, 00711 // 101, 0, 42, 00712 // 99, 0, 48, 00713 // 98, 0, 54, 00714 // 97, 0, 60, 00715 // 96, 0, 66, 00716 // 94, 0, 72, 00717 // 93, 0, 78, 00718 // 92, 0, 84, 00719 // 91, 0, 90, 00720 // 89, 0, 96, 00721 // 88, 0, 102, 00722 // 87, 0, 108, 00723 // 85, 0, 114, 00724 // 84, 0, 120, 00725 // 83, 0, 126, 00726 // 82, 0, 131, 00727 // 80, 0, 137, 00728 // 79, 0, 143, 00729 // 78, 0, 149, 00730 // 77, 0, 155, 00731 // 75, 0, 161, 00732 // 74, 0, 167, 00733 // 73, 0, 173, 00734 // 71, 0, 179, 00735 // 70, 0, 185, 00736 // 69, 0, 191, 00737 // 68, 0, 197, 00738 // 66, 0, 203, 00739 // 65, 0, 209, 00740 // 64, 0, 215, 00741 // 62, 0, 221, 00742 // 61, 0, 227, 00743 // 60, 0, 233, 00744 // 59, 0, 239, 00745 // 57, 0, 245, 00746 // 56, 0, 251, 00747 // 55, 0, 255, 00748 // 54, 0, 255, 00749 // 52, 0, 255, 00750 // 51, 0, 255, 00751 // 50, 0, 255, 00752 // 48, 0, 255, 00753 // 47, 0, 255, 00754 // 46, 0, 255, 00755 // 45, 0, 255, 00756 // 43, 0, 255, 00757 // 42, 0, 255, 00758 // 41, 0, 255, 00759 // 40, 0, 255, 00760 // 38, 0, 255, 00761 // 37, 0, 255, 00762 // 36, 0, 255, 00763 // 34, 0, 255, 00764 // 33, 0, 255, 00765 // 32, 0, 255, 00766 // 31, 0, 255, 00767 // 29, 0, 255, 00768 // 28, 0, 255, 00769 // 27, 0, 255, 00770 // 26, 0, 255, 00771 // 24, 0, 255, 00772 // 23, 0, 255, 00773 // 22, 0, 255, 00774 // 20, 0, 255, 00775 // 19, 0, 255, 00776 // 18, 0, 255, 00777 // 17, 0, 255, 00778 // 15, 0, 255, 00779 // 14, 0, 255, 00780 // 13, 0, 255, 00781 // 11, 0, 255, 00782 // 10, 0, 255, 00783 // 9, 0, 255, 00784 // 8, 0, 255, 00785 // 6, 0, 255, 00786 // 5, 0, 255, 00787 // 4, 0, 255, 00788 // 3, 0, 255, 00789 // 1, 0, 255, 00790 // 0, 4, 255, 00791 // 0, 10, 255, 00792 // 0, 16, 255, 00793 // 0, 22, 255, 00794 // 0, 28, 255, 00795 // 0, 34, 255, 00796 // 0, 40, 255, 00797 // 0, 46, 255, 00798 // 0, 52, 255, 00799 // 0, 58, 255, 00800 // 0, 64, 255, 00801 // 0, 70, 255, 00802 // 0, 76, 255, 00803 // 0, 82, 255, 00804 // 0, 88, 255, 00805 // 0, 94, 255, 00806 // 0, 100, 255, 00807 // 0, 106, 255, 00808 // 0, 112, 255, 00809 // 0, 118, 255, 00810 // 0, 124, 255, 00811 // 0, 129, 255, 00812 // 0, 135, 255, 00813 // 0, 141, 255, 00814 // 0, 147, 255, 00815 // 0, 153, 255, 00816 // 0, 159, 255, 00817 // 0, 165, 255, 00818 // 0, 171, 255, 00819 // 0, 177, 255, 00820 // 0, 183, 255, 00821 // 0, 189, 255, 00822 // 0, 195, 255, 00823 // 0, 201, 255, 00824 // 0, 207, 255, 00825 // 0, 213, 255, 00826 // 0, 219, 255, 00827 // 0, 225, 255, 00828 // 0, 231, 255, 00829 // 0, 237, 255, 00830 // 0, 243, 255, 00831 // 0, 249, 255, 00832 // 0, 255, 255, 00833 // 0, 255, 249, 00834 // 0, 255, 243, 00835 // 0, 255, 237, 00836 // 0, 255, 231, 00837 // 0, 255, 225, 00838 // 0, 255, 219, 00839 // 0, 255, 213, 00840 // 0, 255, 207, 00841 // 0, 255, 201, 00842 // 0, 255, 195, 00843 // 0, 255, 189, 00844 // 0, 255, 183, 00845 // 0, 255, 177, 00846 // 0, 255, 171, 00847 // 0, 255, 165, 00848 // 0, 255, 159, 00849 // 0, 255, 153, 00850 // 0, 255, 147, 00851 // 0, 255, 141, 00852 // 0, 255, 135, 00853 // 0, 255, 129, 00854 // 0, 255, 124, 00855 // 0, 255, 118, 00856 // 0, 255, 112, 00857 // 0, 255, 106, 00858 // 0, 255, 100, 00859 // 0, 255, 94, 00860 // 0, 255, 88, 00861 // 0, 255, 82, 00862 // 0, 255, 76, 00863 // 0, 255, 70, 00864 // 0, 255, 64, 00865 // 0, 255, 58, 00866 // 0, 255, 52, 00867 // 0, 255, 46, 00868 // 0, 255, 40, 00869 // 0, 255, 34, 00870 // 0, 255, 28, 00871 // 0, 255, 22, 00872 // 0, 255, 16, 00873 // 0, 255, 10, 00874 // 0, 255, 4, 00875 // 2, 255, 0, 00876 // 8, 255, 0, 00877 // 14, 255, 0, 00878 // 20, 255, 0, 00879 // 26, 255, 0, 00880 // 32, 255, 0, 00881 // 38, 255, 0, 00882 // 44, 255, 0, 00883 // 50, 255, 0, 00884 // 56, 255, 0, 00885 // 62, 255, 0, 00886 // 68, 255, 0, 00887 // 74, 255, 0, 00888 // 80, 255, 0, 00889 // 86, 255, 0, 00890 // 92, 255, 0, 00891 // 98, 255, 0, 00892 // 104, 255, 0, 00893 // 110, 255, 0, 00894 // 116, 255, 0, 00895 // 122, 255, 0, 00896 // 128, 255, 0, 00897 // 133, 255, 0, 00898 // 139, 255, 0, 00899 // 145, 255, 0, 00900 // 151, 255, 0, 00901 // 157, 255, 0, 00902 // 163, 255, 0, 00903 // 169, 255, 0, 00904 // 175, 255, 0, 00905 // 181, 255, 0, 00906 // 187, 255, 0, 00907 // 193, 255, 0, 00908 // 199, 255, 0, 00909 // 205, 255, 0, 00910 // 211, 255, 0, 00911 // 217, 255, 0, 00912 // 223, 255, 0, 00913 // 229, 255, 0, 00914 // 235, 255, 0, 00915 // 241, 255, 0, 00916 // 247, 255, 0, 00917 // 253, 255, 0, 00918 // 255, 251, 0, 00919 // 255, 245, 0, 00920 // 255, 239, 0, 00921 // 255, 233, 0, 00922 // 255, 227, 0, 00923 // 255, 221, 0, 00924 // 255, 215, 0, 00925 // 255, 209, 0, 00926 // 255, 203, 0, 00927 // 255, 197, 0, 00928 // 255, 191, 0, 00929 // 255, 185, 0, 00930 // 255, 179, 0, 00931 // 255, 173, 0, 00932 // 255, 167, 0, 00933 // 255, 161, 0, 00934 // 255, 155, 0, 00935 // 255, 149, 0, 00936 // 255, 143, 0, 00937 // 255, 137, 0, 00938 // 255, 131, 0, 00939 // 255, 126, 0, 00940 // 255, 120, 0, 00941 // 255, 114, 0, 00942 // 255, 108, 0, 00943 // 255, 102, 0, 00944 // 255, 96, 0, 00945 // 255, 90, 0, 00946 // 255, 84, 0, 00947 // 255, 78, 0, 00948 // 255, 72, 0, 00949 // 255, 66, 0, 00950 // 255, 60, 0, 00951 // 255, 54, 0, 00952 // 255, 48, 0, 00953 // 255, 42, 0, 00954 // 255, 36, 0, 00955 // 255, 30, 0, 00956 // 255, 24, 0, 00957 // 255, 18, 0, 00958 // 255, 12, 0, 00959 // 255, 6, 0, 00960 // 255, 0, 0, 00961 // }; 00962 00963 // 00964 // IplImage *image = 0, *grey = 0, *prev_grey = 0, *pyramid = 0, *prev_pyramid = 0, *swap_temp; 00965 // 00966 // int win_size = 10; 00967 // const int MAX_COUNT = 500; 00968 // CvPoint2D32f* points[2] = {0,0}, *swap_points; 00969 // char* status = 0; 00970 // int count1 = 0; 00971 // int need_to_init = 0; 00972 // int night_mode = 0; 00973 // int flags = 0; 00974 // int add_remove_pt = 0; 00975 // CvPoint pt; 00976 // 00977 00978 00979 00980 #if NO_ROS 00981 int main( int argc, char** argv ) 00982 { 00983 if (argc == 1) 00984 { 00985 std::cerr << "Usage: " << argv[0] << " <images>" << std::endl; 00986 exit(0); 00987 } 00988 cv::namedWindow("tracker", 0); 00989 cv::namedWindow("tracker_temp", 0); 00990 00991 int num_images = argc - 1; 00992 int num_images_loaded = 0; 00993 IplImage** all_images = new IplImage*[num_images]; 00994 // for (int i = 0 ; i < num_images; i++){ 00995 // all_images[i] = cvLoadImage(argv[i+1]); 00996 // } 00997 00998 FeatureTracker ft; 00999 all_images[0] = cvLoadImage(argv[1]); 01000 num_images_loaded++; 01001 cv::Mat img(all_images[0]); 01002 ft.findCorners(img); 01003 01004 cv::imshow("tracker", ft.vis_image); 01005 cv::waitKey(); 01006 01007 int c; 01008 for (int i = 1 ; i < num_images; i++){ 01009 all_images[i] = cvLoadImage(argv[i+1]); 01010 num_images_loaded++; 01011 printf("loading image %s\n", argv[i+1]); 01012 cv::Mat img(all_images[i]); 01013 ft.tracking_step(img); 01014 01015 if( (i-1) % 5 == 0){ 01016 Timer t; 01017 ft.evluateTrajectories(); 01018 printf("took %f secs\n", t.stop()); 01019 cv::imshow("tracker", ft.vis_image); 01020 c = cvWaitKey(); 01021 if( (char)c == 27 ) 01022 break; 01023 } 01024 01025 } 01026 01027 for (int i = 0 ; i < num_images_loaded; i++){ 01028 cvReleaseImage(&all_images[i]); 01029 } 01030 delete [] all_images; 01031 01032 01033 } 01034 01035 #else 01036 01037 /*** 01038 * Main method to be run with PR2 robot 01039 */ 01040 01041 int main( int argc, char** argv ) 01042 { 01043 01044 ros::init(argc, argv, "image_tracker"); 01045 ros::NodeHandle nh; 01046 sensor_msgs::CvBridge _bridge; 01047 cv::namedWindow("tracker", 0); 01048 cv::namedWindow("tracker_temp", 0); 01049 01050 01051 std::string input_image_topic = 01052 argc == 2 ? argv[1] : "/camera/rgb/image_color"; 01053 01054 FeatureTracker ft; 01055 01056 sensor_msgs::ImageConstPtr imgmasg_ptr = ros::topic::waitForMessage<sensor_msgs::Image>("prosilica/image_rect_color", ros::Duration(5.0)); 01057 IplImage* ipl_img = _bridge.imgMsgToCv(imgmasg_ptr, "passthrough"); 01058 cv::Mat img(ipl_img); 01059 01060 ros::ServiceClient svc = nh.serviceClient<camera_self_filter::mask>("self_mask"); 01061 camera_self_filter::mask servicecall; 01062 servicecall.request.header.frame_id = "high_def_optical_frame"; 01063 servicecall.request.header.stamp = ros::Time::now(); 01064 svc.call(servicecall); 01065 sensor_msgs::ImageConstPtr maskptr = boost::make_shared<sensor_msgs::Image>(boost::ref(servicecall.response.mask_image)); 01066 01067 IplImage* ipl_mask = _bridge.imgMsgToCv(maskptr, "passthrough"); 01068 cvDilate(ipl_mask, ipl_mask, 0, 3); 01069 cvNot(ipl_mask,ipl_mask); 01070 cv::Mat mask(ipl_mask); 01071 01072 cv::Mat ROI_mat = cv::Mat::zeros(img.rows, img.cols, CV_8U); 01073 cv::rectangle(ROI_mat, cv::Point(0,0), cv::Point(img.cols-1, 1400),cv::Scalar(255,255,255,0), -1); 01074 01075 cv::resize(mask, mask, cv::Size(img.cols, img.rows), 0, 0, CV_INTER_NN); 01076 01077 cv::bitwise_and(ROI_mat,mask, mask); 01078 01079 01080 cv::imshow("tracker", mask); 01081 cv::waitKey(); 01082 01083 // ft.findCorners(img); 01084 ft.findCorners(img, &mask); 01085 01086 cv::imshow("tracker", ft.vis_image); 01087 cv::waitKey(); 01088 01089 int c; 01090 for ( ; ; ){ 01091 01092 sensor_msgs::ImageConstPtr imgmasg_ptr = ros::topic::waitForMessage<sensor_msgs::Image>("prosilica/image_rect_color", ros::Duration(5.0)); 01093 IplImage* ipl_img = _bridge.imgMsgToCv(imgmasg_ptr, "passthrough"); 01094 cv::Mat img(ipl_img); 01095 Timer t; 01096 ft.tracking_step(img); 01097 ft.evluateTrajectories(); 01098 printf("took %f secs\n", t.stop()); 01099 cv::imshow("tracker", ft.vis_image); 01100 c = cvWaitKey(); 01101 if( (char)c == 27 ) 01102 break; 01103 01104 } 01105 01106 return 0; 01107 01108 } 01109 01110 01111 #endif 01112 01113