flow_clustering.cpp
Go to the documentation of this file.
00001 class FlowClustering
00002 {
00003  public:
00004   FlowClustering(FeatureTracker* ft,
00005                     int kmeans_max_iter=200, double kmeans_epsilon=0.5,
00006                     int kmeans_tries=5, int affine_estimate_radius=5,
00007                     double surf_hessian=100) :
00008       ft_(ft),
00009       kmeans_max_iter_(kmeans_max_iter), kmeans_epsilon_(kmeans_epsilon),
00010       kmeans_tries_(kmeans_tries),
00011       affine_estimate_radius_(affine_estimate_radius)
00012   {
00013     // Create derivative kernels for flow calculation
00014     cv::getDerivKernels(dy_kernel_, dx_kernel_, 1, 0, CV_SCHARR, true, CV_32F);
00015     cv::flip(dy_kernel_, dy_kernel_, -1);
00016     cv::transpose(dy_kernel_, dx_kernel_);
00017   }
00018 
00019   AffineFlowMeasures clusterFlowFields(cv::Mat& color_img, cv::Mat& depth_img,
00020                                        cv::Mat& u, cv::Mat& v, cv::Mat& mask)
00021   {
00022     // return clusterFlowFieldsKMeans(color_img, depth_img, u, v, mask);
00023     return clusterSparseFlowKMeans(color_img, depth_img, u, v, mask);
00024   }
00025 
00026   AffineFlowMeasures clusterFlowFieldsKMeans(cv::Mat& color_img,
00027                                              cv::Mat& depth_img,
00028                                              cv::Mat& u, cv::Mat& v,
00029                                              cv::Mat& mask)
00030   {
00031     // Setup the samples as the flow vectors for the segmented moving region
00032     AffineFlowMeasures points;
00033     points.clear();
00034     for (int r = 0; r < mask.rows; ++r)
00035     {
00036       uchar* mask_row = mask.ptr<uchar>(r);
00037       for (int c = 0; c < mask.cols; ++c)
00038       {
00039         if ( mask_row[c] > 0)
00040         {
00041           AffineFlowMeasure p;
00042           p.u = u.at<float>(r,c);
00043           p.v = v.at<float>(r,c);
00044           p.x = c;
00045           p.y = r;
00046           p.a = estimateAffineTransform(u, v, r, c, affine_estimate_radius_);
00047           if (std::sqrt(p.u*p.u+p.v*p.v) > 1.0 )
00048             points.push_back(p);
00049         }
00050       }
00051     }
00052 
00053     if (points.size() < 1)
00054     {
00055       AffineFlowMeasures cluster_centers;
00056       cluster_centers.clear();
00057       return cluster_centers;
00058     }
00059     AffineFlowMeasures cluster_centers = clusterAffineKMeans(color_img, u, v,
00060                                                              points);
00061     return cluster_centers;
00062   }
00063 
00064   AffineFlowMeasures clusterFlowFieldsRANSAC(cv::Mat& color_img,
00065                                              cv::Mat& depth_img,
00066                                              cv::Mat& u, cv::Mat& v,
00067                                              cv::Mat& mask)
00068   {
00069     AffineFlowMeasures points;
00070     for (int r = 0; r < mask.rows; ++r)
00071     {
00072       uchar* mask_row = mask.ptr<uchar>(r);
00073       for (int c = 0; c < mask.cols; ++c)
00074       {
00075         if ( mask_row[c] > 0)
00076         {
00077           AffineFlowMeasure p;
00078           p.u = u.at<float>(r,c);
00079           p.v = v.at<float>(r,c);
00080           p.x = c;
00081           p.y = r;
00082           if (std::sqrt(p.u*p.u+p.v*p.v) > 1.0 )
00083             points.push_back(p);
00084         }
00085       }
00086     }
00087 
00088     AffineFlowMeasures cluster_centers;
00089     if (points.size() < 1)
00090     {
00091       cluster_centers.clear();
00092       return cluster_centers;
00093     }
00094 
00095     // Perform RANSAC itteratively on the affine estimates to cluster a set of
00096     // affine movement regions
00097     int k = 0;
00098     AffineFlowMeasures active_points = points;
00099     while (active_points.size() > min_affine_point_set_size_ &&
00100            k < max_k_)
00101     {
00102       AffineFlowMeasures inliers;
00103       inliers.clear();
00104       cv::Mat new_estimate = affineRANSAC(active_points, inliers,
00105                                           ransac_inlier_percent_est_,
00106                                           ransac_epsilon_, max_ransac_iters_);
00107       AffineFlowMeasure new_center;
00108       new_center.a = new_estimate;
00109       new_center.label = k;
00110       new_center.x = 0;
00111       new_center.y = 0;
00112       for (unsigned int i = 0; i < inliers.size(); ++i)
00113       {
00114         new_center.x += inliers[i].x;
00115         new_center.y += inliers[i].y;
00116 
00117         // Set labels for the removed points
00118         for (unsigned int j = 0; j < points.size(); ++j)
00119         {
00120           if (points[j] == inliers[i])
00121           {
00122             points[j].label = k;
00123           }
00124         }
00125         // Remove inliers from active points
00126         for (unsigned int j = 0; j < active_points.size(); )
00127         {
00128           if (inliers[i] == active_points[j])
00129           {
00130             active_points.erase(active_points.begin()+j);
00131           }
00132           else
00133           {
00134             ++j;
00135           }
00136         }
00137       }
00138       if (inliers.size() > 0)
00139       {
00140         new_center.x /= inliers.size();
00141         new_center.y /= inliers.size();
00142         cv::Mat V = new_center.a*new_center.X();
00143         new_center.u = V.at<float>(0,0);
00144         new_center.v = V.at<float>(1,0);
00145       }
00146       else
00147       {
00148         new_center.x = 0;
00149         new_center.y = 0;
00150         new_center.u = 0;
00151         new_center.v = 0;
00152       }
00153       cluster_centers.push_back(new_center);
00154       ROS_INFO_STREAM("Fit affine transform " << k << " with center ("
00155                       << new_center.x << ", " << new_center.y << ")");
00156       ROS_INFO_STREAM("Number of points remaining: " << active_points.size());
00157       ++k;
00158     }
00159 
00160 #ifdef DISPLAY_FLOW_FIELD_CLUSTERING
00161     // ROS_INFO_STREAM("Displaying clusters");
00162     displayClusterCenters(cluster_centers, points, color_img);
00163     // ROS_INFO_STREAM("Displayed clusters");
00164 #endif // DISPLAY_FLOW_FIELD_CLUSTERING
00165 
00166     return cluster_centers;
00167   }
00168 
00169   AffineFlowMeasures clusterSparseFlowKMeans(cv::Mat& color_img,
00170                                              cv::Mat& depth_img,
00171                                              cv::Mat& u, cv::Mat& v,
00172                                              cv::Mat& mask)
00173   {
00174     cv::Mat img_bw;
00175     cv::cvtColor(color_img, img_bw, CV_BGR2GRAY);
00176     // AffineFlowMeasures sparse_flow = ft_->updateTracks(img_bw, mask);
00177     AffineFlowMeasures sparse_flow = ft_->getMostRecentFlow();
00178     // TODO: Apply the mask to sparse_flow results
00179 
00180     // TODO: Try add in geometric matching here to complement the sparse feature
00181     // tracks
00182     for (unsigned int i = 0; i < sparse_flow.size(); ++i)
00183     {
00184       sparse_flow[i].a = estimateAffineTransform(u, v, sparse_flow[i].y,
00185                                                  sparse_flow[i].x,
00186                                                  affine_estimate_radius_);
00187     }
00188     AffineFlowMeasures cluster_centers;
00189     if (sparse_flow.size() < /*1*/ 2)
00190     {
00191       cluster_centers.clear();
00192       return cluster_centers;
00193     }
00194     cluster_centers = clusterAffineKMeans(color_img, u, v, sparse_flow);
00195     return cluster_centers;
00196   }
00197 
00198   AffineFlowMeasures clusterSparseFlowRANSAC(cv::Mat& color_img,
00199                                              cv::Mat& depth_img,
00200                                              cv::Mat& u, cv::Mat& v,
00201                                              cv::Mat& mask)
00202   {
00203     return clusterSparseFlowKMeans(color_img, depth_img, u, v, mask);
00204   }
00205 
00206   //
00207   // Core functions
00208   //
00209 
00210   AffineFlowMeasures clusterAffineKMeans(cv::Mat& color_img, cv::Mat& u,
00211                                          cv::Mat& v, AffineFlowMeasures& points)
00212   {
00213     const int num_samples = points.size();
00214     const int r_scale = color_img.cols / 2;
00215 
00216     const int num_sample_elements = 8;
00217 
00218     // Setup sample matrix for kmeans
00219     cv::Mat samples(num_samples, num_sample_elements, CV_32FC1);
00220     for (unsigned int i = 0; i < points.size(); ++i)
00221     {
00222       AffineFlowMeasure p = points[i];
00223       // TODO: This could be done better by reshaping p.a and setting it to a
00224       // submatrix of samples
00225       samples.at<float>(i, 0) = p.a.at<float>(0,0)*r_scale;
00226       samples.at<float>(i, 1) = p.a.at<float>(0,1)*r_scale;
00227       samples.at<float>(i, 2) = p.a.at<float>(0,2);
00228       samples.at<float>(i, 3) = p.a.at<float>(1,0)*r_scale;
00229       samples.at<float>(i, 4) = p.a.at<float>(1,1)*r_scale;
00230       samples.at<float>(i, 5) = p.a.at<float>(1,2);
00231       samples.at<float>(i, 6) = p.x;
00232       samples.at<float>(i, 7) = p.y;
00233     }
00234 
00235     std::vector<cv::Mat> labels;
00236     std::vector<cv::Mat> centers;
00237     double compactness[max_k_];
00238     cv::TermCriteria term_crit(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER,
00239                                kmeans_max_iter_, kmeans_epsilon_);
00240 
00241     AffineFlowMeasures cluster_centers;
00242     AffineFlowMeasures fewer_centers;
00243     AffineFlowMeasures best_centers;
00244     for (int K = 1; K <= min(max_k_, num_samples); ++K)
00245     {
00246       // Perform clustering with K centers
00247       cv::Mat labels_k;
00248       cv::Mat centers_k;
00249       double slack = cv::kmeans(samples, K, labels_k, term_crit,
00250                                 kmeans_tries_, cv::KMEANS_PP_CENTERS,
00251                                 centers_k);
00252       compactness[K-1] = slack;
00253       labels.push_back(labels_k);
00254       centers.push_back(centers_k);
00255       cluster_centers.clear();
00256       // Get descriptors for each cluster and compare them to the previous level
00257       for (int c = 0; c < K; ++c)
00258       {
00259         AffineFlowMeasure new_center;
00260         new_center.x = 0;
00261         new_center.y = 0;
00262         new_center.label = c;
00263         int num_members = 0;
00264         for (int i = 0; i < num_samples; ++i)
00265         {
00266           if (labels[K-1].at<uchar>(i,0) == c)
00267           {
00268             new_center.x += points[i].x;
00269             new_center.y += points[i].y;
00270             points[i].label = c;
00271             ++num_members;
00272           }
00273         }
00274 
00275         if (num_members <= 0 ||
00276             centers[K-1].cols == 0 || centers[K-1].rows == 0)
00277         {
00278           new_center.x = 0;
00279           new_center.y = 0;
00280           new_center.u = 0;
00281           new_center.v = 0;
00282         }
00283         else
00284         {
00285           new_center.x = new_center.x/num_members;
00286           new_center.y = new_center.y/num_members;
00287 
00288           // Correctly set the affine estimate
00289           // TODO: This could be done better by selecting a submatrix from centers
00290           // and then reshaping it
00291           new_center.a.create(2, 3, CV_32FC1);
00292           new_center.a.at<float>(0,0) = centers[K-1].at<float>(c,0) / r_scale;;
00293           new_center.a.at<float>(0,1) = centers[K-1].at<float>(c,1) / r_scale;;
00294           new_center.a.at<float>(0,2) = centers[K-1].at<float>(c,2);
00295           new_center.a.at<float>(1,0) = centers[K-1].at<float>(c,3) / r_scale;;
00296           new_center.a.at<float>(1,1) = centers[K-1].at<float>(c,4) / r_scale;;
00297           new_center.a.at<float>(1,2) = centers[K-1].at<float>(c,5);
00298 
00299           // Estimate flow of the cluster center using affine transform estimate
00300           cv::Mat V = new_center.a*new_center.X();
00301           new_center.u = V.at<float>(0,0);
00302           new_center.v = V.at<float>(1,0);
00303         }
00304         cluster_centers.push_back(new_center);
00305       }
00306       // Compare current K centers to centers of cardinality K-1
00307       if (K > 1)
00308       {
00309         float farthest_nearest_neighbor = 0;
00310         for (unsigned int i = 0; i < cluster_centers.size(); ++i)
00311         {
00312           float nn = FLT_MAX;
00313           for (unsigned int j = 0; j < fewer_centers.size(); ++j)
00314           {
00315             float dist = cluster_centers[i] - fewer_centers[j];
00316             if (dist < nn)
00317               nn = dist;
00318           }
00319           if (nn > farthest_nearest_neighbor)
00320             farthest_nearest_neighbor = nn;
00321         }
00322         // If no new clusters have center far enough from the current clusters,
00323         // Then we choose the previous set as best
00324         if (farthest_nearest_neighbor < minimum_new_cluster_separation_)
00325         {
00326           best_centers = fewer_centers;
00327           break;
00328         }
00329       }
00330       // Store current estimates for comparing in next iteration of K
00331       fewer_centers = cluster_centers;
00332       best_centers = cluster_centers;
00333     }
00334     ROS_INFO_STREAM("Chose " << best_centers.size() << " clusters");
00335 #ifdef DISPLAY_FLOW_FIELD_CLUSTERING
00336     displayClusterCenters(best_centers, points, color_img, 0);
00337 #endif // DISPLAY_FLOW_FIELD_CLUSTERING
00338     return best_centers;
00339   }
00340 
00341   cv::Mat estimateAffineTransform(cv::Mat& u, cv::Mat& v,
00342                                   const int r, const int c, const int radius)
00343   {
00344     const int r_min = max(r - radius, 0);
00345     const int r_max = min(r + radius, u.rows-1);
00346     const int c_min = max(c - radius, 0);
00347     const int c_max = min(c + radius, u.cols-1);
00348     const int r_range = r_max-r_min+1;
00349     const int c_range = c_max-c_min+1;
00350     const int num_eqs = r_range*c_range*2;
00351     cv::Mat a(6, 1, CV_32FC1, cv::Scalar(1.0));
00352     if (num_eqs < 6)
00353     {
00354       ROS_WARN_STREAM("Too few equations; num equations is: " << num_eqs);
00355       cv::Mat A = a.reshape(1, 2);
00356       return A;
00357     }
00358     cv::Mat phi(num_eqs, 6, CV_32FC1, cv::Scalar(0.0));
00359     cv::Mat V(num_eqs, 1, CV_32FC1, cv::Scalar(0.0));
00360     for (int r = r_min, out_row = 0; r <= r_max; ++r)
00361     {
00362       for (int c = c_min; c <= c_max; ++c, ++out_row)
00363       {
00364         phi.at<float>(out_row, 0) = r;
00365         phi.at<float>(out_row, 1) = c;
00366         phi.at<float>(out_row, 2) = 1.0;
00367         V.at<float>(out_row, 0) = u.at<float>(r,c);
00368         ++out_row;
00369         phi.at<float>(out_row, 3) = r;
00370         phi.at<float>(out_row, 4) = c;
00371         phi.at<float>(out_row, 5) = 1.0;
00372         V.at<float>(out_row, 0) = v.at<float>(r,c);
00373       }
00374     }
00375     try
00376     {
00377       cv::solve(phi, V, a, cv::DECOMP_SVD);
00378     }
00379     catch (cv::Exception cve)
00380     {
00381       ROS_ERROR_STREAM(cve.what());
00382     }
00383     cv::Mat A = a.reshape(1, 2);
00384     return A;
00385   }
00386 
00387   cv::Mat estimateAffineTransform(AffineFlowMeasures& points)
00388   {
00389     const int num_eqs = points.size()*2;
00390     cv::Mat phi(num_eqs, 6, CV_32FC1, cv::Scalar(0.0));
00391     cv::Mat V(num_eqs, 1, CV_32FC1, cv::Scalar(0.0));
00392     cv::Mat a(6, 1, CV_32FC1, cv::Scalar(1.0));
00393     if (num_eqs < 6)
00394     {
00395       ROS_WARN_STREAM("Too few equations; num equations is: " << num_eqs);
00396       cv::Mat A = a.reshape(1, 2);
00397       return A;
00398     }
00399     for (unsigned int i = 0, out_row = 0; i < points.size(); ++i, ++out_row)
00400     {
00401       AffineFlowMeasure p = points[i];
00402       phi.at<float>(out_row, 0) = p.y;
00403       phi.at<float>(out_row, 1) = p.x;
00404       phi.at<float>(out_row, 2) = 1.0;
00405       V.at<float>(out_row, 0) = p.u;
00406       ++out_row;
00407       phi.at<float>(out_row, 3) = p.y;
00408       phi.at<float>(out_row, 4) = p.x;
00409       phi.at<float>(out_row, 5) = 1.0;
00410       V.at<float>(out_row, 0) = p.v;
00411     }
00412     cv::solve(phi, V, a, cv::DECOMP_SVD);
00413     cv::Mat A = a.reshape(1, 2);
00414     return A;
00415   }
00416 
00425   float getAffineDistortion(AffineFlowMeasure f, cv::Mat A)
00426   {
00427     cv::Mat X(3, 1, CV_32FC1, cv::Scalar(1.0));
00428     X.at<float>(0,0) = f.x;
00429     X.at<float>(1,0) = f.y;
00430 
00431     cv::Mat V(2, 1, CV_32FC1, cv::Scalar(1.0));
00432     V.at<float>(0,0) = f.u;
00433     V.at<float>(0,0) = f.v;
00434 
00435     cv::Mat d = V - A*X;
00436     return d.at<float>(0,0)*d.at<float>(0,0)+d.at<float>(1,0)*d.at<float>(1,0);
00437   }
00438 
00448   AffineFlowMeasures getAffineConsensus(AffineFlowMeasures points,
00449                                         cv::Mat cur_transform, float epsilon)
00450   {
00451     AffineFlowMeasures inliers;
00452     for (unsigned int i = 0; i < points.size(); ++i)
00453     {
00454       float score = getAffineDistortion(points[i], cur_transform);
00455       if (score < epsilon)
00456       {
00457         inliers.push_back(points[i]);
00458       }
00459     }
00460     return inliers;
00461   }
00462 
00475   cv::Mat affineRANSAC(AffineFlowMeasures& points, AffineFlowMeasures& inliers,
00476                        float inlier_percent_est, float epsilon,
00477                        int max_iterations=0, int min_iterations = 2)
00478   {
00479     AffineFlowMeasures sample_points;
00480     AffineFlowMeasures cur_inliers;
00481     AffineFlowMeasures best_inliers;
00482     best_inliers.clear();
00483     bool done;
00484     int iter = 0;
00485 
00486     // Compute max_iterations as function of inlier percetage
00487     if (max_iterations == 0)
00488     {
00489       // Percent certainty
00490       const float p = 0.99;
00491       // Number of model parameters
00492       const float s = 3.0f;
00493       max_iterations = log(1 - p) / log(1-pow(inlier_percent_est, s));
00494     }
00495 
00496     while ( !done )
00497     {
00498       // Randomly select 3 points
00499       sample_points.clear();
00500       for (int i = 0; i < 3; ++i)
00501       {
00502         int r_idx = (rand() % (points.size()+1));
00503         sample_points.push_back(points[r_idx]);
00504       }
00505       // Estimate affine flow from them
00506       cv::Mat cur_transform = estimateAffineTransform(sample_points);
00507       cur_inliers = getAffineConsensus(points, cur_transform, epsilon);
00508       // Update best estimate if we have more points
00509       if ( best_inliers.size() < cur_inliers.size() )
00510       {
00511         best_inliers = cur_inliers;
00512       }
00513       // Check if sampling should stop
00514       iter++;
00515       done = ((iter > min_iterations &&
00516                (static_cast<float>(best_inliers.size())/points.size() >
00517                 inlier_percent_est ||
00518                 best_inliers.size() > inlier_percent_est*points.size() )) ||
00519                iter > max_iterations);
00520     }
00521     inliers = best_inliers;
00522     return estimateAffineTransform(inliers);
00523   }
00524 
00525   //
00526   // Helper Functions
00527   //
00528 
00536   void displayClusterCenters(AffineFlowMeasures& cluster_centers,
00537                              AffineFlowMeasures& samples,
00538                              cv::Mat& color_img, int cur_max_k=0)
00539   {
00540     cv::Mat flow_center_disp = color_img.clone();
00541     for (unsigned int i = 0; i < cluster_centers.size(); ++i)
00542     {
00543       cv::Point pt_a(cluster_centers[i].x, cluster_centers[i].y);
00544       cv::Point pt_b(pt_a.x - cluster_centers[i].u,
00545                      pt_a.y - cluster_centers[i].v);
00546       cv::circle(flow_center_disp, pt_a, 20, cv::Scalar(0,255,0));
00547       cv::line(flow_center_disp, pt_a, pt_b, cv::Scalar(0,255,0));
00548     }
00549     std::stringstream center_disp_name;
00550     center_disp_name << "Flow Cluster Centers";
00551     if (cur_max_k != 0) center_disp_name << " " << cur_max_k;
00552     cv::imshow(center_disp_name.str(), flow_center_disp);
00553     cv::Mat flow_clusters_disp = color_img.clone();
00554     std::vector<cv::Scalar> colors;
00555     for (unsigned int k = 0; k < cluster_centers.size(); ++k)
00556     {
00557       cv::Scalar rand_color;
00558       rand_color[0] = (static_cast<float>(rand()) /
00559                        static_cast<float>(RAND_MAX))*255;
00560       rand_color[1] = (static_cast<float>(rand()) /
00561                        static_cast<float>(RAND_MAX))*255;
00562       rand_color[2] = (static_cast<float>(rand()) /
00563                        static_cast<float>(RAND_MAX))*255;
00564       colors.push_back(rand_color);
00565     }
00566     for (unsigned int i = 0; i < samples.size(); ++i)
00567     {
00568       AffineFlowMeasure s = samples[i];
00569       if (s.label < 0 || s.label > (cluster_centers.size()-1)) continue;
00570       if (std::sqrt(s.u*s.u+s.v*s.v) > 1.0)
00571       {
00572         cv::Scalar cur_color = colors[s.label];
00573         cv::line(flow_clusters_disp, cv::Point(s.x, s.y),
00574                  cv::Point(s.x - s.u, s.y - s.v), cur_color);
00575       }
00576     }
00577     std::stringstream cluster_disp_name;
00578     cluster_disp_name << "Flow Clusters";
00579     if (cur_max_k != 0) cluster_disp_name << " " << cur_max_k;
00580     cv::imshow(cluster_disp_name.str(), flow_clusters_disp);
00581   }
00582 
00583   //
00584   // Class member variables
00585   //
00586  protected:
00587   cv::Mat dx_kernel_;
00588   cv::Mat dy_kernel_;
00589   cv::Mat g_kernel_;
00590   FeatureTracker* ft_;
00591  public:
00592   int kmeans_max_iter_;
00593   double kmeans_epsilon_;
00594   double ransac_epsilon_;
00595   double ransac_inlier_percent_est_;
00596   int kmeans_tries_;
00597   int max_k_;
00598   int affine_estimate_radius_;
00599   int min_affine_point_set_size_;
00600   int max_ransac_iters_;
00601   double minimum_new_cluster_separation_;
00602 };


tabletop_pushing
Author(s): Tucker Hermans
autogenerated on Wed Nov 27 2013 11:59:44