find_object_on_plane_nodelet.cpp
Go to the documentation of this file.
1 // -*- mode: c++ -*-
2 /*********************************************************************
3  * Software License Agreement (BSD License)
4  *
5  * Copyright (c) 2015, JSK Lab
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/or other materials provided
17  * with the distribution.
18  * * Neither the name of the JSK Lab nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *********************************************************************/
35 #define BOOST_PARAMETER_MAX_ARITY 7
37 #include <opencv2/opencv.hpp>
38 #include <cv_bridge/cv_bridge.h>
40 
41 namespace jsk_pcl_ros
42 {
44  {
45  DiagnosticNodelet::onInit();
46  pub_min_area_rect_image_ = advertise<sensor_msgs::Image>(
47  *pnh_, "debug/min_area_rect_image", 1);
48  onInitPostProcess();
49  }
50 
52  // message_filters::Synchronizer needs to be called reset
53  // before message_filters::Subscriber is freed.
54  // Calling reset fixes the following error on shutdown of the nodelet:
55  // terminate called after throwing an instance of
56  // 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::lock_error> >'
57  // what(): boost: mutex lock failed in pthread_mutex_lock: Invalid argument
58  // Also see https://github.com/ros/ros_comm/issues/720 .
59  sync_.reset();
60  }
61 
63  {
64  sub_image_.subscribe(*pnh_, "input", 1);
65  sub_info_.subscribe(*pnh_, "input/camera_info", 1);
66  sub_coefficients_.subscribe(*pnh_, "input/coefficients", 1);
67  sync_ = boost::make_shared<message_filters::Synchronizer<SyncPolicy> >(100);
69  sync_->registerCallback(boost::bind(&FindObjectOnPlane::find,
70  this, _1, _2, _3));
71  }
72 
74  {
77  }
78 
80  const sensor_msgs::Image::ConstPtr& image_msg,
81  const sensor_msgs::CameraInfo::ConstPtr& info_msg,
82  const pcl_msgs::ModelCoefficients::ConstPtr& polygon_3d_coefficient_msg)
83  {
84  cv::Mat object_image = cv_bridge::toCvShare(image_msg, image_msg->encoding)->image;
85 
87  pcl::ModelCoefficients::Ptr polygon_coefficients
88  (new pcl::ModelCoefficients);
89  pcl_conversions::toPCL(*polygon_3d_coefficient_msg, *polygon_coefficients);
91  (new jsk_recognition_utils::Plane(polygon_coefficients->values));
92  model.fromCameraInfo(info_msg);
93  std::vector<cv::Point> all_points;
94  for (int j = 0; j < object_image.rows; j++) {
95  for (int i = 0; i < object_image.cols; i++) {
96  if (object_image.at<uchar>(j, i) == 255) {
97  all_points.push_back(cv::Point(i, j));
98  }
99  }
100  }
101  cv::RotatedRect obb = cv::minAreaRect(all_points);
102 
103  cv::Mat min_area_rect_image;
104  cv::cvtColor(object_image, min_area_rect_image, CV_GRAY2BGR);
105  cv::Point2f vertices2f[4];
106  obb.points(vertices2f);
107  cv::line(min_area_rect_image, vertices2f[0], vertices2f[1],
108  cv::Scalar(0, 0, 255), 4);
109  cv::line(min_area_rect_image, vertices2f[1], vertices2f[2],
110  cv::Scalar(0, 0, 255), 4);
111  cv::line(min_area_rect_image, vertices2f[2], vertices2f[3],
112  cv::Scalar(0, 0, 255), 4);
113  cv::line(min_area_rect_image, vertices2f[3], vertices2f[0],
114  cv::Scalar(0, 0, 255), 4);
115  cv::Rect bb = obb.boundingRect();
116  std::vector<cv::Point3f> search_points_3d;
117  std::vector<cv::Point2f> search_points_2d;
118  generateStartPoints(cv::Point2f(bb.x, bb.y),
119  model, polygon_coefficients,
120  search_points_3d, search_points_2d);
121  for (size_t i = 0; i < search_points_2d.size(); i++) {
122  cv::circle(min_area_rect_image, search_points_2d[i], 5, cv::Scalar(0, 255, 0), 1);
123  }
124 
125  //for (size_t i = 0; i < search_points_3d.size(); i++) {
126  double min_area = DBL_MAX;
127  double min_angle;
128  cv::Point2f min_search_point;
129  double min_x;
130  double min_y;
131  for (size_t i = 0; i < search_points_2d.size(); i++) {
132  std::vector<double> angles;
133  std::vector<double> max_x;
134  std::vector<double> max_y;
135  generateAngles(object_image, search_points_2d[i], angles,
136  max_x, max_y,
137  model, plane);
138  // draw angles
139  for (size_t j = 0; j < angles.size(); j++) {
140  double area = drawAngle(min_area_rect_image, search_points_2d[i], angles[j],
141  max_x[j], max_y[j], model, plane, cv::Scalar(0, 255, 0));
142  if (area < min_area) {
143  min_area = area;
144  min_x = max_x[j];
145  min_y = max_y[j];
146  min_angle = angles[j];
147  min_search_point = search_points_2d[i];
148  }
149  }
150  }
151  drawAngle(min_area_rect_image, min_search_point, min_angle,
152  min_x, min_y, model, plane, cv::Scalar(0, 255, 255));
153  // convert the points into 3-D
155  cv_bridge::CvImage(image_msg->header,
157  min_area_rect_image).toImageMsg());
158  NODELET_INFO("published");
159  }
160 
161 
163  const cv::Mat& blob_image, const cv::Point2f& test_point,
164  std::vector<double>& angles,
165  std::vector<double>& max_x,
166  std::vector<double>& max_y,
169  {
170  angles.clear();
171  const double angle_step = 3;
172  std::vector<cv::Point> indices;
173  for (int j = 0; j < blob_image.rows; j++) {
174  for (int i = 0; i < blob_image.cols; i++) {
175  if (blob_image.at<uchar>(j, i) != 0) { // need to check
176  indices.push_back(cv::Point(i, j));
177  }
178  }
179  }
180  for (double angle = -180; angle < 180; angle += angle_step) {
181  Eigen::Vector2f ux(cos(angle/180*M_PI), sin(angle/180*M_PI));
182  //Eigen::Vector2f uy(sin(angle/180*M_PI), -cos(angle/180*M_PI));
183  cv::Point2d uy_end = getUyEnd(test_point, cv::Point2d(test_point.x + ux[0], test_point.y + ux[1]),
184  model,
185  plane);
186  Eigen::Vector2f uy(uy_end.x - test_point.x, uy_end.y - test_point.y);
187 
188  Eigen::Matrix2f A;
189  A << ux[0], uy[0],
190  ux[1], uy[1];
191  bool excluded = false;
192  double max_alpha = -DBL_MAX;
193  double max_beta = -DBL_MAX;
194  for (size_t i = 0; i < indices.size(); i++) {
195  Eigen::Vector2f p_q = Eigen::Vector2f(indices[i].x, indices[i].y) - Eigen::Vector2f(test_point.x, test_point.y);
196  Eigen::Vector2f a_b = A.inverse() * p_q;
197  double alpha = a_b[0];
198  double beta = a_b[1];
199  if (alpha < 0 || beta < 0) {
200  excluded = true;
201  break;
202  }
203  if (alpha > max_alpha) {
204  max_alpha = alpha;
205  }
206  if (beta > max_beta) {
207  max_beta = beta;
208  }
209 
210  }
211  if (!excluded) {
212  angles.push_back(angle);
213  max_x.push_back(max_alpha);
214  max_y.push_back(max_beta);
215  }
216  }
217  }
218 
220  const cv::Point3d& ray,
222  {
223  Eigen::Vector3f n = plane->getNormal();
224  Eigen::Vector3f d(ray.x, ray.y, ray.z);
225  double alpha = - plane->getD() / n.dot(d);
226  return alpha * d;
227  }
228 
230  const cv::Point2d& ux_start,
231  const cv::Point2d& ux_end,
234  {
235  cv::Point3d start_ray = model.projectPixelTo3dRay(ux_start);
236  cv::Point3d end_ray = model.projectPixelTo3dRay(ux_end);
237  Eigen::Vector3f ux_start_3d = rayPlaneInteersect(start_ray, plane);
238  Eigen::Vector3f ux_end_3d = rayPlaneInteersect(end_ray, plane);
239  Eigen::Vector3f ux_3d = ux_end_3d - ux_start_3d;
240  Eigen::Vector3f normal = plane->getNormal();
241  Eigen::Vector3f uy_3d = normal.cross(ux_3d).normalized();
242  Eigen::Vector3f uy_end_3d = ux_start_3d + uy_3d;
243  cv::Point2d uy_end = model.project3dToPixel(cv::Point3d(uy_end_3d[0],
244  uy_end_3d[1],
245  uy_end_3d[2]));
246  return uy_end;
247  }
248 
250  cv::Mat& out_image, const cv::Point2f& test_point, const double angle,
251  const double max_x, const double max_y,
254  cv::Scalar color)
255  {
256  Eigen::Vector2f ux(cos(angle/180*M_PI), sin(angle/180*M_PI));
257  cv::Point2d uy_end = getUyEnd(
258  test_point, cv::Point2d(test_point.x + ux[0], test_point.y + ux[1]),
259  model, plane);
260  Eigen::Vector2f uy(uy_end.x - test_point.x, uy_end.y - test_point.y);
261  //Eigen::Vector2f uy(sin(angle/180*M_PI), -cos(angle/180*M_PI));
262  Eigen::Vector2f to_point = ux * max_x + Eigen::Vector2f(test_point.x, test_point.y);
263  Eigen::Vector2f to_point2 = uy * max_y + Eigen::Vector2f(test_point.x, test_point.y);
264  cv::Point2f to_point_cv(to_point[0], to_point[1]);
265  cv::Point2f to_point2_cv(to_point2[0], to_point2[1]);
266  cv::Point2f to_point3_cv = to_point_cv + to_point2_cv - test_point;
267  cv::line(out_image, test_point, to_point_cv, color, 4);
268  cv::line(out_image, test_point, to_point2_cv, color, 4);
269  cv::line(out_image, to_point_cv, to_point3_cv, color, 4);
270  cv::line(out_image, to_point2_cv, to_point3_cv, color, 4);
271  return max_x * max_y; // TODO: it's not correct!
272  }
273 
275  const cv::Point2f& point_2d,
277  const pcl::ModelCoefficients::Ptr& coefficients,
278  std::vector<cv::Point3f>& search_points_3d,
279  std::vector<cv::Point2f>& search_points_2d)
280  {
281  NODELET_INFO("generateStartPoints");
284  cv::Point3d ray = model.projectPixelTo3dRay(point_2d);
285  Eigen::Vector3f projected_point = rayPlaneInteersect(ray, plane);
286  const double resolution_step = 0.01;
287  const int resolution = 5;
288  search_points_3d.clear();
289  search_points_2d.clear();
290  for (int i = - resolution; i < resolution; ++i) {
291  for (int j = - resolution; j < resolution; ++j) {
292  double x_diff = resolution_step * i;
293  double y_diff = resolution_step * j;
294  Eigen::Vector3f moved_point = projected_point + Eigen::Vector3f(x_diff, y_diff, 0);
295  Eigen::Vector3f projected_moved_point;
296  plane->project(moved_point, projected_moved_point);
297  cv::Point3f projected_moved_point_cv(projected_moved_point[0],
298  projected_moved_point[1],
299  projected_moved_point[2]);
300  search_points_3d.push_back(cv::Point3f(projected_moved_point_cv));
301  cv::Point2d p2d = model.project3dToPixel(projected_moved_point_cv);
302  search_points_2d.push_back(p2d);
303  }
304  }
305  }
306 }
307 
308 
jsk_pcl_ros::FindObjectOnPlane::unsubscribe
virtual void unsubscribe()
Definition: find_object_on_plane_nodelet.cpp:73
_2
boost::arg< 2 > _2
image_encodings.h
angles
_3
boost::arg< 3 > _3
boost::shared_ptr
i
int i
cv_bridge::CvImage::toImageMsg
sensor_msgs::ImagePtr toImageMsg() const
M_PI
#define M_PI
angle
GLfloat angle
pcl_conversions::toPCL
void toPCL(const pcl_msgs::ModelCoefficients &mc, pcl::ModelCoefficients &pcl_mc)
jsk_pcl_ros::FindObjectOnPlane::~FindObjectOnPlane
virtual ~FindObjectOnPlane()
Definition: find_object_on_plane_nodelet.cpp:51
attention_pose_set.x
x
Definition: attention_pose_set.py:18
jsk_pcl_ros::FindObjectOnPlane::sub_image_
message_filters::Subscriber< sensor_msgs::Image > sub_image_
Definition: find_object_on_plane.h:166
ros::Publisher::publish
void publish(const boost::shared_ptr< M > &message) const
sin
double sin()
message_filters::Subscriber::unsubscribe
void unsubscribe()
jsk_pcl_ros::FindObjectOnPlane::onInit
virtual void onInit()
Definition: find_object_on_plane_nodelet.cpp:43
jsk_pcl_ros::FindObjectOnPlane::generateStartPoints
virtual void generateStartPoints(const cv::Point2f &point_2d, const image_geometry::PinholeCameraModel &model, const pcl::ModelCoefficients::Ptr &coefficients, std::vector< cv::Point3f > &search_points_3d, std::vector< cv::Point2f > &search_points_2d)
Definition: find_object_on_plane_nodelet.cpp:274
jsk_pcl_ros::FindObjectOnPlane::find
virtual void find(const sensor_msgs::Image::ConstPtr &image_msg, const sensor_msgs::CameraInfo::ConstPtr &info_msg, const pcl_msgs::ModelCoefficients::ConstPtr &polygon_3d_coefficient_msg)
Definition: find_object_on_plane_nodelet.cpp:79
class_list_macros.h
jsk_pcl_ros::FindObjectOnPlane
Definition: find_object_on_plane.h:86
A
jsk_pcl_ros
Definition: add_color_from_image.h:51
jsk_pcl_ros::FindObjectOnPlane::drawAngle
virtual double drawAngle(cv::Mat &out_image, const cv::Point2f &test_point, const double angle, const double max_x, const double max_y, const image_geometry::PinholeCameraModel &model, const jsk_recognition_utils::Plane::Ptr &plane, cv::Scalar color)
Definition: find_object_on_plane_nodelet.cpp:249
jsk_pcl_ros::FindObjectOnPlane::sub_info_
message_filters::Subscriber< sensor_msgs::CameraInfo > sub_info_
Definition: find_object_on_plane.h:167
jsk_pcl_ros::FindObjectOnPlane::sync_
boost::shared_ptr< message_filters::Synchronizer< SyncPolicy > > sync_
Definition: find_object_on_plane.h:165
_1
boost::arg< 1 > _1
d
d
alpha
alpha
PLUGINLIB_EXPORT_CLASS
PLUGINLIB_EXPORT_CLASS(jsk_pcl_ros::FindObjectOnPlane, nodelet::Nodelet)
depth_error_calibration.model
model
Definition: depth_error_calibration.py:37
message_filters::Subscriber::subscribe
void subscribe()
NODELET_INFO
#define NODELET_INFO(...)
jsk_pcl_ros::FindObjectOnPlane::rayPlaneInteersect
Eigen::Vector3f rayPlaneInteersect(const cv::Point3d &ray, const jsk_recognition_utils::Plane::Ptr &plane)
Definition: find_object_on_plane_nodelet.cpp:219
nodelet::Nodelet
image_geometry::PinholeCameraModel
jsk_pcl_ros::FindObjectOnPlane::subscribe
virtual void subscribe()
Definition: find_object_on_plane_nodelet.cpp:62
resolution
resolution
cv_bridge.h
cv_bridge::CvImage
cos
double cos()
coefficients
coefficients
find_object_on_plane.h
jsk_pcl_ros::FindObjectOnPlane::generateAngles
virtual void generateAngles(const cv::Mat &blob_image, const cv::Point2f &test_point, std::vector< double > &angles, std::vector< double > &max_x, std::vector< double > &max_y, const image_geometry::PinholeCameraModel &model, const jsk_recognition_utils::Plane::Ptr &plane)
Definition: find_object_on_plane_nodelet.cpp:162
jsk_recognition_utils::Plane
sensor_msgs::image_encodings::BGR8
const std::string BGR8
jsk_pcl_ros::FindObjectOnPlane::pub_min_area_rect_image_
ros::Publisher pub_min_area_rect_image_
Definition: find_object_on_plane.h:169
cv_bridge::toCvShare
CvImageConstPtr toCvShare(const sensor_msgs::Image &source, const boost::shared_ptr< void const > &tracked_object, const std::string &encoding=std::string())
attention_pose_set.y
y
Definition: attention_pose_set.py:19
n
GLfloat n[6][3]
jsk_pcl_ros::FindObjectOnPlane::sub_coefficients_
message_filters::Subscriber< pcl_msgs::ModelCoefficients > sub_coefficients_
Definition: find_object_on_plane.h:168
info_msg
info_msg
jsk_pcl_ros::FindObjectOnPlane::getUyEnd
virtual cv::Point2d getUyEnd(const cv::Point2d &ux_start, const cv::Point2d &ux_end, const image_geometry::PinholeCameraModel &model, const jsk_recognition_utils::Plane::Ptr &plane)
Definition: find_object_on_plane_nodelet.cpp:229


jsk_pcl_ros
Author(s): Yohei Kakiuchi
autogenerated on Tue Jan 7 2025 04:05:44