matcher.cpp
Go to the documentation of this file.
00001 #include <custom_landmark_2d/matcher.h>
00002 
00003 #include <opencv2/highgui/highgui.hpp>
00004 #include <opencv2/imgproc/imgproc.hpp>
00005 #include <sensor_msgs/CameraInfo.h>
00006 #include <pcl/point_cloud.h>
00007 #include <pcl/point_types.h>
00008 #include <image_geometry/pinhole_camera_model.h>
00009 
00010 #include <stdlib.h>
00011 #include <assert.h> 
00012 
00013 using namespace std;
00014 using namespace cv;
00015 
00016 typedef pcl::PointXYZRGB PointC;
00017 typedef pcl::PointCloud<pcl::PointXYZRGB> PointCloudC;
00018 
00019 namespace custom_landmark_2d {
00020 
00021 Frame::Frame(const Point p1, const Point p2, const float score) : p1(p1), p2(p2), score(score) {}
00022 
00023 Matcher::Matcher() : match_method_(CV_TM_CCOEFF_NORMED),
00024                                          count_times(2),
00025                                          match_limit(0.68) {}
00026 
00027 void Matcher::set_template(const Mat& templ) {
00028         templ_ = templ;
00029 }
00030 
00031 void Matcher::set_cam_model(const sensor_msgs::CameraInfoConstPtr& camera_info) {
00032         cam_model_.fromCameraInfo(camera_info);
00033 }
00034 
00035 bool Matcher::Match(const Mat& rgb, const Mat& depth, vector<PointCloudC::Ptr>* object_clouds) {
00036 
00037         check_rgbd(rgb, depth);
00038 
00039         vector<Frame> lst;
00040 
00041     if (!Match(rgb, &lst)) return false; // no match found
00042 
00043     object_clouds->clear();
00044         
00045         PointCloudC::Ptr object_cloud;
00046 
00047         for (std::vector<Frame>::iterator f = lst.begin(); f != lst.end(); f++) {
00048 
00049                 object_cloud = PointCloudC::Ptr(new PointCloudC());
00050 
00051                 if (FrameToCloud(rgb, depth, *f, object_cloud)) {
00052                         object_clouds->push_back(object_cloud);
00053                 }
00054         }
00055 
00056         if (object_clouds->empty()) {
00057                 return false;
00058         }
00059         return true;
00060 }
00061 
00062 bool Matcher::FrameToCloud(const Mat& rgb, const Mat& depth, const Frame& f, PointCloudC::Ptr object_cloud) {
00063 
00064         check_rgbd(rgb, depth);
00065 
00066         object_cloud->clear();
00067 
00068         for(int i = f.p1.y + 1; i < f.p2.y; i++) {
00069                 for (int j = f.p1.x + 1; j < f.p2.x; j++) {
00070 
00071                         float dist = depth.at<float>(i, j);
00072 
00073                         if (!isnan(dist)) {
00074                                 cv::Vec3b color = rgb.at<cv::Vec3b>(i, j);
00075                                 cv::Point2d p_2d;
00076                                 p_2d.x = j;
00077                                 p_2d.y = i;
00078 
00079                                 cv::Point3d p_3d = cam_model_.projectPixelTo3dRay(p_2d);
00080 
00081                                 PointC pcl_point;
00082 
00083                                 pcl_point.x = p_3d.x * dist;
00084                                 pcl_point.y = p_3d.y * dist;
00085                                 pcl_point.z = p_3d.z * dist;
00086 
00087                                 // bgr
00088                                 pcl_point.b = static_cast<uint8_t> (color[0]);
00089                                 pcl_point.g = static_cast<uint8_t> (color[1]);
00090                                 pcl_point.r = static_cast<uint8_t> (color[2]);
00091 
00092                                 object_cloud->points.push_back(pcl_point);
00093                         }
00094                 }   
00095         }
00096 
00097         object_cloud->width = (int) object_cloud->points.size();
00098         object_cloud->height = 1;
00099 
00100         if (object_cloud->empty()) {
00101                 return false;
00102         }
00103         return true;
00104 }
00105 
00106 void Matcher::check_rgbd(const Mat& rgb, const Mat& depth) {
00107         // currently only support depth image encoding of CV_32FC1
00108         assert(depth.type() == CV_32FC1);
00109         assert(rgb.cols == depth.cols && rgb.rows == depth.rows);
00110 }
00111 
00112 bool Matcher::Match(const Mat& scene, vector<Frame>* lst) {
00113         
00114         lst->clear();
00115 
00116         int counter = count_times;
00117         Mat scaled_templ;
00118 
00119         // scale up
00120         double factor = 1.0 + 0.1 * count_times;
00121         while (counter > 0) {
00122 
00123                 resize(templ_, scaled_templ, Size(), factor, factor, INTER_LINEAR);
00124                 exact_match(scene, scaled_templ, lst);
00125 
00126                 factor -= 0.1;
00127                 counter--;
00128         }
00129 
00130         // original scale
00131         exact_match(scene, templ_, lst);
00132 
00133         // scale down
00134         counter = count_times;
00135         factor  = 0.9;
00136         while (counter > 0) {
00137 
00138                 resize(templ_, scaled_templ, Size(), factor, factor, INTER_AREA);
00139                 exact_match(scene, scaled_templ, lst);
00140 
00141                 factor -= 0.1;
00142                 counter--;
00143         }
00144 
00145         if (lst->empty()) {
00146                 return false;
00147         }
00148 
00149         return true;
00150 }
00151 
00152 // performs a single match on the given scene & scaled_templ
00153 void Matcher::exact_match(const Mat& scene, const Mat& scaled_templ, vector<Frame>* lst) {
00154 
00155         x_dist_ = (int) scaled_templ.cols;
00156         y_dist_ = (int) scaled_templ.rows;
00157 
00158         Mat result; // the result matrix
00159 
00160         int result_cols = scene.cols - scaled_templ.cols + 1;
00161         int result_rows = scene.rows - scaled_templ.rows + 1;
00162 
00163         result.create(result_rows, result_cols, CV_32FC1);
00164 
00165         // Do the Matching
00166         matchTemplate(scene, scaled_templ, result, match_method_);
00167 
00168         // scan through result to find all matching points
00169         int i,j;
00170         float* p;
00171         for( i = 0; i < result.rows; i++) {
00172                 p = result.ptr<float>(i);
00173                 for ( j = 0; j < result.cols; j++) {
00174                         if ( p[j] > match_limit) { // acceptable matching point
00175                                 Frame* f_ptr;
00176                                 if (around_frame(j, i, lst, &f_ptr)) {
00177                                         if (p[j] > f_ptr->score) { // current point has better score
00178 
00179                                                 f_ptr->p1 = Point(j, i);
00180                                                 f_ptr->p2 = Point(j + x_dist_, i + y_dist_);
00181                                 f_ptr->score = p[j];
00182                                 }
00183                         } else {
00184                                 lst->push_back(Frame(Point(j, i), Point(j + x_dist_, i + y_dist_), p[j]));
00185                         }
00186                 }
00187                 }
00188         }
00189 }
00190 
00191 // checks whether point(x, y) is around any frame in the vector, returns such frame if found
00192 bool Matcher::around_frame(int x, int y, vector<Frame>* lst, Frame** f_ptr_ptr) {
00193         if (lst->empty()) {
00194                 return false;
00195         }
00196 
00197         for (vector<Frame>::iterator f = lst->begin(); f != lst->end(); f++) {
00198                 if (around_point(x, y, f->p1)) {
00199                         *f_ptr_ptr = &(*f);
00200                         return true;
00201                 }
00202         }
00203         return false;
00204 }
00205 
00206 // checks whether point(x, y) is around point p using the current x_dist_ & y_dist_
00207 bool Matcher::around_point(int x, int y, Point& p) {
00208         if (abs(p.x - x) < x_dist_ && abs(p.y - y) < y_dist_) {
00209         return true;
00210         }
00211         return false;
00212 }
00213 
00214 }


custom_landmark_2d
Author(s):
autogenerated on Thu Jun 6 2019 18:35:43