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