imagesift.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
2 // vim: tabstop=4 shiftwidth=4:
3 // Copyright (C) 2008 Rosen Diankov (rdiankov@cs.cmu.edu)
4 //
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "imagesift/imagesift.h"
18 #include <ros/node_handle.h>
19 #include <sensor_msgs/Image.h>
20 #include <sensor_msgs/CameraInfo.h>
21 #include <posedetection_msgs/ImageFeature0D.h>
22 #include <posedetection_msgs/Feature0DDetect.h>
25 #if ( CV_MAJOR_VERSION >= 4)
26 #include <opencv2/highgui.hpp>
27 #else
28 #include <opencv/highgui.h>
29 #include <opencv/cv.h>
30 #endif
31 
32 #include <boost/shared_ptr.hpp>
33 #include <boost/thread/mutex.hpp>
34 #include <map>
35 #include <string>
36 #include <cstdio>
37 #include <vector>
38 
39 #include <cv_bridge/cv_bridge.h>
41 #include <siftfast/siftfast.h>
42 
47 
48 using namespace std;
49 using namespace ros;
50 
51 namespace imagesift
52 {
53  void SiftNode::onInit()
54  {
55  DiagnosticNodelet::onInit();
56  // First positional argument is the transport type
57  std::string transport;
58  pnh_->param("image_transport", transport, std::string("raw"));
59  ROS_INFO_STREAM("Using transport \"" << transport << "\" for " << pnh_->getNamespace());
60  _it.reset(new image_transport::ImageTransport(*nh_));
61  _hints = image_transport::TransportHints(transport, ros::TransportHints(), *pnh_);
62 
63  pnh_->param("use_mask", _useMask, false);
64 
65  _pubFeatures = advertise<posedetection_msgs::Feature0D>(*nh_, "Feature0D", 1);
66  _pubSift = advertise<posedetection_msgs::ImageFeature0D>(*nh_, "ImageFeature0D", 1);
67  _srvDetect = nh_->advertiseService("Feature0DDetect", &SiftNode::detectCb, this);
68  lasttime = ros::WallTime::now();
69  _bInfoInitialized = false;
70 
71  onInitPostProcess();
72  }
73 
74  SiftNode::~SiftNode() {
75  boost::lock_guard<boost::mutex> g(_g_siftfast_mutex);
76  DestroyAllResources();
77  // message_filters::Synchronizer needs to be called reset
78  // before message_filters::Subscriber is freed.
79  // Calling reset fixes the following error on shutdown of the nodelet:
80  // terminate called after throwing an instance of
81  // 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::lock_error> >'
82  // what(): boost: mutex lock failed in pthread_mutex_lock: Invalid argument
83  // Also see https://github.com/ros/ros_comm/issues/720 .
84  _sync.reset();
85  }
86 
87  void SiftNode::subscribe()
88  {
89  if (!_useMask) {
90  _subImage = _it->subscribe(nh_->resolveName("image"), 1, &SiftNode::imageCb, this, _hints);
91  }
92  else {
93  _subImageWithMask.subscribe(*nh_, "image", 1);
94  _subMask.subscribe(*nh_, "mask", 1);
95  _sync = boost::make_shared<message_filters::Synchronizer<SyncPolicy> >(100);
96  _sync->connectInput(_subImageWithMask, _subMask);
97  _sync->registerCallback(boost::bind(&SiftNode::imageCb, this, _1, _2));
98  }
99  _subInfo = nh_->subscribe("camera_info", 1, &SiftNode::infoCb, this);
100  }
101 
102  void SiftNode::unsubscribe()
103  {
104  if (!_useMask) {
105  _subImage.shutdown();
106  }
107  else {
108  _subImageWithMask.unsubscribe();
109  _subMask.unsubscribe();
110  }
111  _subInfo.shutdown();
112  }
113 
114  void SiftNode::infoCb(const sensor_msgs::CameraInfoConstPtr& msg_ptr)
115  {
116  boost::mutex::scoped_lock lock(_mutex);
117  _sift_msg.info = *msg_ptr;
118  _bInfoInitialized = true;
119  }
120 
121  bool SiftNode::detectCb(posedetection_msgs::Feature0DDetect::Request& req,
122  posedetection_msgs::Feature0DDetect::Response& res)
123  {
124  return detect(res.features,req.image, sensor_msgs::Image::ConstPtr());
125  }
126 
127  bool SiftNode::detect(posedetection_msgs::Feature0D& features, const sensor_msgs::Image& imagemsg,
128  const sensor_msgs::Image::ConstPtr& mask_ptr)
129  {
130  boost::lock_guard<boost::mutex> g(_g_siftfast_mutex);
131  boost::mutex::scoped_lock lock(_mutex);
132  Image imagesift = NULL;
133  cv::Rect region;
134  try {
135  cv::Mat image;
136  cv_bridge::CvImagePtr framefloat;
137 
138  if (!(framefloat = cv_bridge::toCvCopy(imagemsg, "mono8")) )
139  return false;
140 
141  if(imagesift != NULL && (imagesift->cols!=imagemsg.width || imagesift->rows!=imagemsg.height)) {
142  ROS_DEBUG("clear sift resources");
143  DestroyAllImages();
144  imagesift = NULL;
145  }
146 
147  image = framefloat->image;
148 
149  if (mask_ptr) {
150  cv::Mat mask = cv_bridge::toCvShare(mask_ptr, mask_ptr->encoding)->image;
152  ROS_DEBUG ("region x:%d y:%d width:%d height:%d", region.x, region.y, region.width, region.height);
153  if (region.width == 0 || region.height ==0) {
154  region = cv::Rect(0, 0, imagemsg.width, imagemsg.height);
155  }
156  image = image(region);
157  }
158  else {
159  region = cv::Rect(0, 0, imagemsg.width, imagemsg.height);
160  }
161 
162  if(imagesift == NULL)
163  imagesift = CreateImage(imagemsg.height,imagemsg.width);
164 
165  for(int i = 0; i < imagemsg.height; ++i) {
166  uint8_t* psrc = (uint8_t*)image.data+image.step*i;
167  float* pdst = imagesift->pixels+i*imagesift->stride;
168  for(int j = 0; j < imagemsg.width; ++j)
169  pdst[j] = (float)psrc[j]*(1.0f/255.0f);
170  //memcpy(imagesift->pixels+i*imagesift->stride,framefloat->imageData+framefloat->widthStep*i,imagemsg.width*sizeof(float));
171  }
172  }
173  catch (cv_bridge::Exception error) {
174  ROS_WARN("bad frame");
175  return false;
176  }
177 
178  // compute SIFT
179  ros::WallTime siftbasetime = ros::WallTime::now();
180  Keypoint keypts = GetKeypoints(imagesift);
181  // write the keys to the output
182  int numkeys = 0;
183  Keypoint key = keypts;
184  while(key) {
185  numkeys++;
186  key = key->next;
187  }
188 
189  // publish
190  features.header = imagemsg.header;
191  features.positions.resize(numkeys*2);
192  features.scales.resize(numkeys);
193  features.orientations.resize(numkeys);
194  features.confidences.resize(numkeys);
195  features.descriptors.resize(numkeys*128);
196  features.descriptor_dim = 128;
197  features.type = "libsiftfast";
198 
199  int index = 0;
200  key = keypts;
201  while(key) {
202 
203  for(int j = 0; j < 128; ++j)
204  features.descriptors[128*index+j] = key->descrip[j];
205 
206  features.positions[2*index+0] = key->col + region.x;
207  features.positions[2*index+1] = key->row + region.y;
208  features.scales[index] = key->scale;
209  features.orientations[index] = key->ori;
210  features.confidences[index] = 1.0; // SIFT has no confidence?
211 
212  key = key->next;
213  ++index;
214  }
215 
216  FreeKeypoints(keypts);
217  DestroyAllImages();
218 
219  ROS_DEBUG("imagesift: image: %d(size=%lu), num: %d, sift time: %.3fs, total: %.3fs", imagemsg.header.seq,
220  imagemsg.data.size(), numkeys,
221  (float)(ros::WallTime::now()-siftbasetime).toSec(), (float)(ros::WallTime::now()-lasttime).toSec());
222  lasttime = ros::WallTime::now();
223  return true;
224  }
225 
226  void SiftNode::imageCb(const sensor_msgs::ImageConstPtr& msg_ptr,
227  const sensor_msgs::ImageConstPtr& mask_ptr)
228  {
229  vital_checker_->poke();
230  if(_pubFeatures.getNumSubscribers()==0 && _pubSift.getNumSubscribers()==0) {
231  ROS_DEBUG("number of subscribers is 0, ignoring image");
232  return;
233  }
234  detect(_sift_msg.features,*msg_ptr, mask_ptr);
235  _pubFeatures.publish(_sift_msg.features);
236 
237  if(!_bInfoInitialized) {
238  ROS_DEBUG("camera info not initialized, ignoring image");
239  return;
240  }
241  _sift_msg.image = *msg_ptr; // probably copying pointers so don't use after this call
242  {
243  boost::mutex::scoped_lock lock(_mutex); // needed for camerainfo
244  _pubSift.publish(_sift_msg);
245  }
246  }
247 
248  void SiftNode::imageCb(const sensor_msgs::ImageConstPtr& msg_ptr)
249  {
250  imageCb(msg_ptr, sensor_msgs::ImageConstPtr());
251  }
252 }
253 
node_handle.h
imagesift
Definition: imagesift.h:58
jsk_recognition_utils::boundingRectOfMaskImage
cv::Rect boundingRectOfMaskImage(const cv::Mat &image)
_2
boost::arg< 2 > _2
NULL
#define NULL
image_encodings.h
image_transport::ImageTransport
boost::shared_ptr
i
int i
PLUGINLIB_EXPORT_CLASS
PLUGINLIB_EXPORT_CLASS(imagesift::SiftNode, nodelet::Nodelet)
ros
ros::TransportHints
time_synchronizer.h
cv_bridge::Exception
class_list_macros.h
subscriber_filter.h
imagesift.h
cv_bridge::toCvCopy
CvImagePtr toCvCopy(const sensor_msgs::CompressedImage &source, const std::string &encoding=std::string())
ROS_DEBUG
#define ROS_DEBUG(...)
subscriber.h
ros::WallTime::now
static WallTime now()
imagesift::SiftNode
Definition: imagesift.h:95
_1
boost::arg< 1 > _1
ROS_WARN
#define ROS_WARN(...)
ROS_INFO_STREAM
#define ROS_INFO_STREAM(args)
ros::WallTime
f
f
image_transport.h
imagesift::_g_siftfast_mutex
static boost::mutex _g_siftfast_mutex
Definition: imagesift.h:93
nodelet::Nodelet
std
cv_bridge.h
synchronizer.h
cv_utils.h
image_transport::TransportHints
cv_bridge::toCvShare
CvImageConstPtr toCvShare(const sensor_msgs::Image &source, const boost::shared_ptr< void const > &tracked_object, const std::string &encoding=std::string())
error
def error(*args, **kwargs)


imagesift
Author(s): Rosen Diankov (rdiankov@cs.cmu.edu), Kei Okada
autogenerated on Fri May 16 2025 03:11:08