7 BarrelDetection::BarrelDetection()
10 BarrelDetection::~BarrelDetection()
13 void BarrelDetection::onInit(){
14 NODELET_DEBUG(
"Initializing hector_barrel_detection_nodelet");
20 pnh_.
param(
"h_min", h_min, 100);
21 pnh_.
param(
"h_max", h_max, 140);
22 pnh_.
param(
"s_min", s_min, 100);
23 pnh_.
param(
"s_max", s_max, 255);
24 pnh_.
param(
"v_min", v_min, 50);
25 pnh_.
param(
"v_max", v_max, 200);
26 pnh_.
param(
"bluePart", bluePart, 4.0);
27 pnh_.
param(
"minRadius", minRadius, 0.15);
28 pnh_.
param(
"maxRadius", maxRadius, 0.4);
30 pcl_sub = nh_.
subscribe(
"/openni/depth/points", 1, &BarrelDetection::PclCallback,
this);
31 image_sub = it_.
subscribeCamera(
"/openni/rgb/image_color", 10, &BarrelDetection::imageCallback,
this);
32 cloud_filtered_publisher_ = pnh_.
advertise<sensor_msgs::PointCloud2> (
"cloud_filtered_barrel", 0);
33 pose_publisher_ = pnh_.
advertise<geometry_msgs::PoseStamped> (
"pose_filtered_barrel", 0);
34 barrel_marker_publisher_ = pnh_.
advertise<visualization_msgs::MarkerArray> (
"marker_filtered_barrel", 0);
35 imagePercept_pub_ = pnh_.
advertise<hector_worldmodel_msgs::ImagePercept> (
"/worldmodel/image_percept", 0);
36 posePercept_pub_= pnh_.
advertise<hector_worldmodel_msgs::PosePercept> (
"/worldmodel/pose_percept", 0);
37 pcl_debug_pub_= pnh_.
advertise<sensor_msgs::PointCloud2> (
"barrel_pcl_debug", 0);
38 debug_imagePoint_pub_= pnh_.
advertise<geometry_msgs::PointStamped>(
"blaDebugPoseEstimate",0);
41 worldmodel_srv_client_=nh_.
serviceClient<hector_nav_msgs::GetDistanceToObstacle>(
"/hector_octomap_server/get_distance_to_obstacle");
44 dynamic_recf_type = boost::bind(&BarrelDetection::dynamic_recf_cb,
this, _1, _2);
45 dynamic_recf_server.setCallback(dynamic_recf_type);
49 void BarrelDetection::imageCallback(
const sensor_msgs::ImageConstPtr& img,
const sensor_msgs::CameraInfoConstPtr& info){
52 hector_nav_msgs::GetDistanceToObstacle dist_msgs;
53 dist_msgs.request.point.header= img->header;
65 cv::Mat img_filtered(cv_ptr->image);
67 cv::cvtColor(img_filtered, img_filtered, CV_BGR2HSV);
70 float cutPercentage= 0.2;
71 cv::Size size= img_filtered.size();
72 img_filtered = img_filtered(cv::Rect(size.width*cutPercentage,size.height*cutPercentage,size.width*(1-2*cutPercentage),size.height*(1-2*cutPercentage)));
78 cv::inRange(img_filtered, cv::Scalar(h_min, s_min, v_min), cv::Scalar(h_max, s_max, v_max), blueOnly);
80 if(black_white_image_pub_.getNumSubscribers()>0){
82 cvImg.
image = blueOnly;
84 cvImg.
header = img->header;
86 black_white_image_pub_.publish(cvImg.
toImageMsg() ,info);
93 cv::SimpleBlobDetector::Params params;
94 params.filterByColor =
true;
95 params.blobColor = 255;
96 params.minDistBetweenBlobs = 0.5;
97 params.filterByArea =
true;
99 params.minArea = (blueOnly.rows * blueOnly.cols) /bluePart;
101 params.maxArea = blueOnly.rows * blueOnly.cols;
102 params.filterByCircularity =
false;
103 params.filterByColor =
false;
104 params.filterByConvexity =
false;
105 params.filterByInertia =
false;
107 cv::SimpleBlobDetector blob_detector(params);
108 std::vector<cv::KeyPoint> keypoints;
111 blob_detector.detect(blueOnly,keypoints);
117 hector_worldmodel_msgs::ImagePercept ip;
119 ip.header= img->header;
120 ip.info.class_id =
"barrel";
121 ip.info.class_support = 1;
122 ip.camera_info = *info;
124 if(pub_imageDetection.getNumSubscribers() > 0){
125 publish_rectangle_for_recf(keypoints, img, info, img_filtered);
128 for(
unsigned int i=0; i<keypoints.size();i++)
130 ip.x = keypoints.at(i).pt.x;
131 ip.y = keypoints.at(i).pt.y;
134 ROS_DEBUG(
"Barrel blob found at image coord: (%f, %f)", ip.x, ip.y);
141 cameraModel->fromCameraInfo(info);
144 cv::Point2d rectified = cameraModel->rectifyPoint(cv::Point2d(ip.x+size.width*cutPercentage, ip.y+size.height*cutPercentage));
145 cv::Point3d direction_cv = cameraModel->projectPixelTo3dRay(rectified);
146 tf::Point direction(direction_cv.x, direction_cv.y, direction_cv.z);
150 dist_msgs.request.point.header = ip.header;
153 worldmodel_srv_client_.call(dist_msgs);
155 distance = std::max(dist_msgs.response.distance, 0.0f);
161 const geometry_msgs::PointStamped const_point=dist_msgs.request.point;
162 geometry_msgs::PointStamped point_in_map;
166 listener_.waitForTransform(
"/map", img->header.frame_id,
168 listener_.transformPoint(
"/map", const_point, point_in_map);
171 ROS_ERROR(
"Lookup Transform failed: %s",ex.what());
175 if(debug_imagePoint_pub_.getNumSubscribers()>0){
176 debug_imagePoint_pub_.publish(point_in_map);
179 if(current_pc_msg_!=0 && distance>0){
180 findCylinder(current_pc_msg_, point_in_map.point.x, point_in_map.point.y, const_point);
187 void BarrelDetection::PclCallback(
const sensor_msgs::PointCloud2::ConstPtr& pc_msg){
189 current_pc_msg_= pc_msg;
192 void BarrelDetection::findCylinder(
const sensor_msgs::PointCloud2::ConstPtr &pc_msg,
float xKey,
float yKey,
const geometry_msgs::PointStamped cut_around_keypoint){
194 pcl::PCLPointCloud2 pcl_pc2;
196 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZ>);
197 pcl::fromPCLPointCloud2(pcl_pc2,*cloud);
201 float xmin=cut_around_keypoint.point.x-0.3;
202 float xmax=cut_around_keypoint.point.x+0.3;
203 pass_.setInputCloud (cloud);
204 pass_.setFilterFieldName (
"x");
205 pass_.setFilterLimits (xmin, xmax);
206 pass_.filter (*cloud);
208 float ymin=cut_around_keypoint.point.y-0.4;
209 float ymax=cut_around_keypoint.point.y+0.4;
210 pass_.setInputCloud (cloud);
211 pass_.setFilterFieldName (
"y");
212 pass_.setFilterLimits (ymin, ymax);
213 pass_.filter (*cloud);
221 listener_.waitForTransform(
"/map", pc_msg->header.frame_id,
223 listener_.lookupTransform(
"/map", pc_msg->header.frame_id,
224 time, transform_cloud_to_map);
227 ROS_ERROR(
"Lookup Transform failed: %s",ex.what());
235 pcl::transformPointCloud(*cloud, *cloud_tmp, to_map_);
237 cloud->header.frame_id= transform_cloud_to_map.
frame_id_;
241 if (pcl_debug_pub_.getNumSubscribers() > 0){
242 sensor_msgs::PointCloud2 filtered_msg;
244 filtered_msg.header.frame_id = cloud->header.frame_id;
245 pcl_debug_pub_.publish(filtered_msg);
251 pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
253 pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (
new pcl::search::KdTree<pcl::PointXYZ> ());
254 pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (
new pcl::PointCloud<pcl::Normal> ());
255 ne.setSearchMethod (tree);
256 ne.setInputCloud (cloud);
259 ne.compute (*cloud_normals);
263 pcl::SACSegmentationFromNormals<pcl::PointXYZ, pcl::Normal> seg;
264 pcl::ModelCoefficients::Ptr coefficients_cylinder (
new pcl::ModelCoefficients);
265 pcl::PointIndices::Ptr inliers_cylinder (
new pcl::PointIndices);
266 seg.setOptimizeCoefficients (
true);
267 seg.setModelType (pcl::SACMODEL_CYLINDER);
268 seg.setMethodType (pcl::SAC_RANSAC);
269 seg.setNormalDistanceWeight (0.1);
270 seg.setMaxIterations (50);
271 seg.setDistanceThreshold (0.01);
272 seg.setRadiusLimits (minRadius, maxRadius);
273 seg.setInputCloud (cloud);
274 seg.setInputNormals (cloud_normals);
276 Eigen::Vector3f v = Eigen::Vector3f(0.0, 0.0, 1.0);
278 seg.segment (*inliers_cylinder, *coefficients_cylinder);
282 pcl::ExtractIndices<pcl::PointXYZ> extract;
283 extract.setInputCloud (cloud);
284 extract.setIndices (inliers_cylinder);
285 extract.setNegative (
false);
286 extract.filter (*cloud);
290 if (cloud_filtered_publisher_.getNumSubscribers() > 0){
291 sensor_msgs::PointCloud2 cyl_msg;
293 cyl_msg.header.frame_id = cloud->header.frame_id;
294 cloud_filtered_publisher_.publish(cyl_msg);
297 geometry_msgs::Point possibleCylinderPoint;
300 if( cloud->points.size()>0){
301 possibleCylinderPoint.x= coefficients_cylinder->values[0];
302 possibleCylinderPoint.y= coefficients_cylinder->values[1];
303 float square_distance= std::abs(possibleCylinderPoint.x - xKey)*std::abs(possibleCylinderPoint.x - xKey) +
304 std::abs(possibleCylinderPoint.y - yKey)*std::abs(possibleCylinderPoint.y - yKey);
305 if(square_distance < epsilon){
312 if (pose_publisher_.getNumSubscribers() > 0){
313 geometry_msgs::PoseStamped pose_msg;
314 pose_msg.header.frame_id=cloud->header.frame_id;
315 pose_msg.header.stamp=pc_msg->header.stamp;
316 pose_msg.pose.position.x=possibleCylinderPoint.x;
317 pose_msg.pose.position.y=possibleCylinderPoint.y;
318 pose_publisher_.publish(pose_msg);
321 if( cloud->points.size()>0 && inRange)
324 geometry_msgs::PointStamped point_in_map;
327 ros::Time time = cut_around_keypoint.header.stamp;
328 listener_.waitForTransform(
"/map", cut_around_keypoint.header.frame_id,
330 listener_.transformPoint(
"/map", cut_around_keypoint, point_in_map);
333 ROS_ERROR(
"Lookup Transform failed: %s",ex.what());
337 hector_worldmodel_msgs::PosePercept pp;
339 pp.header.frame_id= cloud->header.frame_id;
340 pp.header.stamp= pc_msg->header.stamp;
341 pp.info.class_id=
"barrel";
342 pp.info.class_support=1;
343 pp.info.object_support=1;
344 pp.pose.pose.position.x= coefficients_cylinder->values[0];
345 pp.pose.pose.position.y= coefficients_cylinder->values[1];
346 pp.pose.pose.position.z= point_in_map.point.z;
347 pp.pose.pose.orientation.x= pp.pose.pose.orientation.y = pp.pose.pose.orientation.z= 0;
348 pp.pose.pose.orientation.w= 1;
351 if(pp.pose.pose.position.z < 1.1 && pp.pose.pose.position.z >0.2){
352 posePercept_pub_.publish(pp);
358 visualization_msgs::MarkerArray markerArray_msg_;
359 markerArray_msg_.markers.resize(1);
361 markerArray_msg_.markers[0].action = visualization_msgs::Marker::ADD;
364 markerArray_msg_.markers[0].header.frame_id = cloud->header.frame_id;
365 markerArray_msg_.markers[0].header.stamp = pc_msg->header.stamp;
366 markerArray_msg_.markers[0].id = 0;
367 markerArray_msg_.markers[0].pose.position.x= pp.pose.pose.position.x;
368 markerArray_msg_.markers[0].pose.position.y = pp.pose.pose.position.y;
369 markerArray_msg_.markers[0].pose.position.z = pp.pose.pose.position.z;
370 markerArray_msg_.markers[0].pose.orientation.x=markerArray_msg_.markers[0].pose.orientation.y= markerArray_msg_.markers[0].pose.orientation.z= pp.pose.pose.orientation.x;
371 markerArray_msg_.markers[0].pose.orientation.w=1;
374 markerArray_msg_.markers[0].color.r = 1.0;
375 markerArray_msg_.markers[0].color.g = 0.0;
376 markerArray_msg_.markers[0].color.b = 0.0;
379 markerArray_msg_.markers[0].ns =
"cylinder";
380 markerArray_msg_.markers[0].type = visualization_msgs::Marker::CYLINDER;
381 markerArray_msg_.markers[0].pose.position.z = 0.6;
382 markerArray_msg_.markers[0].scale.x = 0.6;
383 markerArray_msg_.markers[0].scale.y = 0.6;
384 markerArray_msg_.markers[0].scale.z = 1;
385 markerArray_msg_.markers[0].color.a = 0.4;
388 barrel_marker_publisher_.publish(markerArray_msg_);
397 void BarrelDetection::publish_rectangle_for_recf(std::vector<cv::KeyPoint> keypoints,
const sensor_msgs::ImageConstPtr& img,
const sensor_msgs::CameraInfoConstPtr& info, cv::Mat& img_filtered){
398 cv::cvtColor(img_filtered, img_filtered, CV_HSV2BGR);
403 IplImage ipl_img = img_filtered;
406 for(
unsigned int i = 0; i < keypoints.size(); i++){
408 width = (int)(keypoints.at(i).size );
409 height = (int)(keypoints.at(i).size );
410 for(
int j = -width; j <= width;j++){
411 if ((keypoints.at(i).pt.x + j) >= 0 && (keypoints.at(i).pt.x + j) < ipl_img.width){
413 if ((keypoints.at(i).pt.y - height) >= 0){
414 cvSet2D(&ipl_img,(
int)(keypoints.at(i).pt.y - height), (
int)(keypoints.at(i).pt.x + j),cv::Scalar(0));
417 if ((keypoints.at(i).pt.y + height) < ipl_img.height){
418 cvSet2D(&ipl_img,(
int)(keypoints.at(i).pt.y + height), (
int)(keypoints.at(i).pt.x + j),cv::Scalar(0));
423 for(
int k = -height; k <= height;k++){
424 if ((keypoints.at(i).pt.y + k) >= 0 && (keypoints.at(i).pt.y + k) < ipl_img.height){
426 if ((keypoints.at(i).pt.x - width) >= 0){
427 cvSet2D(&ipl_img,(
int)(keypoints.at(i).pt.y +k), (
int)(keypoints.at(i).pt.x - width),cv::Scalar(0));
430 if ((keypoints.at(i).pt.x + width) < ipl_img.width){
431 cvSet2D(&ipl_img,(
int)(keypoints.at(i).pt.y +k), (
int)(keypoints.at(i).pt.x + width),cv::Scalar(0));
439 cvImg.
image = img_filtered;
442 cvImg.header = img->header;
443 cvImg.encoding = img->encoding;
444 pub_imageDetection.publish(cvImg.toImageMsg(),info);
448 void BarrelDetection::dynamic_recf_cb(hector_barrel_detection_nodelet::BarrelDetectionConfig &config, uint32_t level) {
449 ROS_INFO(
"Reconfigure Callback enterd");
451 h_min= config.min_H_value;
452 h_max= config.max_H_value;
453 s_min= config.min_S_value;
454 s_max= config.max_S_value;
455 v_min= config.min_V_value;
456 v_max= config.max_V_value;
457 bluePart= config.bluePart;
458 minRadius= config.minRadius;
459 maxRadius= config.maxRadius;
CvImageConstPtr toCvShare(const sensor_msgs::ImageConstPtr &source, const std::string &encoding=std::string())
ServiceClient serviceClient(const std::string &service_name, bool persistent=false, const M_string &header_values=M_string())
void transformTFToEigen(const tf::Transform &t, Eigen::Affine3d &e)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
CameraSubscriber subscribeCamera(const std::string &base_topic, uint32_t queue_size, const CameraSubscriber::Callback &callback, const ros::VoidPtr &tracked_object=ros::VoidPtr(), const TransportHints &transport_hints=TransportHints())
PLUGINLIB_EXPORT_CLASS(BAGReader, nodelet::Nodelet)
TFSIMD_FORCE_INLINE tfScalar distance(const Vector3 &v) const
CameraPublisher advertiseCamera(const std::string &base_topic, uint32_t queue_size, bool latch=false)
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
TFSIMD_FORCE_INLINE Vector3 normalized() const
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
#define ROS_DEBUG_STREAM(args)
TFSIMD_FORCE_INLINE Vector3 & normalize()
void toROSMsg(const sensor_msgs::PointCloud2 &cloud, sensor_msgs::Image &image)
#define NODELET_DEBUG(...)
sensor_msgs::ImagePtr toImageMsg() const
void toPCL(const ros::Time &stamp, pcl::uint64_t &pcl_stamp)
static void pointTFToMsg(const Point &bt_v, geometry_msgs::Point &msg_v)