object_detection.cpp
Go to the documentation of this file.
00001 #include <stdio.h>
00002 #include <iostream>
00003 #include <cstdio> 
00004 #include <boost/filesystem.hpp>
00005 
00006 #include <image_transport/image_transport.h>
00007 #include <cv_bridge/cv_bridge.h>
00008 #include <sensor_msgs/image_encodings.h>
00009 
00010 #include "opencv2/core/core.hpp"
00011 #include "opencv2/features2d/features2d.hpp"
00012 #include "opencv2/highgui/highgui.hpp"
00013 #include "opencv2/calib3d/calib3d.hpp"
00014 #include "opencv2/nonfree/nonfree.hpp"
00015 
00016 #include "opencv2/objdetect/objdetect.hpp"
00017 #include "opencv2/imgproc/imgproc.hpp"
00018 
00019 #include "ros/ros.h"
00020 #include "std_msgs/String.h"
00021 
00022 #include "bwi_scavenger/ObjectDetection.h"
00023 
00024 using namespace cv;
00025 
00026 cv_bridge::CvImageConstPtr cv_ptr;
00027 Mat frame;
00028 
00029 std::string file, name, directory; 
00030 std::string default_dir = "/home/bwi/shiqi/";
00031 
00032 
00033 void callback(const sensor_msgs::ImageConstPtr& msg) 
00034 {
00035     cv_ptr = cv_bridge::toCvShare(msg, sensor_msgs::image_encodings::BGR8); 
00036     frame = cv_ptr->image;
00037 }
00038 
00039 
00040 bool callback_detection(bwi_scavenger::ObjectDetection::Request &req, 
00041     bwi_scavenger::ObjectDetection::Response &res) {
00042 
00043     file  = req.path_to_template; 
00044     Mat img_object = imread(file, CV_LOAD_IMAGE_GRAYSCALE );
00045     if(! img_object.data )
00046         ROS_ERROR("No template image is provided for object detection"); 
00047 
00048     cv_ptr.reset (new cv_bridge::CvImage);
00049 
00050     //-- Step 1: Detect the keypoints using SURF Detector
00051     int minHessian = 400;
00052     SurfFeatureDetector detector( minHessian );
00053     std::vector<KeyPoint> keypoints_object, keypoints_frame;
00054 
00055     detector.detect( img_object, keypoints_object );
00056 
00057     //-- Step 2: Calculate descriptors (feature vectors)
00058     SurfDescriptorExtractor extractor;
00059     Mat descriptors_object, descriptors_frame;
00060 
00061     extractor.compute( img_object, keypoints_object, descriptors_object );
00062 
00063     //-- Step 3: Matching descriptor vectors using FLANN matcher
00064     FlannBasedMatcher matcher;
00065     std::vector< DMatch > matches;
00066 
00067     // namedWindow("WindowName", CV_WINDOW_AUTOSIZE);
00068 
00069     int cnt = 0;
00070 
00071     ros::param::param<std::string>("~name", name, "NAME");
00072 
00073     while (ros::ok()) {
00074 
00075         ros::spinOnce();
00076 
00077         if (frame.empty()) {
00078           ROS_WARN("frame empty");
00079           ros::Duration(0.1).sleep(); 
00080           ros::spinOnce();
00081           continue;
00082         }
00083 
00084         detector.detect(frame, keypoints_frame);
00085         extractor.compute(frame, keypoints_frame, descriptors_frame);
00086         // Finds the best match for each descriptor from a query set.
00087         matcher.match(descriptors_object, descriptors_frame, matches);
00088 
00089         //-- Quick calculation of max and min distances between keypoints
00090         double max_dist = 0; double min_dist = 100;
00091 
00092         for( int i = 0; i < descriptors_object.rows; i++ )
00093         { double dist = matches[i].distance;
00094           if( dist < min_dist ) min_dist = dist;
00095           if( dist > max_dist ) max_dist = dist;
00096         }
00097         // printf("-- Max dist : %f \n", max_dist );
00098         // printf("-- Min dist : %f \n", min_dist );
00099 
00100         //-- Draw only "good" matches (i.e. whose distance is less than 3*min_dist )
00101         std::vector< DMatch > good_matches;
00102 
00103         for( int i = 0; i < descriptors_object.rows; i++ )
00104         { if( matches[i].distance < 3*min_dist )
00105            { good_matches.push_back( matches[i]); }
00106         }
00107 
00108         Mat img_matches;
00109         drawMatches( img_object, keypoints_object, frame, keypoints_frame,
00110                      good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
00111                      vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
00112 
00113         //-- Localize the object
00114         std::vector<Point2f> obj;
00115         std::vector<Point2f> scene;
00116 
00117         for( int i = 0; i < good_matches.size(); i++ )
00118         {
00119           //-- Get the keypoints from the good matches
00120           obj.push_back( keypoints_object[ good_matches[i].queryIdx ].pt );
00121           scene.push_back( keypoints_frame[ good_matches[i].trainIdx ].pt );
00122         }
00123 
00124         if (obj.size() < 4 || scene.size() < 4) 
00125           continue;
00126 
00127         Mat H = findHomography( obj, scene, CV_RANSAC );
00128 
00129         //-- Get the corners from the image_1 ( the object to be "detected" )
00130         std::vector<Point2f> obj_corners(4);
00131         obj_corners[0] = cvPoint(0,0); obj_corners[1] = cvPoint( img_object.cols, 0 );
00132         obj_corners[2] = cvPoint( img_object.cols, img_object.rows ); 
00133         obj_corners[3] = cvPoint( 0, img_object.rows );
00134         std::vector<Point2f> scene_corners(4);
00135 
00136         perspectiveTransform( obj_corners, scene_corners, H);
00137 
00138         //-- Draw lines between the corners (the mapped object in the scene - image_2 )
00139         line( img_matches, scene_corners[0] + Point2f( img_object.cols, 0), 
00140               scene_corners[1] + Point2f( img_object.cols, 0), 
00141               Scalar(0, 255, 0), 4 );
00142         line( img_matches, scene_corners[1] + Point2f( img_object.cols, 0), 
00143               scene_corners[2] + Point2f( img_object.cols, 0), 
00144               Scalar( 0, 255, 0), 4 );
00145         line( img_matches, scene_corners[2] + Point2f( img_object.cols, 0), 
00146               scene_corners[3] + Point2f( img_object.cols, 0), 
00147               Scalar( 0, 255, 0), 4 );
00148         line( img_matches, scene_corners[3] + Point2f( img_object.cols, 0), 
00149               scene_corners[0] + Point2f( img_object.cols, 0), 
00150               Scalar( 0, 255, 0), 4 );
00151 
00152         float dis = 0.0;
00153         dis += norm( (scene_corners[0] + Point2f( img_object.cols, 0)) - 
00154                      (scene_corners[1] + Point2f( img_object.cols, 0)) );
00155         dis += norm( (scene_corners[1] + Point2f( img_object.cols, 0)) - 
00156                      (scene_corners[2] + Point2f( img_object.cols, 0)) );
00157         dis += norm( (scene_corners[2] + Point2f( img_object.cols, 0)) - 
00158                      (scene_corners[3] + Point2f( img_object.cols, 0)) );
00159         dis += norm( (scene_corners[3] + Point2f( img_object.cols, 0)) - 
00160                      (scene_corners[0] + Point2f( img_object.cols, 0)) );
00161      
00162         //-- Show detected matches
00163 
00164         if (dis > 500)
00165           cnt++;
00166         else
00167           cnt = 0;
00168 
00169         ros::param::param<std::string>("~directory", directory, default_dir);
00170         if (boost::filesystem::is_directory(directory) == false)
00171             boost::filesystem::create_directory(directory);
00172         std::string file_object = directory + "object_matched.jpg"; 
00173         if (cnt >= 5) {
00174             imwrite(file_object, frame);
00175             res.path_to_image = file_object; 
00176             return true;
00177         }
00178 
00179         imshow( "WindowName", img_matches );
00180         waitKey(1);
00181 
00182     }
00183 
00184     destroyAllWindows(); 
00185 
00186     return true;
00187 }
00188 
00189 int main(int argc, char **argv) {
00190     
00191     ros::init(argc, argv, "object_detection_server");
00192     ros::NodeHandle nh;
00193 
00194     
00195     ros::Subscriber sub = nh.subscribe("/nav_kinect/rgb/image_color", 1, callback);
00196     ros::ServiceServer service = nh.advertiseService("object_detection_service", 
00197         callback_detection); 
00198 
00199     ros::Rate r(10);
00200     ros::Duration(2.0).sleep();
00201 
00202     ros::spin(); 
00203     
00204     return true; 
00205 }


bwi_scavenger
Author(s): Shiqi Zhang
autogenerated on Thu Jun 6 2019 17:57:53