00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "FindObjectROS.h"
00029
00030 #include <std_msgs/Float32MultiArray.h>
00031 #include "find_object_2d/ObjectsStamped.h"
00032
00033 #include <cmath>
00034
00035 using namespace find_object;
00036
00037 FindObjectROS::FindObjectROS(const std::string & objFramePrefix, QObject * parent) :
00038 FindObject(parent),
00039 objFramePrefix_("object")
00040 {
00041 ros::NodeHandle pnh("~");
00042 pnh.param("object_prefix", objFramePrefix_, objFramePrefix_);
00043
00044 ros::NodeHandle nh;
00045
00046 pub_ = nh.advertise<std_msgs::Float32MultiArray>("objects", 1);
00047 pubStamped_ = nh.advertise<find_object_2d::ObjectsStamped>("objectsStamped", 1);
00048
00049 this->connect(this, SIGNAL(objectsFound(find_object::DetectionInfo)), this, SLOT(publish(find_object::DetectionInfo)));
00050 }
00051
00052 void FindObjectROS::publish(const find_object::DetectionInfo & info)
00053 {
00054
00055 if(info.objDetected_.size() && !depth_.empty() && depthConstant_ != 0.0f)
00056 {
00057 std::vector<tf::StampedTransform> transforms;
00058 QMultiMap<int, QSize>::const_iterator iterSizes=info.objDetectedSizes_.constBegin();
00059 for(QMultiMap<int, QTransform>::const_iterator iter=info.objDetected_.constBegin();
00060 iter!=info.objDetected_.constEnd();
00061 ++iter, ++iterSizes)
00062 {
00063
00064 int id = iter.key();
00065 float objectWidth = iterSizes->width();
00066 float objectHeight = iterSizes->height();
00067
00068
00069 QPointF center = iter->map(QPointF(objectWidth/2, objectHeight/2));
00070 QPointF xAxis = iter->map(QPointF(3*objectWidth/4, objectHeight/2));
00071 QPointF yAxis = iter->map(QPointF(objectWidth/2, 3*objectHeight/4));
00072
00073 cv::Vec3f center3D = this->getDepth(depth_,
00074 center.x()+0.5f, center.y()+0.5f,
00075 float(depth_.cols/2)-0.5f, float(depth_.rows/2)-0.5f,
00076 1.0f/depthConstant_, 1.0f/depthConstant_);
00077
00078 cv::Vec3f axisEndX = this->getDepth(depth_,
00079 xAxis.x()+0.5f, xAxis.y()+0.5f,
00080 float(depth_.cols/2)-0.5f, float(depth_.rows/2)-0.5f,
00081 1.0f/depthConstant_, 1.0f/depthConstant_);
00082
00083 cv::Vec3f axisEndY = this->getDepth(depth_,
00084 yAxis.x()+0.5f, yAxis.y()+0.5f,
00085 float(depth_.cols/2)-0.5f, float(depth_.rows/2)-0.5f,
00086 1.0f/depthConstant_, 1.0f/depthConstant_);
00087
00088 if(std::isfinite(center3D.val[0]) && std::isfinite(center3D.val[1]) && std::isfinite(center3D.val[2]) &&
00089 std::isfinite(axisEndX.val[0]) && std::isfinite(axisEndX.val[1]) && std::isfinite(axisEndX.val[2]) &&
00090 std::isfinite(axisEndY.val[0]) && std::isfinite(axisEndY.val[1]) && std::isfinite(axisEndY.val[2]))
00091 {
00092 tf::StampedTransform transform;
00093 transform.setIdentity();
00094 transform.child_frame_id_ = QString("%1_%2").arg(objFramePrefix_.c_str()).arg(id).toStdString();
00095 transform.frame_id_ = frameId_;
00096 transform.stamp_ = stamp_;
00097 transform.setOrigin(tf::Vector3(center3D.val[0], center3D.val[1], center3D.val[2]));
00098
00099
00100 tf::Vector3 xAxis(axisEndX.val[0] - center3D.val[0], axisEndX.val[1] - center3D.val[1], axisEndX.val[2] - center3D.val[2]);
00101 xAxis.normalize();
00102 tf::Vector3 yAxis(axisEndY.val[0] - center3D.val[0], axisEndY.val[1] - center3D.val[1], axisEndY.val[2] - center3D.val[2]);
00103 yAxis.normalize();
00104 tf::Vector3 zAxis = xAxis*yAxis;
00105 tf::Matrix3x3 rotationMatrix(
00106 xAxis.x(), yAxis.x() ,zAxis.x(),
00107 xAxis.y(), yAxis.y(), zAxis.y(),
00108 xAxis.z(), yAxis.z(), zAxis.z());
00109 tf::Quaternion q;
00110 rotationMatrix.getRotation(q);
00111
00112 q *= tf::createQuaternionFromRPY(CV_PI/2.0, CV_PI/2.0, 0);
00113 transform.setRotation(q.normalized());
00114
00115 transforms.push_back(transform);
00116 }
00117 else
00118 {
00119 ROS_WARN("Object %d detected, center 2D at (%f,%f), but invalid depth, cannot set frame \"%s\"! "
00120 "(maybe object is too near of the camera or bad depth image)\n",
00121 id,
00122 center.x(), center.y(),
00123 QString("%1_%2").arg(objFramePrefix_.c_str()).arg(id).toStdString().c_str());
00124 }
00125 }
00126 if(transforms.size())
00127 {
00128 tfBroadcaster_.sendTransform(transforms);
00129 }
00130 }
00131
00132 if(pub_.getNumSubscribers() || pubStamped_.getNumSubscribers())
00133 {
00134 std_msgs::Float32MultiArray msg;
00135 find_object_2d::ObjectsStamped msgStamped;
00136 msg.data = std::vector<float>(info.objDetected_.size()*12);
00137 msgStamped.objects.data = std::vector<float>(info.objDetected_.size()*12);
00138 int i=0;
00139 QMultiMap<int, QSize>::const_iterator iterSizes=info.objDetectedSizes_.constBegin();
00140 for(QMultiMap<int, QTransform>::const_iterator iter=info.objDetected_.constBegin();
00141 iter!=info.objDetected_.constEnd();
00142 ++iter, ++iterSizes)
00143 {
00144 msg.data[i] = msgStamped.objects.data[i] = iter.key(); ++i;
00145 msg.data[i] = msgStamped.objects.data[i] = iterSizes->width(); ++i;
00146 msg.data[i] = msgStamped.objects.data[i] = iterSizes->height(); ++i;
00147 msg.data[i] = msgStamped.objects.data[i] = iter->m11(); ++i;
00148 msg.data[i] = msgStamped.objects.data[i] = iter->m12(); ++i;
00149 msg.data[i] = msgStamped.objects.data[i] = iter->m13(); ++i;
00150 msg.data[i] = msgStamped.objects.data[i] = iter->m21(); ++i;
00151 msg.data[i] = msgStamped.objects.data[i] = iter->m22(); ++i;
00152 msg.data[i] = msgStamped.objects.data[i] = iter->m23(); ++i;
00153 msg.data[i] = msgStamped.objects.data[i] = iter->m31(); ++i;
00154 msg.data[i] = msgStamped.objects.data[i] = iter->m32(); ++i;
00155 msg.data[i] = msgStamped.objects.data[i] = iter->m33(); ++i;
00156 }
00157 if(pub_.getNumSubscribers())
00158 {
00159 pub_.publish(msg);
00160 }
00161 if(pubStamped_.getNumSubscribers())
00162 {
00163
00164 msgStamped.header.frame_id = frameId_;
00165 msgStamped.header.stamp = stamp_;
00166 pubStamped_.publish(msgStamped);
00167 }
00168 }
00169 }
00170
00171 void FindObjectROS::setDepthData(const std::string & frameId,
00172 const ros::Time & stamp,
00173 const cv::Mat & depth,
00174 float depthConstant)
00175 {
00176 frameId_ = frameId;
00177 stamp_ = stamp;
00178 depth_ = depth;
00179 depthConstant_ = depthConstant;
00180 }
00181
00182 cv::Vec3f FindObjectROS::getDepth(const cv::Mat & depthImage,
00183 int x, int y,
00184 float cx, float cy,
00185 float fx, float fy)
00186 {
00187 if(!(x >=0 && x<depthImage.cols && y >=0 && y<depthImage.rows))
00188 {
00189 ROS_ERROR("Point must be inside the image (x=%d, y=%d), image size=(%d,%d)",
00190 x, y,
00191 depthImage.cols, depthImage.rows);
00192 return cv::Vec3f(
00193 std::numeric_limits<float>::quiet_NaN (),
00194 std::numeric_limits<float>::quiet_NaN (),
00195 std::numeric_limits<float>::quiet_NaN ());
00196 }
00197
00198
00199 cv::Vec3f pt;
00200
00201
00202 float center_x = cx;
00203 float center_y = cy;
00204
00205 bool isInMM = depthImage.type() == CV_16UC1;
00206
00207
00208 float unit_scaling = isInMM?0.001f:1.0f;
00209 float constant_x = unit_scaling / fx;
00210 float constant_y = unit_scaling / fy;
00211 float bad_point = std::numeric_limits<float>::quiet_NaN ();
00212
00213 float depth;
00214 bool isValid;
00215 if(isInMM)
00216 {
00217 depth = (float)depthImage.at<uint16_t>(y,x);
00218 isValid = depth != 0.0f;
00219 }
00220 else
00221 {
00222 depth = depthImage.at<float>(y,x);
00223 isValid = std::isfinite(depth);
00224 }
00225
00226
00227 if (!isValid)
00228 {
00229 pt.val[0] = pt.val[1] = pt.val[2] = bad_point;
00230 }
00231 else
00232 {
00233
00234 pt.val[0] = (float(x) - center_x) * depth * constant_x;
00235 pt.val[1] = (float(y) - center_y) * depth * constant_y;
00236 pt.val[2] = depth*unit_scaling;
00237 }
00238 return pt;
00239 }