processed_image.cpp
Go to the documentation of this file.
00001 /*
00002  *  This file is part of ucl_drone 2016.
00003  *  For more information, refer
00004  *  to the corresponding header file.
00005  *
00006  *  \author Arnaud Jacques & Alexandre Leclere
00007  *  \date 2016
00008  *
00009  *  based on tuto:
00010  *  http://wiki.ros.org/cv_bridge/Tutorials/UsingCvBridgeToConvertBetweenROSImagesAndOpenCVImages
00011  */
00012 
00013 #include <ucl_drone/computer_vision/computer_vision.h>
00014 
00015 int ProcessedImage::last_number_of_keypoints = 0;
00016 
00017 // Contructor for the empty object
00018 ProcessedImage::ProcessedImage()
00019 {
00020   ucl_drone::ProcessedImageMsg::Ptr msg(new ucl_drone::ProcessedImageMsg());
00021 }
00022 
00023 // Constructor
00024 // [in] msg: ROS Image message sent by the camera
00025 // [in] pose_: Pose3D message before visual estimation to be attached with the processed image
00026 // [in] prev: previous processed image used for keypoints tracking
00027 // [in] use_OpticalFlowPyrLK: flag to enable keypoints tracking
00028 ProcessedImage::ProcessedImage(const sensor_msgs::Image msg, const ucl_drone::Pose3D pose_,
00029                                ProcessedImage& prev, bool use_OpticalFlowPyrLK)
00030 {
00031   ROS_DEBUG("ProcessedImage::init");
00032   this->pose = pose_;
00033 
00034   // convert ROS image to OpenCV image
00035   try
00036   {
00037     this->cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8);
00038     // ROS_DEBUG("ProcessedImage::init: the size of the corrected image is: %d, %d",
00039     // cv_ptr->image.rows, cv_ptr->image.cols);
00040   }
00041   catch (cv_bridge::Exception& e)
00042   {
00043     ROS_ERROR("ucl_drone::imgproc::cv_bridge exception: %s", e.what());
00044     return;
00045   }
00046 
00047   // Resize the image according to the parameters in the launch file
00048   cv::Size size(Read::img_width(), Read::img_height());
00049   cv::resize(this->cv_ptr->image, this->cv_ptr->image, size);
00050 
00051   // Convert opencv image to ROS Image message format
00052   this->cv_ptr->toImageMsg(this->image);
00053 
00054   // Use keypoints tracking between the previous and the current image processed
00055   if (use_OpticalFlowPyrLK && prev.cv_ptr && prev.keypoints.size() > 0 &&
00056       ProcessedImage::last_number_of_keypoints != 0)  // performs only if the previous image
00057                                                       // processed is not empty and if keypoints
00058                                                       // were detected
00059   {
00060     ROS_DEBUG("use_OpticalFlowPyrLK");
00061     TIC(optical_flow);
00062     bool OF_success = false;  // flag which indicates the success of keypoints tracking
00063 
00064     // If the picture is in colours, convert it to grayscale
00065     cv::Mat prevgray, gray;
00066     if (this->cv_ptr->image.channels() == 3)
00067     {
00068       cv::cvtColor(this->cv_ptr->image, gray, CV_RGB2GRAY);
00069       cv::cvtColor(prev.cv_ptr->image, prevgray, CV_RGB2GRAY);
00070     }
00071     else
00072     {
00073       prevgray = prev.cv_ptr->image;
00074       gray = this->cv_ptr->image;
00075     }
00076 
00077     // Prepare structures to receive keypoints tracking results
00078     std::vector< uchar > vstatus(prev.keypoints.size());
00079     std::vector< float > verror(prev.keypoints.size());
00080 
00081     std::vector< cv::Point2f > found;
00082     std::vector< cv::Point2f > to_find = Points(prev.keypoints);
00083 
00084     // Perform keypoints tracking
00085     cv::calcOpticalFlowPyrLK(prevgray, gray, to_find, found, vstatus, verror);
00086 
00087     // Copy all keypoints tracked with success
00088     double thres = 12.0;
00089 
00090     for (int i = 0; i < prev.keypoints.size(); i++)
00091     {
00092       if (vstatus[i] && verror[i] < thres)
00093       {
00094         cv::KeyPoint newKeyPoint = prev.keypoints[i];
00095         newKeyPoint.pt.x = found[i].x;
00096         newKeyPoint.pt.y = found[i].y;
00097         this->keypoints.push_back(newKeyPoint);
00098       }
00099     }
00100 
00101     // Determine if enough keypoints were detected or if new keypoints detection is needed
00102     OF_success = this->keypoints.size() > ProcessedImage::last_number_of_keypoints * 0.75 &&
00103                  this->keypoints.size() > 80;
00104     TOC(optical_flow, "optical flow tracking");
00105 
00106     if (OF_success)  // then simply copy all descriptors previously computed
00107     {
00108       this->descriptors = cv::Mat::zeros(this->keypoints.size(), DESCRIPTOR_SIZE, CV_32F);
00109       for (int i = 0, j = 0; i < prev.keypoints.size(); i++)
00110       {
00111         if (vstatus[i] && verror[i] < thres)
00112         {
00113           for (unsigned k = 0; k < DESCRIPTOR_SIZE; k++)
00114           {
00115             this->descriptors.at< float >(j, k) = prev.descriptors.at< float >(i, k);
00116           }
00117           j++;
00118         }
00119       }
00120       // KEYPOINTS TRACKING SUCCESS, no more computation needed
00121       return;
00122     }
00123     else
00124     {
00125       this->keypoints.clear();
00126     }
00127   }
00128 
00129   ROS_DEBUG("=== OPTICAL FLOW NOT SUCCESS ===");
00130 
00131   // Keypoints detection for current image
00132   TIC(detect);
00133   detector.detect(this->cv_ptr->image, this->keypoints);
00134   TOC(detect, "detect keypoints");
00135   ROS_DEBUG("ProcessedImage::init this->keypoints.size()=%d", this->keypoints.size());
00136   ProcessedImage::last_number_of_keypoints = this->keypoints.size();
00137   if (this->keypoints.size() == 0)
00138   {
00139     return;
00140   }
00141   TIC(extract);
00142   // Perform keypoints description
00143   extractor.compute(this->cv_ptr->image, this->keypoints, this->descriptors);
00144   TOC(extract, "descriptor extrator");
00145   ROS_DEBUG("end ProcessedImage::init");
00146 }
00147 
00148 ProcessedImage::~ProcessedImage()
00149 {
00150 }
00151 
00152 // This function fill the message that will be sent by the computer vision node
00153 // [out] msg: the filled message
00154 // [in] target: the object to perform target detection
00155 void ProcessedImage::convertToMsg(ucl_drone::ProcessedImageMsg::Ptr& msg, Target target)
00156 {
00157   msg->pose = this->pose;
00158   msg->image = this->image;
00159 
00160   if (this->keypoints.size() == 0)
00161   {
00162     return;
00163   }
00164 
00165   TIC(target);
00166   // Prepare structures for target detection
00167   std::vector< cv::DMatch > good_matches;
00168   std::vector< int > idxs_to_remove;
00169   std::vector< cv::Point2f > target_coord;
00170   // Perform target detection
00171   bool target_is_detected =
00172       target.detect(this->descriptors, this->keypoints, good_matches, idxs_to_remove, target_coord
00173 #ifdef DEBUG_PROJECTION
00174                     ,
00175                     this->pose
00176 #endif /* DEBUG_PROJECTION */
00177 #ifdef DEBUG_TARGET
00178                     ,
00179                     this->cv_ptr->image
00180 #endif /* DEBUG_TARGET */
00181                     );
00182 
00183   if (target_is_detected)
00184   {
00185     ROS_DEBUG("TARGET IS DETECTED");
00186     msg->target_detected = true;
00187     // Copy target center and corners position in the picture coordinates
00188     msg->target_points.resize(5);
00189     for (int i = 0; i < 5; i++)
00190     {
00191       msg->target_points[i].x = target_coord[i].x;
00192       msg->target_points[i].y = target_coord[i].y;
00193       msg->target_points[i].z = 0;
00194     }
00195   }
00196   else
00197   {
00198     msg->target_detected = false;
00199   }
00200 
00201   if (this->keypoints.size() - idxs_to_remove.size() <= 0)
00202   {
00203     // All keypoints are on the target
00204     return;
00205   }
00206 
00207   // Remove keypoints on the target
00208   msg->keypoints.resize(this->keypoints.size() - idxs_to_remove.size());
00209   ROS_DEBUG("ProcessedImage::init msg->keypoints.size()=%d", msg->keypoints.size());
00210   int count = 0;
00211   int j = 0;
00212   for (unsigned i = 0; i < this->keypoints.size() && j < msg->keypoints.size() &&
00213                        (count < idxs_to_remove.size() || idxs_to_remove.size() == 0);
00214        i++)
00215   {
00216     // exclude target points from message to send (to avoid mapping of moving target)
00217     if (idxs_to_remove.size() == 0 || i != idxs_to_remove[count])
00218     {
00219       // Copy the current keypoint position
00220       ucl_drone::KeyPoint keypoint;
00221       geometry_msgs::Point point;
00222       point.x = (double)this->keypoints[i].pt.x;
00223       point.y = (double)this->keypoints[i].pt.y;
00224 
00225       keypoint.point = point;
00226 
00227       // Copy the current keypoint description
00228       std::vector< float > descriptor;
00229       descriptor.resize(DESCRIPTOR_SIZE);
00230       for (unsigned k = 0; k < DESCRIPTOR_SIZE; k++)
00231       {
00232         descriptor[k] = this->descriptors.at< float >(i, k);
00233       }
00234       keypoint.descriptor = descriptor;
00235 
00236       msg->keypoints[j] = keypoint;
00237       j++;
00238     }
00239     if (idxs_to_remove.size() != 0 && i == idxs_to_remove[count])
00240     {
00241       // this way of doing is possible since idxs_to_remove are sorted in increasing order
00242       if (count < idxs_to_remove.size() - 1)
00243       {
00244         count++;
00245       }
00246     }
00247   }
00248   TOC(target, "detect and remove target");
00249   ROS_DEBUG("=========== POINT (%f;%f)", msg->keypoints[msg->keypoints.size() - 1].point.x,
00250             msg->keypoints[msg->keypoints.size() - 1].point.y);
00251 }


ucl_drone
Author(s): dronesinma
autogenerated on Sat Jun 8 2019 20:51:53