00001
00018 #include "fake_object_recognition.h"
00019 #include <rapidxml.hpp>
00020 #include <rapidxml_utils.hpp>
00021 #include <ros/package.h>
00022 #include <boost/algorithm/string/predicate.hpp>
00023 #include <boost/lexical_cast.hpp>
00024 #include <boost/algorithm/string.hpp>
00025 #include "rating.h"
00026 #include "error_simulation.h"
00027 #include <unistd.h>
00028 #include <algorithm>
00029
00030 #include <Eigen/Geometry>
00031
00032 #include "asr_object_database/ObjectMetaData.h"
00033 #include "ApproxMVBB/ComputeApproxMVBB.hpp"
00034
00035 namespace fake_object_recognition {
00036
00037 FakeObjectRecognition::FakeObjectRecognition() : nh_(NODE_NAME), config_changed_(false), recognition_released_(true) {
00038 ROS_DEBUG("Initialize process");
00039 nh_.getParam("fovx", fovx_);
00040 nh_.getParam("fovy", fovy_);
00041 nh_.getParam("ncp", ncp_);
00042 nh_.getParam("fcp", fcp_);
00043 nh_.getParam("frame_world", frame_world_);
00044 nh_.getParam("frame_camera_left", frame_camera_left_);
00045 nh_.getParam("frame_camera_right", frame_camera_right_);
00046 nh_.getParam("config_file_path", config_file_path_);
00047 nh_.getParam("output_rec_objects_topic", output_rec_objects_topic_);
00048 nh_.getParam("output_rec_marker_topic", output_rec_markers_topic_);
00049 nh_.getParam("output_constellation_topic", output_constellation_marker_topic_);
00050 nh_.getParam("output_normals_topic", output_normals_topic_);
00051 nh_.getParam("rating_threshold_d", rating_threshold_d_);
00052 nh_.getParam("rating_threshold_x", rating_threshold_x_);
00053 nh_.getParam("rating_threshold_y", rating_threshold_y_);
00054 nh_.getParam("timer_duration", timer_duration_);
00055
00056 reconfigure_server_.setCallback(boost::bind(&FakeObjectRecognition::configCallback, this, _1, _2));
00057
00058 get_recognizer_service_ = nh_.advertiseService(GET_RECOGNIZER_SERVICE_NAME, &FakeObjectRecognition::processGetRecognizerRequest, this);
00059 release_recognizer_service_ = nh_.advertiseService(RELEASE_RECOGNIZER_SERVICE_NAME, &FakeObjectRecognition::processReleaseRecognizerRequest, this);
00060
00061 get_all_recognizers_service_ = nh_.advertiseService(GET_ALL_RECOGNIZERS_SERVICE_NAME, &FakeObjectRecognition::processGetAllRecognizersRequest, this);
00062 clear_all_recognizers_service_ = nh_.advertiseService(CLEAR_ALL_RECOGNIZERS_SERVICE_NAME, &FakeObjectRecognition::processClearAllRecognizers, this);
00063
00064 recognized_objects_pub_ = nh_.advertise<asr_msgs::AsrObject>(output_rec_objects_topic_, 1);
00065 recognized_objects_marker_pub_ = nh_.advertise<visualization_msgs::Marker>(output_rec_markers_topic_, 1);
00066 generated_constellation_marker_pub_ = nh_.advertise<visualization_msgs::Marker>(output_constellation_marker_topic_, 1);
00067 object_normals_pub_ = nh_.advertise<visualization_msgs::MarkerArray>(output_normals_topic_, 100);
00068
00069 timer_ = nh_.createTimer(ros::Duration(timer_duration_), &FakeObjectRecognition::timerCallback, this);
00070
00071
00072 loadObjects();
00073
00074
00075 ROS_DEBUG_STREAM("Initializing object bounding boxes and normals");
00076
00077 ros::service::waitForService("/asr_object_database/object_meta_data");
00078 object_metadata_service_client_ = nh_.serviceClient<asr_object_database::ObjectMetaData>("/asr_object_database/object_meta_data");
00079
00080 bb_corners_file_name_ = ros::package::getPath("asr_fake_object_recognition") + "/config/bounding_box_corners.xml";
00081
00082 object_database_name_ = "asr_object_database";
00083
00084 for (std::vector<ObjectConfig>::iterator iter = objects_.begin(); iter != objects_.end(); ++iter) {
00085 if (normals_.find(iter->getType()) == normals_.end()) {
00086 ROS_DEBUG_STREAM("Initializing normals of object type " << iter->getType());
00087 normals_[iter->getType()] = getNormals(*iter);
00088 ROS_DEBUG_STREAM("Found " << normals_[iter->getType()].size() << " normals. Normals initialized.");
00089 }
00090 if (bounding_box_corners_.find(iter->getType()) == bounding_box_corners_.end()) {
00091 ROS_DEBUG_STREAM("Initializing bounding box of object type " << iter->getType());
00092 std::array<geometry_msgs::Point, 8> corner_points;
00093 if (!getBBfromFile(corner_points, iter->getType())) {
00094 corner_points = calculateBB(*iter);
00095 }
00096 bounding_box_corners_[iter->getType()] = corner_points;
00097 ROS_DEBUG_STREAM("Found " << bounding_box_corners_[iter->getType()].size() << " bounding box corner points. Bounding box initialized.");
00098 }
00099 }
00100 ROS_INFO("Recognition is initially released");
00101 }
00102
00103 void FakeObjectRecognition::loadObjects() {
00104 objects_.clear();
00105
00106 std::string xml_path;
00107 if (boost::starts_with(config_file_path_, "."))
00108 {
00109 xml_path = ros::package::getPath("asr_fake_object_recognition") + config_file_path_.substr(1);
00110 }
00111 else
00112 {
00113 xml_path = config_file_path_;
00114 }
00115 ROS_DEBUG_STREAM("Path to objects.xml: " << xml_path);
00116
00117 try {
00118 rapidxml::file<> xmlFile(xml_path.c_str());
00119 rapidxml::xml_document<> doc;
00120 doc.parse<0>(xmlFile.data());
00121
00122 rapidxml::xml_node<> *root_node = doc.first_node();
00123 if (root_node) {
00124 rapidxml::xml_node<> *child_node = root_node->first_node();
00125 while (child_node) {
00126 rapidxml::xml_attribute<> *type_attribute = child_node->first_attribute("type");
00127 rapidxml::xml_attribute<> *id_attribute = child_node->first_attribute("id");
00128 rapidxml::xml_attribute<> *mesh_attribute = child_node->first_attribute("mesh");
00129 rapidxml::xml_attribute<> *angles_attribute = child_node->first_attribute("angles");
00130 if (type_attribute && id_attribute && mesh_attribute && angles_attribute) {
00131 std::string type = type_attribute->value();
00132 std::string mesh = mesh_attribute->value();
00133 std::string id = id_attribute->value();
00134 std::string pose_string = child_node->value();
00135 std::string angles = angles_attribute->value();
00136 geometry_msgs::Pose pose;
00137 if (parsePoseString(pose_string, pose, " ,", angles)) {
00138 objects_.push_back(ObjectConfig(type, id, pose, mesh));
00139 }
00140 }
00141 child_node = child_node->next_sibling();
00142 }
00143 }
00144 } catch(std::runtime_error err) {
00145 ROS_DEBUG_STREAM("Can't parse xml-file. Runtime error: " << err.what());
00146 } catch (rapidxml::parse_error err) {
00147 ROS_DEBUG_STREAM("Can't parse xml-file Parse error: " << err.what());
00148 }
00149
00150 }
00151
00152
00153 bool FakeObjectRecognition::parsePoseString(std::string pose_in, geometry_msgs::Pose &pose_out, std::string delim, std::string angles) {
00154 std::vector<std::string> strvec;
00155
00156 boost::algorithm::trim_if(pose_in, boost::algorithm::is_any_of(delim));
00157 boost::algorithm::split(strvec, pose_in, boost::algorithm::is_any_of(delim), boost::algorithm::token_compress_on);
00158 if (strvec.size() == 6 || strvec.size() == 7) {
00159 try {
00160 pose_out.position.x = boost::lexical_cast<double>(strvec[0]);
00161 pose_out.position.y = boost::lexical_cast<double>(strvec[1]);
00162 pose_out.position.z = boost::lexical_cast<double>(strvec[2]);
00163
00164 if(angles == "quaternion" && strvec.size() == 7)
00165 {
00166 pose_out.orientation.w = boost::lexical_cast<double>(strvec[3]);
00167 pose_out.orientation.x = boost::lexical_cast<double>(strvec[4]);
00168 pose_out.orientation.y = boost::lexical_cast<double>(strvec[5]);
00169 pose_out.orientation.z = boost::lexical_cast<double>(strvec[6]);
00170 }
00171 else if(angles == "euler" && strvec.size() == 6)
00172 {
00173 double euler0,euler1,euler2;
00174 euler0 = boost::lexical_cast<double>(strvec[3]);
00175 euler1 = boost::lexical_cast<double>(strvec[4]);
00176 euler2 = boost::lexical_cast<double>(strvec[5]);
00177
00178 Eigen::Matrix3d rotationMatrix;
00179 rotationMatrix = Eigen::AngleAxisd(euler0 * (M_PI / 180), Eigen::Vector3d::UnitX())
00180 * Eigen::AngleAxisd(euler1 * (M_PI / 180), Eigen::Vector3d::UnitY())
00181 * Eigen::AngleAxisd(euler2 * (M_PI / 180), Eigen::Vector3d::UnitZ());
00182
00183 Eigen::Quaternion<double> result(rotationMatrix);
00184 pose_out.orientation.w = result.w();
00185 pose_out.orientation.x = result.x();
00186 pose_out.orientation.y = result.y();
00187 pose_out.orientation.z = result.z();
00188 }
00189 else
00190 {
00191 ROS_ERROR("Invalid XML syntax.");
00192 nh_.shutdown();
00193 }
00194
00195 return true;
00196 } catch (boost::bad_lexical_cast err) {
00197 ROS_DEBUG_STREAM("Can't cast node-value. Cast error: " << err.what());
00198 }
00199 }
00200 return false;
00201 }
00202
00203 bool FakeObjectRecognition::processGetRecognizerRequest(GetRecognizer::Request &req, GetRecognizer::Response &res) {
00204 ROS_DEBUG("Get recognizer request");
00205 if(std::find(objects_to_rec_.begin(), objects_to_rec_.end(), req.object_type_name) != objects_to_rec_.end()) {
00206 ROS_DEBUG("Requested object is already in list of recognizable objects");
00207 } else {
00208 ROS_DEBUG("Add requested object to recognizable object list");
00209 objects_to_rec_.push_back(req.object_type_name);
00210 recognition_released_ = false;
00211 }
00212 return true;
00213 }
00214
00215 bool FakeObjectRecognition::processReleaseRecognizerRequest(ReleaseRecognizer::Request &req, ReleaseRecognizer::Response &res) {
00216 ROS_DEBUG("Release recognizer request");
00217 objects_to_rec_.erase(std::remove(objects_to_rec_.begin(), objects_to_rec_.end(), req.object_type_name), objects_to_rec_.end());
00218 if (!(objects_to_rec_.size() > 0)) {
00219 recognition_released_ = true;
00220 }
00221 return true;
00222 }
00223
00224 bool FakeObjectRecognition::processGetAllRecognizersRequest(GetAllRecognizers::Request &req, GetAllRecognizers::Response &res) {
00225 ROS_DEBUG("Get all recognizers request");
00226
00227 objects_to_rec_.clear();
00228 for(std::vector<ObjectConfig>::iterator objectIt = objects_.begin(); objectIt != objects_.end(); objectIt++){
00229 ROS_DEBUG_STREAM("Adding objects " << objectIt->getType() << " to recognizable list");
00230 objects_to_rec_.push_back(objectIt->getType());
00231
00232 }
00233
00234 recognition_released_ = false;
00235 return true;
00236
00237 }
00238
00239 bool FakeObjectRecognition::processClearAllRecognizers(ClearAllRecognizers::Request &req, ClearAllRecognizers::Response &res) {
00240 ROS_DEBUG("Clear all recognizers request");
00241 objects_to_rec_.clear();
00242 recognition_released_ = true;
00243 return true;
00244 }
00245
00246 void FakeObjectRecognition::timerCallback(const ros::TimerEvent& event) {
00247 for (std::vector<ObjectConfig>::iterator iter = objects_.begin(); iter != objects_.end(); ++iter) {
00248
00249 asr_msgs::AsrObjectPtr asr_msg = createAsrMessage(*iter, iter->getPose(), frame_world_);
00250 generated_constellation_marker_pub_.publish(createMarker(asr_msg, iter - objects_.begin(), 2 * timer_duration_, true));
00251
00252 visualization_msgs::MarkerArray::Ptr normal_markers = createNormalMarker(*iter, (iter - objects_.begin()) * 100, 10 * timer_duration_);
00253 object_normals_pub_.publish(normal_markers);
00254 }
00255 if (!recognition_released_) {
00256 doRecognition();
00257 }
00258 }
00259
00260 void FakeObjectRecognition::configCallback(FakeObjectRecognitionConfig &config, uint32_t level) {
00261 config_changed_ = true;
00262 config_ = config;
00263 }
00264
00265 void FakeObjectRecognition::doRecognition() {
00266 ROS_INFO("Do recognition");
00267
00268 if (config_changed_) {
00269 ROS_DEBUG("Configuration change");
00270 ROS_DEBUG("Load Objects");
00271 if (config_file_path_ != config_.config_file_path) {
00272 ROS_INFO_STREAM("Path to config file has changed. Recognition is released");
00273 config_file_path_ = config_.config_file_path;
00274 objects_to_rec_.clear();
00275 recognition_released_ = true;
00276 return;
00277 }
00278 loadObjects();
00279 err_sim_ = ErrorSimulation(config_.use_pose_invalidation, config_.use_position_noise, config_.use_orientation_noise);
00280 err_sim_.setProbPoseInval(config_.prob_pose_invalidation);
00281 err_sim_.setPoseNoiseDistMean(config_.pos_noise_normal_dist_mean);
00282 err_sim_.setPoseNoiseDistDev(config_.pos_noise_normal_dist_dev);
00283 err_sim_.setOrXNoiseDistMean(config_.or_x_noise_normal_dist_mean);
00284 err_sim_.setOrXNoiseDistDev(config_.or_x_noise_normal_dist_dev);
00285 err_sim_.setOrYNoiseDistMean(config_.or_y_noise_normal_dist_mean);
00286 err_sim_.setOrYNoiseDistDev(config_.or_y_noise_normal_dist_dev);
00287 err_sim_.setOrZNoiseDistMean(config_.or_z_noise_normal_dist_mean);
00288 err_sim_.setOrZNoiseDistDev(config_.or_z_noise_normal_dist_dev);
00289 config_changed_ = false;
00290 }
00291
00292 std::string recognizable_objects;
00293 std::string objects_to_rec;
00294 for (std::vector<ObjectConfig>::iterator iter = objects_.begin(); iter != objects_.end(); ++iter) {
00295 recognizable_objects += iter->getType() + " ";
00296 }
00297 ROS_DEBUG_STREAM("All recognizable objects: " << recognizable_objects);
00298
00299 for (std::vector<std::string>::iterator iter = objects_to_rec_.begin(); iter != objects_to_rec_.end(); ++iter) {
00300 objects_to_rec += *iter + " ";
00301 }
00302 ROS_DEBUG_STREAM("Objects to recognize: " << objects_to_rec);
00303
00304 for (std::vector<ObjectConfig>::iterator iter = objects_.begin(); iter != objects_.end(); ++iter) {
00305 if(std::find(objects_to_rec_.begin(), objects_to_rec_.end(), iter->getType()) == objects_to_rec_.end()) {
00306 continue;
00307 }
00308 ROS_INFO_STREAM("Current object: '" << iter->getType() << "'");
00309 geometry_msgs::Pose pose_left;
00310 geometry_msgs::Pose pose_right;
00311
00312 std::array<geometry_msgs::Point, 8> bounding_box = bounding_box_corners_[iter->getType()];
00313 std::array<geometry_msgs::Point, 8> bb_left;
00314 std::array<geometry_msgs::Point, 8> bb_right;
00315
00316 std::vector<geometry_msgs::Point> normals = normals_[iter->getType()];
00317 std::vector<geometry_msgs::Point> normals_left;
00318 std::vector<geometry_msgs::Point> normals_right;
00319
00320 try {
00321 if (config_.use_camera_pose) {
00322 ROS_DEBUG_STREAM("Transform into camera frame");
00323
00324 pose_left = transformFrame((*iter).getPose(), frame_world_, frame_camera_left_);
00325 pose_right = transformFrame((*iter).getPose(), frame_world_, frame_camera_right_);
00326
00327 ROS_DEBUG_STREAM("Pose left: " << pose_left.position.x << " " << pose_left.position.y << " " << pose_left.position.z << " " << pose_left.orientation.w << " " << pose_left.orientation.x << " " << pose_left.orientation.y << " " << pose_left.orientation.z << " ");
00328 ROS_DEBUG_STREAM("Pose right: " << pose_right.position.x << " " << pose_right.position.y << " " << pose_right.position.z << " " << pose_right.orientation.w << " " << pose_right.orientation.x << " " << pose_right.orientation.y << " " << pose_right.orientation.z << " ");
00329
00330 pose_left = err_sim_.addNoiseToOrientation(err_sim_.addNoiseToPosition(pose_left));
00331 pose_right = err_sim_.addNoiseToOrientation(err_sim_.addNoiseToPosition(pose_right));
00332
00333 ROS_DEBUG_STREAM("Pose left (with errors): " << pose_left.position.x << " " << pose_left.position.y << " " << pose_left.position.z << " " << pose_left.orientation.w << " " << pose_left.orientation.x << " " << pose_left.orientation.y << " " << pose_left.orientation.z << " ");
00334 ROS_DEBUG_STREAM("Pose right (with errors): " << pose_right.position.x << " " << pose_right.position.y << " " << pose_right.position.z << " " << pose_right.orientation.w << " " << pose_right.orientation.x << " " << pose_right.orientation.y << " " << pose_right.orientation.z << " ");
00335
00336
00337 Eigen::Quaterniond rot_left(pose_left.orientation.w, pose_left.orientation.x, pose_left.orientation.y, pose_left.orientation.z);
00338 Eigen::Quaterniond rot_right(pose_right.orientation.w, pose_right.orientation.x, pose_right.orientation.y, pose_right.orientation.z);
00339
00340 ROS_DEBUG_STREAM("Transform " << bounding_box.size() << " bounding box corner points.");
00341 Eigen::Vector3d trans_left(pose_left.position.x, pose_left.position.y, pose_left.position.z);
00342 Eigen::Vector3d trans_right(pose_right.position.x, pose_right.position.y, pose_right.position.z);
00343 bb_left = transformPoints(bounding_box, rot_left, trans_left);
00344 bb_right = transformPoints(bounding_box, rot_right, trans_right);
00345
00346
00347 ROS_DEBUG_STREAM("Transform " << normals.size() << " normals.");
00348 normals_left = transformPoints(normals, rot_left, Eigen::Vector3d(0.0, 0.0, 0.0));
00349 normals_right = transformPoints(normals, rot_right, Eigen::Vector3d(0.0, 0.0, 0.0));
00350 } else {
00351 ROS_DEBUG_STREAM("Camera pose is not used");
00352 }
00353 } catch (tf2::LookupException &exc) {
00354 ROS_DEBUG_STREAM("Lookup exception at doRecognition: " << exc.what());
00355 continue;
00356 } catch (tf2::ExtrapolationException &exc) {
00357 ROS_DEBUG_STREAM("Extrapolation exception at doRecognition: " << exc.what());
00358 continue;
00359 } catch (tf2::InvalidArgumentException &exc) {
00360 ROS_DEBUG_STREAM("Invalid argument exception at doRecognition: " << exc.what());
00361 continue;
00362 } catch (tf2::ConnectivityException &exc) {
00363 ROS_DEBUG_STREAM("Connectivity exception at doRecognition: " << exc.what());
00364 continue;
00365 }
00366
00367
00368 if (!(config_.use_camera_pose) || objectIsVisible(bb_left, bb_right, pose_left, pose_right, normals_left, normals_right)) {
00369 ROS_INFO_STREAM("Object '" << (*iter).getType() << "' was found");
00370 asr_msgs::AsrObjectPtr asr_msg;
00371 if (!(config_.use_camera_pose)) {
00372 asr_msg = createAsrMessage(*iter, iter->getPose(), frame_world_);
00373 } else {
00374 asr_msg = createAsrMessage(*iter, pose_left, frame_camera_left_);
00375 }
00376 recognized_objects_pub_.publish(asr_msg);
00377 recognized_objects_marker_pub_.publish(createMarker(asr_msg, iter - objects_.begin(), 10 * timer_duration_));
00378 }
00379 }
00380 ROS_INFO("---------------------------------- \n");
00381 }
00382
00383 geometry_msgs::Pose FakeObjectRecognition::transformFrame(const geometry_msgs::Pose &pose, const std::string &frame_from, const std::string &frame_to) {
00384
00385 tf::StampedTransform transform;
00386 listener_.lookupTransform(frame_from, frame_to, ros::Time(0), transform);
00387
00388 geometry_msgs::PoseStamped stamped_in;
00389 stamped_in.header.frame_id = frame_from;
00390 stamped_in.header.stamp = transform.stamp_;
00391 stamped_in.pose.position = pose.position;
00392 stamped_in.pose.orientation = pose.orientation;
00393
00394 geometry_msgs::PoseStamped stamped_out;
00395 listener_.transformPose(frame_to, stamped_in, stamped_out);
00396
00397 geometry_msgs::Pose result;
00398 result.position = stamped_out.pose.position;
00399 result.orientation = stamped_out.pose.orientation;
00400
00401 return result;
00402 }
00403
00404 bool FakeObjectRecognition::objectIsVisible(const geometry_msgs::Pose &pose_left, const geometry_msgs::Pose &pose_right) {
00405 Rating rating(fovx_, fovy_, ncp_, fcp_);
00406 bool pose_inval = err_sim_.poseInvalidation();
00407 if (!pose_inval) {ROS_DEBUG("Pose is invalid (simulated error)");}
00408
00409 bool rating_result = false;
00410 ROS_DEBUG("Rating in left camera:");
00411 bool left_rating = rating.ratePose(pose_left, rating_threshold_d_, rating_threshold_x_, rating_threshold_y_);
00412 ROS_DEBUG("Rating in left camera:");
00413 bool right_rating = rating.ratePose(pose_right, rating_threshold_d_, rating_threshold_x_, rating_threshold_y_);
00414
00415 switch(config_.frustum_mode) {
00416 case 1: rating_result = left_rating | right_rating; ROS_DEBUG("Rating left and right pose (OR)"); break;
00417 case 2: rating_result = left_rating; ROS_DEBUG("Rating left pose only"); break;
00418 case 3: rating_result = right_rating; ROS_DEBUG("Rating right pose only"); break;
00419 default: rating_result = left_rating & right_rating; ROS_DEBUG("Rating left and right pose (AND)");
00420 }
00421
00422
00423 if (rating_result && pose_inval) {
00424 return true;
00425 }
00426 return false;
00427 }
00428
00429 bool FakeObjectRecognition::objectIsVisible(const std::array<geometry_msgs::Point, 8> &bb_left, const std::array<geometry_msgs::Point, 8> &bb_right,
00430 const geometry_msgs::Pose &pose_left, const geometry_msgs::Pose &pose_right,
00431 const std::vector<geometry_msgs::Point> &normals_left, const std::vector<geometry_msgs::Point> &normals_right) {
00432 Rating rating(fovx_, fovy_, ncp_, fcp_);
00433 bool pose_inval = err_sim_.poseInvalidation();
00434 if (!pose_inval) {ROS_DEBUG("Pose is invalid (simulated error)");}
00435
00436 bool rating_result = false;
00437 bool left_rating = rating.rateBBandNormal(pose_left, bb_left, normals_left, rating_threshold_);
00438 bool right_rating = rating.rateBBandNormal(pose_right, bb_right, normals_right, rating_threshold_);
00439
00440
00441 switch(config_.frustum_mode) {
00442 case 1: rating_result = left_rating | right_rating; ROS_DEBUG("Rating left and right pose (OR)"); break;
00443 case 2: rating_result = left_rating; ROS_DEBUG("Rating left pose only"); break;
00444 case 3: rating_result = right_rating; ROS_DEBUG("Rating right pose only"); break;
00445 default: rating_result = left_rating & right_rating; ROS_DEBUG("Rating left and right pose (AND)");
00446 }
00447
00448
00449 if (rating_result && pose_inval) {
00450 return true;
00451 }
00452 return false;
00453 }
00454
00455 asr_msgs::AsrObjectPtr FakeObjectRecognition::createAsrMessage(const ObjectConfig &object_config, const geometry_msgs::Pose &pose, const std::string &frame_id) {
00456 asr_msgs::AsrObjectPtr object;
00457 object.reset(new asr_msgs::AsrObject());
00458
00459 std_msgs::Header header;
00460 header.frame_id = frame_id;
00461 header.stamp = ros::Time::now();
00462 object->header = header;
00463 object->providedBy = "fake_object_recognition";
00464
00465 geometry_msgs::PoseWithCovariance pose_covariance;
00466 pose_covariance.pose.position.x = pose.position.x;
00467 pose_covariance.pose.position.y = pose.position.y;
00468 pose_covariance.pose.position.z = pose.position.z;
00469 pose_covariance.pose.orientation.w = pose.orientation.w;
00470 pose_covariance.pose.orientation.x = pose.orientation.x;
00471 pose_covariance.pose.orientation.y = pose.orientation.y;
00472 pose_covariance.pose.orientation.z = pose.orientation.z;
00473
00474 for(unsigned int i = 0; i < pose_covariance.covariance.size(); i++) {
00475 pose_covariance.covariance.at(i) = 0.0f;
00476 }
00477 object->sampledPoses.push_back(pose_covariance);
00478
00479
00480 boost::array< ::geometry_msgs::Point_<std::allocator<void> > , 8> bounding_box;
00481 std::array<geometry_msgs::Point, 8> object_bb = bounding_box_corners_[object_config.getType()];
00482 for (unsigned int i = 0; i < 8; i++) {
00483 bounding_box[i] = object_bb.at(i);
00484 }
00485 object->boundingBox = bounding_box;
00486
00487 if(object_config.getId() == std::string("0"))
00488 {
00489 object->colorName = "textured";
00490 }
00491 else
00492 {
00493 object->color = getMeshColor(object_config.getId());
00494 }
00495 object->type = object_config.getType();
00496
00497 object->identifier = object_config.getId();
00498 object->meshResourcePath = object_config.getMeshName();
00499
00500
00501
00502
00503 return object;
00504 }
00505
00506 visualization_msgs::Marker FakeObjectRecognition::createMarker(const asr_msgs::AsrObjectPtr &object, int id, int lifetime, bool use_col_init) {
00507 visualization_msgs::Marker marker;
00508 marker.header = object->header;
00509 marker.id = id;
00510 marker.action = visualization_msgs::Marker::ADD;
00511 marker.pose.position = object->sampledPoses.front().pose.position;
00512 marker.pose.orientation = object->sampledPoses.front().pose.orientation;
00513
00514 if (use_col_init) {
00515 marker.color = createColorRGBA(0.0, 0.0, 1.0, 0.4);
00516 marker.ns = "Available objects";
00517 } else {
00518 marker.color = getMeshColor(object->identifier);
00519 marker.ns = "Recognition results";
00520 }
00521
00522 marker.scale.x = 0.001;
00523 marker.scale.y = 0.001;
00524 marker.scale.z = 0.001;
00525
00526 marker.mesh_use_embedded_materials = true;
00527 marker.type = visualization_msgs::Marker::MESH_RESOURCE;
00528 marker.mesh_resource = object->meshResourcePath;
00529 marker.lifetime = ros::Duration(lifetime);
00530
00531 return marker;
00532 }
00533
00534
00535
00536 std_msgs::ColorRGBA FakeObjectRecognition::getMeshColor(std::string observed_id)
00537 {
00538 std_msgs::ColorRGBA retColor = FakeObjectRecognition::createColorRGBA(0.0, 0.0, 0.0, 0.0);
00539
00540 if (( observed_id.length() == 12 ) && ( observed_id.find_first_not_of("0123456789") == std::string::npos )) {
00541 float rgba[4];
00542 bool isColor = true;
00543 try {
00544 for (int i = 0; i <= 3; i++) {
00545 std::string temp;
00546 temp = observed_id.substr( (i * 3), 3 );
00547 rgba[i] = std::stof(temp) / 100.0;
00548 }
00549 } catch (std::invalid_argument& ia) {
00550 ROS_DEBUG_STREAM(ia.what());
00551 isColor = false;
00552 }
00553
00554 if(isColor) {
00555 retColor = FakeObjectRecognition::createColorRGBA(rgba[0], rgba[1], rgba[2], 1.0);
00556 }
00557 }
00558 return retColor;
00559 }
00560
00561 std_msgs::ColorRGBA FakeObjectRecognition::createColorRGBA(float red, float green, float blue, float alpha) {
00562 std_msgs::ColorRGBA color;
00563
00564 color.r = red;
00565 color.g = green;
00566 color.b = blue;
00567 color.a = alpha;
00568
00569 return color;
00570 }
00571
00572 std::vector<geometry_msgs::Point> FakeObjectRecognition::transformPoints(std::vector<geometry_msgs::Point> points_list, Eigen::Quaterniond rotation, Eigen::Vector3d translation) {
00573 std::vector<geometry_msgs::Point> result_list = points_list;
00574 rotation.normalize();
00575 Eigen::Matrix3d rot_mat = rotation.toRotationMatrix();
00576 for (unsigned int i = 0; i < points_list.size(); i++) {
00577 Eigen::Vector3d current_point = Eigen::Vector3d(points_list.at(i).x, points_list.at(i).y, points_list.at(i).z);
00578 current_point = rot_mat * current_point;
00579 current_point += translation;
00580 result_list.at(i) = createPoint(current_point.x(), current_point.y(), current_point.z());
00581 }
00582 return result_list;
00583 }
00584
00585 std::array<geometry_msgs::Point, 8> FakeObjectRecognition::transformPoints(std::array<geometry_msgs::Point, 8> points_list, Eigen::Quaterniond rotation, Eigen::Vector3d translation) {
00586 std::vector<geometry_msgs::Point> points_vector;
00587 for (unsigned int i = 0; i < points_list.size(); i++) {
00588 points_vector.push_back(points_list.at(i));
00589 }
00590 points_vector = transformPoints(points_vector, rotation, translation);
00591 std::array<geometry_msgs::Point, 8> result_array;
00592 for (unsigned int i = 0; i < result_array.size(); i++) {
00593 result_array.at(i) = points_vector.at(i);
00594 }
00595 return result_array;
00596 }
00597
00598 visualization_msgs::MarkerArray::Ptr FakeObjectRecognition::createNormalMarker(const ObjectConfig &object, int id, int lifetime) {
00599
00600 visualization_msgs::MarkerArray::Ptr objectNormalsMarkerArrayPtr;
00601
00602 Eigen::Matrix<float, 4, 1> color = Eigen::Matrix<float, 4, 1>(1.0, 1.0, 0.0, 1.0);
00603 Eigen::Matrix<float, 3, 1> scale = Eigen::Matrix<float, 3, 1>(0.005, 0.01, 0.005);
00604 std::string ns = "ObjectNormals";
00605
00606
00607 visualization_msgs::Marker objectNormalMarker;
00608 objectNormalMarker.header.frame_id = "/map";
00609 objectNormalMarker.lifetime = ros::Duration(lifetime);
00610 objectNormalMarker.ns = ns;
00611 objectNormalMarker.action = visualization_msgs::Marker::ADD;
00612
00613 objectNormalMarker.type = visualization_msgs::Marker::ARROW;
00614 objectNormalMarker.pose.position = createPoint(0, 0, 0);
00615 objectNormalMarker.pose.orientation.x = 0.0;
00616 objectNormalMarker.pose.orientation.y = 0.0;
00617 objectNormalMarker.pose.orientation.z = 0.0;
00618 objectNormalMarker.pose.orientation.w = 1.0;
00619
00620 objectNormalMarker.scale.x = scale[0];
00621 objectNormalMarker.scale.y = scale[1];
00622 objectNormalMarker.scale.z = scale[2];
00623
00624 objectNormalMarker.color.r = color[0];
00625 objectNormalMarker.color.g = color[1];
00626 objectNormalMarker.color.b = color[2];
00627 objectNormalMarker.color.a = color[3];
00628
00629 objectNormalsMarkerArrayPtr = boost::make_shared<visualization_msgs::MarkerArray>();
00630
00631 std::vector<geometry_msgs::Point> normals = normals_[object.getType()];
00632 geometry_msgs::Pose object_pose = object.getPose();
00633 Eigen::Quaterniond rotation(object_pose.orientation.w, object_pose.orientation.x, object_pose.orientation.y, object_pose.orientation.z);
00634 normals = transformPoints(normals, rotation, Eigen::Vector3d(0.0, 0.0, 0.0));
00635 for(unsigned int i = 0; i < normals_[object.getType()].size(); i++) {
00636 geometry_msgs::Point start = object.getPose().position;
00637 geometry_msgs::Point end;
00638 end = createPoint(0.07 * normals.at(i).x, 0.07 * normals.at(i).y, 0.07 * normals.at(i).z);
00639 end.x += start.x;
00640 end.y += start.y;
00641 end.z += start.z;
00642
00643 objectNormalMarker.header.stamp = ros::Time();
00644 objectNormalMarker.id = id + i;
00645
00646 objectNormalMarker.points = std::vector<geometry_msgs::Point>();
00647 objectNormalMarker.points.push_back(start);
00648 objectNormalMarker.points.push_back(end);
00649
00650 objectNormalsMarkerArrayPtr->markers.push_back(objectNormalMarker);
00651 }
00652 return objectNormalsMarkerArrayPtr;
00653 }
00654
00655 std::vector<geometry_msgs::Point> FakeObjectRecognition::getNormals(const ObjectConfig &object) {
00656
00657 std::vector<geometry_msgs::Point> temp_normals = std::vector<geometry_msgs::Point>();
00658
00659
00660
00661 std::vector<std::string> strvec;
00662 std::string in = object.getMeshName();
00663 boost::algorithm::trim_if(in, boost::algorithm::is_any_of("_/"));
00664 boost::algorithm::split(strvec, in, boost::algorithm::is_any_of("_/"));
00665 ROS_DEBUG_STREAM("Recognizer name of object: " << strvec.at(7));
00666 std::string recognizer = strvec.at(7);
00667
00668
00669 asr_object_database::ObjectMetaData objectMetaData;
00670 objectMetaData.request.object_type = object.getType();
00671 objectMetaData.request.recognizer = recognizer;
00672
00673 if (!object_metadata_service_client_.exists()) { ROS_DEBUG_STREAM("/asr_object_database/object_meta_data service is not available"); }
00674 else {
00675 object_metadata_service_client_.call(objectMetaData);
00676 if (!objectMetaData.response.is_valid) { ROS_DEBUG_STREAM("objectMetadata response is not valid for object type " << object.getType()); }
00677 else { temp_normals = objectMetaData.response.normal_vectors; }
00678 }
00679 return temp_normals;
00680 }
00681
00682 bool FakeObjectRecognition::getBBfromFile(std::array<geometry_msgs::Point, 8> &result, std::string object_type) {
00683
00684
00685 ROS_DEBUG_STREAM("Looking for bounding box corner points in " << bb_corners_file_name_);
00686 std::string corners_string;
00687 if (std::ifstream(bb_corners_file_name_)) {
00688 try {
00689 rapidxml::file<> xmlFile(bb_corners_file_name_.c_str());
00690 rapidxml::xml_document<> doc;
00691 doc.parse<0>(xmlFile.data());
00692 rapidxml::xml_node<> *root_node = doc.first_node();
00693 if (root_node) {
00694 rapidxml::xml_node<> *child_node = root_node->first_node();
00695 while (child_node) {
00696 rapidxml::xml_attribute<> *type_attribute = child_node->first_attribute("type");
00697 if (type_attribute) {
00698 if (object_type == type_attribute->value()) {
00699 rapidxml::xml_node<> *bb_corners_node = child_node->first_node();
00700 if (bb_corners_node) {
00701 corners_string = bb_corners_node->value();
00702 }
00703 else {
00704 ROS_DEBUG_STREAM("Could not find values in node with attribute type = \"" << object_type << "\"");
00705 }
00706 break;
00707 }
00708 }
00709 child_node = child_node->next_sibling();
00710 }
00711 }
00712 } catch(std::runtime_error err) {
00713 ROS_DEBUG_STREAM("Can't parse xml-file. Runtime error: " << err.what());
00714 } catch (rapidxml::parse_error err) {
00715 ROS_DEBUG_STREAM("Can't parse xml-file Parse error: " << err.what());
00716 }
00717 }
00718 else {
00719 ROS_DEBUG_STREAM("File " << bb_corners_file_name_ << " does not exist. Will be created when calculating new bounding box corners.");
00720 }
00721 std::array<geometry_msgs::Point, 8> corner_points;
00722 if (corners_string.length() > 0) {
00723
00724 std::stringstream cornerstream;
00725 cornerstream.str(corners_string);
00726 std::string corner_coord;
00727 std::vector<float> coord_list;
00728 try {
00729 while (std::getline(cornerstream, corner_coord, ' ')) {
00730 coord_list.push_back(std::stof(corner_coord));
00731 }
00732 } catch (std::invalid_argument& ia) {
00733 ROS_DEBUG_STREAM(ia.what());
00734 coord_list = std::vector<float>();
00735 }
00736 unsigned int j = 0;
00737 for (unsigned int i = 0; i <= coord_list.size() - 3; i+=3) {
00738 corner_points.at(j) = createPoint(coord_list.at(i), coord_list.at(i+1), coord_list.at(i+2));
00739 j++;
00740 }
00741 }
00742 else {
00743 return false;
00744 }
00745 result = corner_points;
00746 return true;
00747 }
00748
00749 std::array<geometry_msgs::Point, 8> FakeObjectRecognition::calculateBB(const ObjectConfig &object) {
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767 std::string to_cut = "package://" + object_database_name_;
00768 unsigned int length_to_cut = to_cut.length();
00769 std::string mesh_path = ros::package::getPath(object_database_name_) + object.getMeshName().substr(length_to_cut);
00770 ROS_DEBUG_STREAM("Looking for mesh in: " << mesh_path);
00771
00772
00773 std::string vertices;
00774 try {
00775 rapidxml::file<> xmlFile(mesh_path.c_str());
00776 rapidxml::xml_document<> doc;
00777 doc.parse<0>(xmlFile.data());
00778 rapidxml::xml_node<> *collada_node = doc.first_node("COLLADA");
00779 if (!collada_node) ROS_DEBUG_STREAM("Could not find node " << "COLLADA");
00780 else {
00781 rapidxml::xml_node<> *lib_geom_node = collada_node->first_node("library_geometries");
00782 if (!lib_geom_node) ROS_DEBUG_STREAM("Could not find node " << "library_geometries");
00783 else {
00784 rapidxml::xml_node<> *geom_node = lib_geom_node->first_node("geometry");
00785 if (!geom_node) ROS_DEBUG_STREAM("Could not find node " << "geometry");
00786 else {
00787 rapidxml::xml_node<> *mesh_node = geom_node->first_node("mesh");
00788 if (!mesh_node) ROS_DEBUG_STREAM("Could not find node " << "mesh");
00789 else {
00790 rapidxml::xml_node<> *source_node = mesh_node->first_node("source");
00791 while (source_node) {
00792 rapidxml::xml_attribute<> *name_attribute = source_node->first_attribute("name");
00793 std::string name;
00794 if (name_attribute) {
00795 name = name_attribute->value();
00796 if (name == "position") {
00797 rapidxml::xml_node<> *f_array_node = source_node->first_node("float_array");
00798 if (!f_array_node) ROS_DEBUG_STREAM("Could not find node " << "float_array");
00799 else {
00800 rapidxml::xml_node<> *array_node = f_array_node->first_node();
00801 if (!array_node) ROS_DEBUG_STREAM("Could not find node " << "containing the position array");
00802 else {
00803 vertices = array_node->value();
00804 break;
00805 }
00806 }
00807 }
00808 }
00809 source_node = source_node->next_sibling("source");
00810 }
00811 if (!source_node) ROS_DEBUG_STREAM("Could not find node " << "source with name position and position array");
00812 }
00813 }
00814 }
00815 }
00816 } catch(std::runtime_error err) {
00817 ROS_DEBUG_STREAM("Can't parse xml-file. Runtime error: " << err.what());
00818 } catch (rapidxml::parse_error err) {
00819 ROS_DEBUG_STREAM("Can't parse xml-file Parse error: " << err.what());
00820 }
00821
00822
00823 std::stringstream vertstream;
00824 vertstream.str(vertices);
00825 std::vector<float> vertex_list;
00826 std::string vertex_coord;
00827 float sum = 0.0;
00828 try {
00829 while (std::getline(vertstream, vertex_coord, ' ')) {
00830 float value= std::stof(vertex_coord);
00831 sum += std::abs(value);
00832 vertex_list.push_back(value);
00833 }
00834 } catch (std::invalid_argument& ia) {
00835 ROS_DEBUG_STREAM(ia.what());
00836 sum = 0.0;
00837 }
00838
00839
00840 float min_x, min_y, min_z, max_x, max_y, max_z;
00841 min_x = min_y = min_z = max_x = max_y = max_z = 0.0;
00842
00843 ROS_DEBUG_STREAM("Calculating approximated oriented bounding box");
00844 ApproxMVBB::OOBB bb;
00845
00846 if (sum > 0.0) {
00847
00848 ApproxMVBB::Matrix3Dyn points(3,vertex_list.size()/3);
00849 unsigned int j = 0;
00850 for (unsigned int i = 0; i <= vertex_list.size() - 3; i+=3) {
00851 points(0,j) = vertex_list.at(i);
00852 points(1,j) = vertex_list.at(i+1);
00853 points(2,j) = vertex_list.at(i+2);
00854 j++;
00855 }
00856
00857
00858 bb = ApproxMVBB::approximateMVBB(points,0.001,500,5,0,5);
00859
00860 ApproxMVBB::Matrix33 A_KI = bb.m_q_KI.matrix().transpose();
00861 for(unsigned int i = 0; i < points.cols(); ++i) {
00862 bb.unite(A_KI*points.col(i));
00863 }
00864
00865
00866 ApproxMVBB::Vector3 min_point = bb.m_minPoint;
00867 ApproxMVBB::Vector3 max_point = bb.m_maxPoint;
00868 min_x = min_point.x();
00869 min_y = min_point.y();
00870 min_z = min_point.z();
00871 max_x = max_point.x();
00872 max_y = max_point.y();
00873 max_z = max_point.z();
00874 }
00875
00876
00877 std::array<ApproxMVBB::Vector3, 8> corners_amvbb;
00878 corners_amvbb.at(0) = ApproxMVBB::Vector3(min_x, min_y, min_z);
00879 corners_amvbb.at(1) = ApproxMVBB::Vector3(max_x, min_y, min_z);
00880 corners_amvbb.at(2) = ApproxMVBB::Vector3(min_x, max_y, min_z);
00881 corners_amvbb.at(3) = ApproxMVBB::Vector3(max_x, max_y, min_z);
00882 corners_amvbb.at(4) = ApproxMVBB::Vector3(min_x, min_y, max_z);
00883 corners_amvbb.at(5) = ApproxMVBB::Vector3(max_x, min_y, max_z);
00884 corners_amvbb.at(6) = ApproxMVBB::Vector3(min_x, max_y, max_z);
00885 corners_amvbb.at(7) = ApproxMVBB::Vector3(max_x, max_y, max_z);
00886
00887
00888 if (sum > 0.0) {
00889 for (unsigned int i = 0; i < corners_amvbb.size(); i++) {
00890 corners_amvbb.at(i) = (bb.m_q_KI * corners_amvbb.at(i)) * 0.001;
00891 }
00892 }
00893
00894
00895 std::array<geometry_msgs::Point, 8> corner_points;
00896 for (unsigned int i = 0; i < corners_amvbb.size(); i++) {
00897 corner_points.at(i) = createPoint(corners_amvbb.at(i).x(), corners_amvbb.at(i).y(), corners_amvbb.at(i).z());
00898 }
00899
00900
00901 try {
00902 std::string corners_string;
00903 for (unsigned int i = 0; i < corner_points.size(); i++) {
00904 corners_string += boost::lexical_cast<std::string>(corner_points.at(i).x) + " " + boost::lexical_cast<std::string>(corner_points.at(i).y) + " "
00905 + boost::lexical_cast<std::string>(corner_points.at(i).z) + " ";
00906 }
00907 std::string object_node = "<Object type=\"" + object.getType() + "\">" + corners_string + "</Object>";
00908 std::ifstream ifile;
00909 std::ofstream ofile;
00910
00911 if (!(std::ifstream(bb_corners_file_name_))) {
00912 ROS_DEBUG_STREAM("Could not find file " << bb_corners_file_name_ << ". Creating file.");
00913 ofile.open(bb_corners_file_name_);
00914 if (ofile.is_open()) {
00915 ofile << "<Objects></Objects>";
00916 ofile.close();
00917 }
00918 else
00919 ROS_DEBUG_STREAM("Could not open file " << bb_corners_file_name_);
00920 }
00921
00922 ifile.open(bb_corners_file_name_);
00923 if (ifile.is_open()) {
00924 std::string old_contents;
00925 std::string line;
00926 while(getline(ifile, line)) {
00927 old_contents.append(line);
00928 }
00929 ifile.close();
00930 if (old_contents.find("<Objects>") == 0) {
00931 ofile.open(bb_corners_file_name_);
00932 if (ofile.is_open()) {
00933 std::string inner_nodes = old_contents.substr(9);
00934 ofile << "<Objects>" << object_node << inner_nodes;
00935 ofile.close();
00936 ROS_DEBUG_STREAM("Bounding box corner points written to file " << bb_corners_file_name_);
00937 }
00938 }
00939 else ROS_DEBUG_STREAM("When trying to write bounding box corners to file " << bb_corners_file_name_ << ": Could not find root node " << "<Objects>" << ". Corners not written.");
00940 }
00941 else {
00942 ROS_DEBUG_STREAM("Could not open file " << bb_corners_file_name_ << ". Bounding box corners not written.");
00943 }
00944 } catch(boost::bad_lexical_cast err) {
00945 ROS_DEBUG_STREAM("Can't cast bounding box corner points to string. Cast error: " << err.what());
00946 }
00947
00948 return corner_points;
00949 }
00950
00951 geometry_msgs::Point FakeObjectRecognition::createPoint(double x, double y, double z) {
00952 geometry_msgs::Point pt;
00953 pt.x = x;
00954 pt.y = y;
00955 pt.z = z;
00956 return pt;
00957 }
00958
00959 }
00960
00961 int main(int argc, char** argv) {
00962
00963 ros::init (argc, argv, "asr_fake_object_recognition");
00964
00965 fake_object_recognition::FakeObjectRecognition rec;
00966
00967 ros::spin();
00968
00969 return 0;
00970 }
00971