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;
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
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
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
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
00131 exact_match(scene, templ_, lst);
00132
00133
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
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;
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
00166 matchTemplate(scene, scaled_templ, result, match_method_);
00167
00168
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) {
00175 Frame* f_ptr;
00176 if (around_frame(j, i, lst, &f_ptr)) {
00177 if (p[j] > f_ptr->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
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
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 }