30 #include <geometry_msgs/msg/transform_stamped.hpp> 35 #include <tf2_geometry_msgs/tf2_geometry_msgs.h> 37 #include <tf2_geometry_msgs/tf2_geometry_msgs.hpp> 47 objFramePrefix_(
"object"),
50 tfBroadcaster_ = std::make_shared<tf2_ros::TransformBroadcaster>(node);
52 objFramePrefix_ = node->declare_parameter(
"object_prefix", objFramePrefix_);
54 RCLCPP_INFO(node->get_logger(),
"object_prefix = %s", objFramePrefix_.c_str());
55 RCLCPP_INFO(node->get_logger(),
"pnp = %s",
usePnP_?
"true":
"false");
57 pub_ = node->create_publisher<std_msgs::msg::Float32MultiArray>(
"objects", rclcpp::QoS(1).reliability((rmw_qos_reliability_policy_t)1));
58 pubStamped_ = node->create_publisher<find_object_2d::msg::ObjectsStamped>(
"objectsStamped", rclcpp::QoS(1).reliability((rmw_qos_reliability_policy_t)1));
59 pubInfo_ = node->create_publisher<find_object_2d::msg::DetectionInfo>(
"info", rclcpp::QoS(1).reliability((rmw_qos_reliability_policy_t)1));
67 if(info.
objDetected_.size() && !depth.empty() && depthConstant != 0.0f)
69 std::vector<geometry_msgs::msg::TransformStamped> transforms;
70 char multiSubId =
'b';
72 QMultiMap<int, QSize>::const_iterator iterSizes=info.
objDetectedSizes_.constBegin();
73 for(QMultiMap<int, QTransform>::const_iterator iter=info.
objDetected_.constBegin();
79 float objectWidth = iterSizes->width();
80 float objectHeight = iterSizes->height();
85 multiSuffix = QString(
"_") + multiSubId++;
94 QPointF center = iter->map(QPointF(objectWidth/2, objectHeight/2));
95 cv::Vec3f center3D = this->
getDepth(depth,
96 center.x()+0.5f, center.y()+0.5f,
97 float(depth.cols/2)-0.5f, float(depth.rows/2)-0.5f,
98 1.0f/depthConstant, 1.0f/depthConstant);
104 QPointF xAxis = iter->map(QPointF(3*objectWidth/4, objectHeight/2));
106 xAxis.x()+0.5f, xAxis.y()+0.5f,
107 float(depth.cols/2)-0.5f, float(depth.rows/2)-0.5f,
108 1.0f/depthConstant, 1.0f/depthConstant);
110 QPointF yAxis = iter->map(QPointF(objectWidth/2, 3*objectHeight/4));
112 yAxis.x()+0.5f, yAxis.y()+0.5f,
113 float(depth.cols/2)-0.5f, float(depth.rows/2)-0.5f,
114 1.0f/depthConstant, 1.0f/depthConstant);
117 if((std::isfinite(center3D.val[2]) &&
usePnP_) ||
118 (std::isfinite(center3D.val[0]) && std::isfinite(center3D.val[1]) && std::isfinite(center3D.val[2]) &&
119 std::isfinite(axisEndX.val[0]) && std::isfinite(axisEndX.val[1]) && std::isfinite(axisEndX.val[2]) &&
120 std::isfinite(axisEndY.val[0]) && std::isfinite(axisEndY.val[1]) && std::isfinite(axisEndY.val[2])))
122 geometry_msgs::msg::TransformStamped transform;
123 transform.transform.rotation.x=0;
124 transform.transform.rotation.y=0;
125 transform.transform.rotation.z=0;
126 transform.transform.rotation.w=1;
127 transform.transform.translation.x=0;
128 transform.transform.translation.y=0;
129 transform.transform.translation.z=0;
130 transform.child_frame_id = QString(
"%1_%2%3").arg(
objFramePrefix_.c_str()).arg(
id).arg(multiSuffix).toStdString();
131 transform.header.frame_id = header.
frameId_.toStdString();
132 transform.header.stamp.sec = header.
sec_;
133 transform.header.stamp.nanosec = header.
nsec_;
138 std::vector<cv::Point3f> objectPoints(4);
139 std::vector<cv::Point2f> imagePoints(4);
141 objectPoints[0] = cv::Point3f(-0.5, -(objectHeight/objectWidth)/2.0
f,0);
142 objectPoints[1] = cv::Point3f(0.5,-(objectHeight/objectWidth)/2.0
f,0);
143 objectPoints[2] = cv::Point3f(0.5,(objectHeight/objectWidth)/2.0
f,0);
144 objectPoints[3] = cv::Point3f(-0.5,(objectHeight/objectWidth)/2.0
f,0);
146 QPointF pt = iter->map(QPointF(0, 0));
147 imagePoints[0] = cv::Point2f(pt.x(), pt.y());
148 pt = iter->map(QPointF(objectWidth, 0));
149 imagePoints[1] = cv::Point2f(pt.x(), pt.y());
150 pt = iter->map(QPointF(objectWidth, objectHeight));
151 imagePoints[2] = cv::Point2f(pt.x(), pt.y());
152 pt = iter->map(QPointF(0, objectHeight));
153 imagePoints[3] = cv::Point2f(pt.x(), pt.y());
155 cv::Mat cameraMatrix = cv::Mat::eye(3,3,CV_64FC1);
156 cameraMatrix.at<
double>(0,0) = 1.0
f/depthConstant;
157 cameraMatrix.at<
double>(1,1) = 1.0
f/depthConstant;
158 cameraMatrix.at<
double>(0,2) =
float(depth.cols/2)-0.5f;
159 cameraMatrix.at<
double>(1,2) =
float(depth.rows/2)-0.5f;
162 cv::Mat rvec(1,3, CV_64FC1);
163 cv::Mat tvec(1,3, CV_64FC1);
164 cv::solvePnP(objectPoints, imagePoints, cameraMatrix, distCoeffs, rvec, tvec);
167 cv::Rodrigues(rvec, R);
169 R.at<
double>(0,0), R.at<
double>(0,1), R.at<
double>(0,2),
170 R.at<
double>(1,0), R.at<
double>(1,1), R.at<
double>(1,2),
171 R.at<
double>(2,0), R.at<
double>(2,1), R.at<
double>(2,2));
173 transform.transform.translation.x = tvec.at<
double>(0)*(center3D.val[2]/tvec.at<
double>(2));
174 transform.transform.translation.y = tvec.at<
double>(1)*(center3D.val[2]/tvec.at<
double>(2));
175 transform.transform.translation.z = tvec.at<
double>(2)*(center3D.val[2]/tvec.at<
double>(2));
179 tf2::Vector3 xAxis(axisEndX.val[0] - center3D.val[0], axisEndX.val[1] - center3D.val[1], axisEndX.val[2] - center3D.val[2]);
181 tf2::Vector3 yAxis(axisEndY.val[0] - center3D.val[0], axisEndY.val[1] - center3D.val[1], axisEndY.val[2] - center3D.val[2]);
183 tf2::Vector3 zAxis = xAxis.cross(yAxis);
186 xAxis.x(), yAxis.x() ,zAxis.x(),
187 xAxis.y(), yAxis.y(), zAxis.y(),
188 xAxis.z(), yAxis.z(), zAxis.z());
190 transform.transform.translation.x = center3D.val[0];
191 transform.transform.translation.y = center3D.val[1];
192 transform.transform.translation.z = center3D.val[2];
197 q2.
setRPY(CV_PI/2.0, CV_PI/2.0, 0);
200 transforms.push_back(transform);
204 RCLCPP_WARN(
node_->get_logger(),
"Object %d detected, center 2D at (%f,%f), but invalid depth, cannot set frame \"%s\"! " 205 "(maybe object is too near of the camera or bad depth image)\n",
207 center.x(), center.y(),
208 QString(
"%1_%2").arg(
objFramePrefix_.c_str()).arg(
id).toStdString().c_str());
211 if(transforms.size())
217 if(
pub_->get_subscription_count() ||
pubStamped_->get_subscription_count() ||
pubInfo_->get_subscription_count())
219 std_msgs::msg::Float32MultiArray msg;
220 find_object_2d::msg::ObjectsStamped msgStamped;
221 find_object_2d::msg::DetectionInfo infoMsg;
222 if(
pubInfo_->get_subscription_count())
232 msg.data = std::vector<float>(info.
objDetected_.size()*12);
233 msgStamped.objects.data = std::vector<float>(info.
objDetected_.size()*12);
242 QMultiMap<int, QSize>::const_iterator iterSizes=info.
objDetectedSizes_.constBegin();
246 for(QMultiMap<int, QTransform>::const_iterator iter=info.
objDetected_.constBegin();
248 ++iter, ++iterSizes, ++iterFilePaths, ++infoIndex, ++iterInliers, ++iterOutliers)
250 if(
pub_->get_subscription_count() ||
pubStamped_->get_subscription_count())
252 msg.data[i] = msgStamped.objects.data[i] = iter.key(); ++i;
253 msg.data[i] = msgStamped.objects.data[i] = iterSizes->width(); ++i;
254 msg.data[i] = msgStamped.objects.data[i] = iterSizes->height(); ++i;
255 msg.data[i] = msgStamped.objects.data[i] = iter->m11(); ++i;
256 msg.data[i] = msgStamped.objects.data[i] = iter->m12(); ++i;
257 msg.data[i] = msgStamped.objects.data[i] = iter->m13(); ++i;
258 msg.data[i] = msgStamped.objects.data[i] = iter->m21(); ++i;
259 msg.data[i] = msgStamped.objects.data[i] = iter->m22(); ++i;
260 msg.data[i] = msgStamped.objects.data[i] = iter->m23(); ++i;
261 msg.data[i] = msgStamped.objects.data[i] = iter->m31(); ++i;
262 msg.data[i] = msgStamped.objects.data[i] = iter->m32(); ++i;
263 msg.data[i] = msgStamped.objects.data[i] = iter->m33(); ++i;
266 if(
pubInfo_->get_subscription_count())
268 infoMsg.ids[infoIndex].data = iter.key();
269 infoMsg.widths[infoIndex].data = iterSizes->width();
270 infoMsg.heights[infoIndex].data = iterSizes->height();
271 infoMsg.file_paths[infoIndex].data = iterFilePaths.value().toStdString();
272 infoMsg.inliers[infoIndex].data = iterInliers.value();
273 infoMsg.outliers[infoIndex].data = iterOutliers.value();
274 infoMsg.homographies[infoIndex].data.resize(9);
275 infoMsg.homographies[infoIndex].data[0] = iter->m11();
276 infoMsg.homographies[infoIndex].data[1] = iter->m12();
277 infoMsg.homographies[infoIndex].data[2] = iter->m13();
278 infoMsg.homographies[infoIndex].data[3] = iter->m21();
279 infoMsg.homographies[infoIndex].data[4] = iter->m22();
280 infoMsg.homographies[infoIndex].data[5] = iter->m23();
281 infoMsg.homographies[infoIndex].data[6] = iter->m31();
282 infoMsg.homographies[infoIndex].data[7] = iter->m32();
283 infoMsg.homographies[infoIndex].data[8] = iter->m33();
286 if(
pub_->get_subscription_count())
293 msgStamped.header.frame_id = header.
frameId_.toStdString();
294 msgStamped.header.stamp.sec = header.
sec_;
295 msgStamped.header.stamp.nanosec = header.
nsec_;
298 if(
pubInfo_->get_subscription_count())
301 infoMsg.header.frame_id = header.
frameId_.toStdString();
302 infoMsg.header.stamp.sec = header.
sec_;
303 infoMsg.header.stamp.nanosec = header.
nsec_;
314 if(!(x >=0 && x<depthImage.cols && y >=0 && y<depthImage.rows))
316 RCLCPP_ERROR(
node_->get_logger(),
"Point must be inside the image (x=%d, y=%d), image size=(%d,%d)",
318 depthImage.cols, depthImage.rows);
320 std::numeric_limits<float>::quiet_NaN (),
321 std::numeric_limits<float>::quiet_NaN (),
322 std::numeric_limits<float>::quiet_NaN ());
332 bool isInMM = depthImage.type() == CV_16UC1;
335 float unit_scaling = isInMM?0.001f:1.0f;
336 float constant_x = unit_scaling / fx;
337 float constant_y = unit_scaling / fy;
338 float bad_point = std::numeric_limits<float>::quiet_NaN ();
344 depth = (float)depthImage.at<uint16_t>(y,x);
345 isValid = depth != 0.0f;
349 depth = depthImage.at<
float>(y,x);
350 isValid = std::isfinite(depth) && depth > 0.0f;
356 pt.val[0] = pt.val[1] = pt.val[2] = bad_point;
361 pt.val[0] = (float(x) - center_x) * depth * constant_x;
362 pt.val[1] = (float(y) - center_y) * depth * constant_y;
363 pt.val[2] = depth*unit_scaling;
void setRPY(const tf2Scalar &roll, const tf2Scalar &pitch, const tf2Scalar &yaw)
tf::TransformBroadcaster tfBroadcaster_
ros::Publisher pubStamped_
QMultiMap< int, QString > objDetectedFilePaths_
QMultiMap< int, QSize > objDetectedSizes_
void publish(const boost::shared_ptr< M > &message) const
QMultiMap< int, int > objDetectedInliersCount_
FindObjectROS(QObject *parent=0)
void objectsFound(const find_object::DetectionInfo &, const find_object::Header &, const cv::Mat &, float)
QMultiMap< int, QTransform > objDetected_
std::string objFramePrefix_
void publish(const find_object::DetectionInfo &info, const find_object::Header &header, const cv::Mat &depth, float depthConstant)
QMultiMap< int, int > objDetectedOutliersCount_
cv::Vec3f getDepth(const cv::Mat &depthImage, int x, int y, float cx, float cy, float fx, float fy)
Quaternion normalized() const
void getRotation(Quaternion &q) const