00001
00018 #include "rating.h"
00019 #include <Eigen/Dense>
00020 #include <ros/console.h>
00021
00022 #include <pcl/point_cloud.h>
00023 #include <pcl/filters/frustum_culling.h>
00024 #include <pcl/impl/point_types.hpp>
00025
00026 #include <pcl/filters/impl/frustum_culling.hpp>
00027
00028 namespace fake_object_recognition {
00029
00030 Rating::Rating(double fovx, double fovy, double ncp, double fcp) :
00031 fovx_(fovx),
00032 fovy_(fovy),
00033 ncp_(ncp),
00034 fcp_(fcp),
00035 camera_orientation_(Eigen::Vector3d(0.0, 0.0, 1.0)) { }
00036
00037 bool Rating::ratePose(const geometry_msgs::Pose &pose, double threshold_d, double threshold_x, double threshold_y) {
00038
00039 double rating_d = getDistanceRating(pose);
00040 ROS_DEBUG_STREAM("Distance Rating: " << rating_d);
00041 double rating_x = getAngleRating(pose, true);
00042 ROS_DEBUG_STREAM("Angle rating in xz-plane: " << rating_x);
00043 double rating_y = getAngleRating(pose, false);
00044 ROS_DEBUG_STREAM("Angle rating in yz-plane: " << rating_y);
00045
00046 return rating_d > threshold_d && rating_x > threshold_x && rating_y > threshold_y;
00047 }
00048
00049 double Rating::getDistanceRating(const geometry_msgs::Pose &object_pose) {
00050 double rating = 0.0;
00051 Eigen::Vector3d object_position(object_pose.position.x, object_pose.position.y, object_pose.position.z);
00052 double dot_cam_obj = camera_orientation_.dot(object_position);
00053
00054 double dist_to_mid = std::abs(dot_cam_obj - ((fcp_ + ncp_) / 2.0));
00055 double dist_threshold = (fcp_ - ncp_) / 2.0;
00056
00057 if (dist_to_mid < dist_threshold) {
00058 rating = 0.5 + 0.5 * cos((dist_to_mid * M_PI) / dist_threshold);
00059 }
00060
00061 return rating;
00062 }
00063
00064 double Rating::getAngleRating(const geometry_msgs::Pose &object_pose, bool direction) {
00065 double rating = 0.0;
00066
00067 Eigen::Vector3d object_position(object_pose.position.x, object_pose.position.y, object_pose.position.z);
00068
00069 double angle_max;
00070
00071
00072 if(direction){
00073
00074 object_position.y() = 0.0;
00075 angle_max = (fovx_ * M_PI) / 180.0;
00076 }
00077
00078 else {
00079
00080 object_position.x() = 0.0;
00081 angle_max = (fovy_ * M_PI) / 180.0;
00082 }
00083
00084 object_position.normalize();
00085
00086 double angle = std::acos(camera_orientation_.dot(object_position));
00087
00088 if (angle < angle_max) {
00089 rating = 0.5 + 0.5 * std::cos((angle * M_PI) / angle_max);
00090 }
00091
00092 return rating;
00093 }
00094
00095 bool Rating::getBBRating(const std::array<geometry_msgs::Point, 8> &bounding_box) {
00096 pcl::PointCloud<pcl::PointXYZ>::Ptr point_cloud = boost::make_shared<pcl::PointCloud<pcl::PointXYZ>>();
00097 unsigned int bb_size = bounding_box.size();
00098 for (unsigned int i = 0; i < bb_size; i++) {
00099 pcl::PointXYZ pt = pcl::PointXYZ(bounding_box.at(i).x, bounding_box.at(i).y, bounding_box.at(i).z);
00100 point_cloud->push_back(pt);
00101 }
00102
00103 pcl::FrustumCulling<pcl::PointXYZ> fc;
00104 fc.setHorizontalFOV(fovx_);
00105 fc.setVerticalFOV(fovy_);
00106 fc.setNearPlaneDistance(ncp_);
00107 fc.setFarPlaneDistance(fcp_);
00108
00109
00110
00111 Eigen::Matrix4f cam;
00112 cam << 0.0, 0.0, -1.0, 0.0,
00113 0.0, 1.0, 0.0, 0.0,
00114 1.0, 0.0, 0.0, 0.0,
00115 0.0, 0.0, 0.0, 1.0;
00116 fc.setCameraPose(cam);
00117
00118 fc.setInputCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr(point_cloud));
00119
00120 pcl::PointCloud<pcl::PointXYZ>::Ptr culled_cloud = boost::make_shared<pcl::PointCloud<pcl::PointXYZ>>();
00121 fc.filter(*culled_cloud);
00122
00123 return (culled_cloud->size() == bb_size);
00124 }
00125
00126 double Rating::getNormalRating(const geometry_msgs::Pose &object_pose, const std::vector<geometry_msgs::Point> &normals) {
00127
00128
00129 Eigen::Vector3d v1, v2;
00130 double angleThreshold = M_PI * 0.5;
00131 v1 << object_pose.position.x, object_pose.position.y, object_pose.position.z;
00132 v1 = (-1) * v1;
00133 v1.normalize();
00134
00135 float xNorm = v1.lpNorm<2>();
00136 if (xNorm == 0) {
00137 ROS_DEBUG_STREAM("Object appears to be inside camera.");
00138 return 0.0;
00139 }
00140
00141 float best_rated = 0.0;
00142 for (unsigned int i = 0; i < normals.size(); i++) {
00143 v2 << normals.at(i).x, normals.at(i).y, normals.at(i).z;
00144 v2.normalize();
00145 float yNorm = v2.lpNorm<2>();
00146 if (yNorm != 0) {
00147 float cosine = v1.dot(v2) / xNorm / yNorm;
00148 float angle = std::acos(cosine);
00149 if (angle < angleThreshold) {
00150 float rating = 0.5 + 0.5 * std::cos(angle * M_PI / angleThreshold);
00151 if (rating > best_rated) { best_rated = rating; }
00152 }
00153 }
00154 }
00155 ROS_DEBUG_STREAM("getNormalRating: best_rated = " << best_rated);
00156 return best_rated;
00157 }
00158
00159 bool Rating::rateBBandNormal(const geometry_msgs::Pose &object_pose, const std::array<geometry_msgs::Point, 8> &bounding_box, const std::vector<geometry_msgs::Point> &normals, double threshold) {
00160 if (!getBBRating(bounding_box)) {
00161 return false;
00162 }
00163 else if (normals.empty()) {
00164 return true;
00165 }
00166 else {
00167 return (getNormalRating(object_pose, normals) > threshold);
00168 }
00169 }
00170
00171
00172
00173
00174 }