21 #include <ros_uri/ros_uri.hpp> 22 #include <Tracking/ICP.h> 24 #include "opencv2/imgproc/imgproc.hpp" 25 #include "opencv2/highgui/highgui.hpp" 30 typedef boost::array< ::geometry_msgs::Point_<std::allocator<void> > , 8>
BoundingBox;
34 ROS_DEBUG(
"Initializing recognition system");
69 std::string left_markers_img_topic;
70 std::string right_markers_img_topic;
71 std::string asr_objects_topic;
72 nh_.
getParam(
"left_markers_img_topic", left_markers_img_topic);
73 nh_.
getParam(
"right_markers_img_topic", right_markers_img_topic);
74 nh_.
getParam(
"asr_objects_topic", asr_objects_topic);
81 std::string vis_markers_topic;
82 nh_.
getParam(
"vis_markers_topic", vis_markers_topic);
94 ROS_DEBUG(
"Process get recognizer request");
101 ROS_DEBUG(
"Process release recognizer request");
107 void ArucoMarkerRecognition::imageCallback(
const sensor_msgs::ImageConstPtr& input_img_left,
const sensor_msgs::ImageConstPtr& input_img_right,
const sensor_msgs::CameraInfoConstPtr& cam_info_left,
const sensor_msgs::CameraInfoConstPtr& cam_info_right) {
116 ROS_ERROR(
"Cv_bridge exception: %s", e.what());
120 cv::GaussianBlur(cv_left->image, img, cv::Size(0, 0),
config_.gaussianBlurSigma);
121 cv::addWeighted(cv_left->image,
config_.sharpenWeightImage, img,
config_.sharpenWeightBlur, 0, cv_left->image);
123 cv::GaussianBlur(cv_right->image, img, cv::Size(0, 0),
config_.gaussianBlurSigma);
124 cv::addWeighted(cv_right->image,
config_.sharpenWeightImage, img,
config_.sharpenWeightBlur, 0, cv_right->image);
128 std::vector<aruco::Marker> left_markers =
detector_.
detect(cv_left->image, MarkerDetection::CameraId::cam_left,
config_);
129 std::vector<aruco::Marker> right_markers;
130 std::map<int, geometry_msgs::Pose> idPoseMap;
134 ivt_bridge::IvtStereoCalibration ivtCalib;
135 ivtCalib.fromCameraInfo(cam_info_left, cam_info_right);
137 idPoseMap =
getMarkerPoses(left_markers, right_markers, ivtCalib);
141 std::string cam_left_frame_id =
"/" + cam_info_left->header.frame_id;
145 for (
auto it = idPoseMap.begin(); it != idPoseMap.end(); ++it) {
154 for (
auto idPosePair : idPoseMap) {
155 std::string object_type =
"marker_" + std::to_string(idPosePair.first);
156 asr_object_database::ObjectMetaData objectMetaData;
157 objectMetaData.request.object_type = object_type;
161 if (objectMetaData.response.is_valid) {
172 cv_left->image =
drawMarkers(cv_left->image, left_markers);
176 cv_right->image =
drawMarkers(cv_right->image, right_markers);
188 cv::Mat output = image;
189 for (
unsigned int i = 0; i < markers.size(); i++) {
190 markers[i].draw(output, cv::Scalar(0, 0, 255), 2);
196 std::map<int, geometry_msgs::Pose> idPoseMap;
198 geometry_msgs::Pose pose;
199 pose.position.x = marker.Tvec.at<
float>(0,0);
200 pose.position.y = marker.Tvec.at<
float>(1,0);
201 pose.position.z = marker.Tvec.at<
float>(2,0);
203 cv::Mat rot_cv(3, 3, CV_32FC1);
204 cv::Rodrigues(marker.Rvec, rot_cv);
206 cv::Mat rotate_to_ros(3, 3, CV_32FC1);
210 rotate_to_ros.at<
float>(0,0) = 0.0;
211 rotate_to_ros.at<
float>(0,1) = 1.0;
212 rotate_to_ros.at<
float>(0,2) = 0.0;
213 rotate_to_ros.at<
float>(1,0) = 0.0;
214 rotate_to_ros.at<
float>(1,1) = 0.0;
215 rotate_to_ros.at<
float>(1,2) = -1.0;
216 rotate_to_ros.at<
float>(2,0) = -1.0;
217 rotate_to_ros.at<
float>(2,1) = 0.0;
218 rotate_to_ros.at<
float>(2,2) = 0.0;
219 rot_cv = rot_cv*rotate_to_ros.t();
221 float q4 = 0.5f * sqrt(1.0
f + rot_cv.at<
float>(0,0) + rot_cv.at<
float>(1,1) + rot_cv.at<
float>(2,2));
222 float t = (1.0f / (4.0f * q4));
223 float q1 = t * (rot_cv.at<
float>(2,1) - rot_cv.at<
float>(1,2));
224 float q2 = t * (rot_cv.at<
float>(0,2) - rot_cv.at<
float>(2,0));
225 float q3 = t * (rot_cv.at<
float>(1,0) - rot_cv.at<
float>(0,1));
227 pose.orientation.x = q1;
228 pose.orientation.y = q2;
229 pose.orientation.z = q3;
230 pose.orientation.w = q4;
232 idPoseMap.insert(std::make_pair(marker.id, pose));
237 std::map<int, geometry_msgs::Pose>
ArucoMarkerRecognition::getMarkerPoses(
const std::vector<aruco::Marker> &left_markers,
const std::vector<aruco::Marker> &right_markers,
const ivt_bridge::IvtStereoCalibration &ivtCalib) {
238 std::map<int, geometry_msgs::Pose> idPoseMap;
241 for (
unsigned int i = 0; i < left_markers.size(); i++) {
242 int left_id = left_markers.at(i).id;
243 for (
unsigned int j = 0; j < right_markers.size(); j++) {
244 if (right_markers.at(j).id == left_id) {
245 CVec3dArray world_marker_corners(4);
246 CVec2dArray image_marker_corners_left(4);
247 CVec3dArray camera_marker_corners_left(4);
249 for (
int k = 0; k < 4; ++k) {
250 Vec2d img_point_left;
251 Vec3d world_point = {0.0f};
252 Vec2d left_point = { left_markers.at(i)[k].x, left_markers.at(i)[k].y };
253 Vec2d right_point = { right_markers.at(j)[k].x, right_markers.at(j)[k].y };
254 stereoCalibPtr->Calculate3DPoint(left_point, right_point, world_point,
false,
false);
255 world_marker_corners.AddElement(world_point);
257 stereoCalibPtr->GetLeftCalibration()->WorldToImageCoordinates(world_point, img_point_left);
258 image_marker_corners_left.AddElement(img_point_left);
261 Vec3d m0 = {0.0, 0.0, 0.0};
262 Vec3d m1 = {
static_cast<float>(
marker_size_ * 1000), 0.0, 0.0};
264 Vec3d m3 = {0.0,
static_cast<float>(
marker_size_ * 1000), 0.0};
265 for (
int k = 0; k < 4; ++k) {
266 stereoCalibPtr->GetLeftCalibration()->WorldToCameraCoordinates(world_marker_corners[k], camera_marker_corners_left[k]);
269 Vec3d sourcePoints[4] = {m0, m1, m2, m3};
270 Vec3d targetPointsLeft[4] = {camera_marker_corners_left[0],camera_marker_corners_left[1],camera_marker_corners_left[2],camera_marker_corners_left[3]};
273 Vec3d translation_left;
274 CICP::CalculateOptimalTransformation(sourcePoints, targetPointsLeft, 4, rotation_left, translation_left);
277 const Vec3d x = {
static_cast<float>(
marker_size_ * 1000) / 2.0
f, 0.0
f, 0.0
f };
279 const Vec3d y = { 0.0f,
static_cast<float>(
marker_size_ * 1000) / 2.0
f, 0.0
f };
282 Math3d::MulMatVec(rotation_left, x, x2);
283 Math3d::MulMatVec(rotation_left, y, y2);
285 Math3d::AddToVec(translation_left, x2);
286 Math3d::AddToVec(translation_left, y2);
294 float theta = 0.5 * M_PI;
295 Math3d::SetRotationMat(B, axis, theta);
298 Math3d::MulMatMat(rotation_left, B, C);
300 geometry_msgs::Pose pose;
301 pose.position.x = translation_left.x / 1000;
302 pose.position.y = translation_left.y / 1000;
303 pose.position.z = translation_left.z / 1000;
305 float q4 = 0.5f * sqrt(1.0
f + C.r1 + C.r5 + C.r9);
306 float t = (1.0f / (4.0f * q4));
307 float q1 = t * (C.r8 - C.r6);
308 float q2 = t * (C.r3 - C.r7);
309 float q3 = t * (C.r4 - C.r2);
311 pose.orientation.x = q1;
312 pose.orientation.y = q2;
313 pose.orientation.z = q3;
314 pose.orientation.w = q4;
316 idPoseMap.insert(std::make_pair(left_id, pose));
326 visualization_msgs::Marker square_marker;
327 square_marker.header.frame_id = frame_id;
328 square_marker.ns =
"Found markers";
329 square_marker.id = id;
330 square_marker.action = visualization_msgs::Marker::ADD;
331 square_marker.pose.position = pose.position;
332 square_marker.pose.orientation = pose.orientation;
333 square_marker.color.a = 1;
334 square_marker.color.r = 1;
335 square_marker.color.g = 0;
336 square_marker.color.b = 0;
338 square_marker.scale.y = 0.001;
340 square_marker.type = visualization_msgs::Marker::CUBE;
343 return square_marker;
347 visualization_msgs::Marker arrow_marker;
348 arrow_marker.header.frame_id = frame_id;
349 arrow_marker.ns = isNsX ?
"Found markers (orientation x)" :
"Found markers (orientation)";
350 arrow_marker.id = id;
351 arrow_marker.action = visualization_msgs::Marker::ADD;
352 arrow_marker.pose.position = pose.position;
353 arrow_marker.pose.orientation = pose.orientation;
354 geometry_msgs::Point p0;
358 geometry_msgs::Point p1;
359 p1.x = isNsX ? 0.05 : 0;
360 p1.y = isNsX ? 0 : -0.05;
362 arrow_marker.points.push_back(p0);
363 arrow_marker.points.push_back(p1);
364 arrow_marker.color.a = 1;
365 arrow_marker.color.r = isNsX ? 1 : 0;
366 arrow_marker.color.g = 0;
367 arrow_marker.color.b = isNsX ? 0 : 1;
368 arrow_marker.scale.x = 0.01;
369 arrow_marker.scale.y = 0.02;
370 arrow_marker.scale.z = 0.02;
371 arrow_marker.type = visualization_msgs::Marker::ARROW;
379 visualization_msgs::Marker marker;
380 marker.header.frame_id = frame_id;
381 marker.ns =
"Found markers (meshes)";
383 marker.action = visualization_msgs::Marker::ADD;
384 marker.pose.position = pose.position;
385 marker.pose.orientation = pose.orientation;
387 marker.scale.x = marker.scale.y = marker.scale.z = 0.001;
388 marker.color.r = marker.color.g = marker.color.b = 130.0f / 255.0f;
389 marker.color.a = 1.0;
391 marker.mesh_resource = mesh_res;
392 marker.mesh_use_embedded_materials =
false;
394 marker.type = visualization_msgs::Marker::MESH_RESOURCE;
401 asr_msgs::AsrObject o;
403 o.header.frame_id = frame_id;
406 geometry_msgs::PoseWithCovariance current_pose_with_c;
407 current_pose_with_c.pose = pose;
408 o.sampledPoses.push_back(current_pose_with_c);
411 BoundingBox bounding_box;
414 minPoint.x = minPoint.y = minPoint.z = 0.0;
419 for (
unsigned int z = 0; z < 2; z++) {
420 for (
unsigned int y = 0; y < 2; y++) {
421 for (
unsigned int x = 0; x < 2; x++) {
422 bounding_box[4*z+2*y+x].x = (1 - x) * minPoint.x + x * maxPoint.x;
423 bounding_box[4*z+2*y+x].y = (1 - y) * minPoint.y + y * maxPoint.y;
424 bounding_box[4*z+2*y+x].z = (1 - z) * minPoint.z + z * maxPoint.z;
429 o.boundingBox = bounding_box;
431 o.color.r = o.color.g = o.color.b = 130.0f / 255.0f;
433 o.type = object_type;
434 o.typeConfidence = 1.0f;
435 o.identifier =
"052052051100";
436 o.meshResourcePath = mesh_res;
444 int main(
int argc,
char** argv) {
445 ros::init(argc, argv,
"asr_aruco_marker_recognition");
446 ROS_INFO(
"Starting up ArucoMarkerRecognition.\n");
448 ROS_DEBUG(
"ArucoMarkerRecognition is started up.\n");
450 unsigned int hertz = 5;
451 ROS_DEBUG_STREAM(
"ArucoMarkerRecognition runs at " << hertz <<
" hertz.\n");
visualization_msgs::Marker createMeshMarker(int id, const geometry_msgs::Pose &pose, const std::string &mesh_res, const string &frame_id)
Create a ros marker from a given pose of a found marker.
ServiceClient serviceClient(const std::string &service_name, bool persistent=false, const M_string &header_values=M_string())
ros::Publisher right_markers_img_pub_
cv::Mat drawMarkers(const cv::Mat &image, const std::vector< aruco::Marker > &markers)
Draws recognized markers and their id into an image.
MarkerDetection detector_
void publish(const boost::shared_ptr< M > &message) const
ArucoMarkerRecognition()
The constructor of this class.
void setCameraParameters(const sensor_msgs::CameraInfo &cam_params_left, const sensor_msgs::CameraInfo &cam_params_right)
Set the camera parameters of the two cameras.
message_filters::Subscriber< sensor_msgs::Image > image_left_sub_
This is the base class of the marker recognition system used for creating the ros environment and con...
visualization_msgs::Marker createArrowMarker(int id, const geometry_msgs::Pose &pose, const string &frame_id, bool isNsX=false)
Create a ros marker from a given pose of a found marker.
bool processGetRecognizerRequest(GetRecognizer::Request &req, GetRecognizer::Response &res)
std::string image_left_topic_
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
message_filters::Subscriber< sensor_msgs::CameraInfo > image_left_param_sub_
bool call(MReq &req, MRes &res)
This class is used to detect markers in an image using the aruco-library.
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
message_filters::Subscriber< sensor_msgs::CameraInfo > image_right_param_sub_
std::string recognizer_name_
static const std::string NODE_NAME("asr_aruco_marker_recognition")
std::string image_right_topic_
int main(int argc, char **argv)
CvImagePtr toCvCopy(const sensor_msgs::ImageConstPtr &source, const std::string &encoding=std::string())
asr_msgs::AsrObject createAsrObject(const geometry_msgs::Pose &pose, const std::string &object_type, const string &frame_id, const std::string &mesh_res="")
Create a asr_object from a given marker pose.
ros::Publisher vis_markers_pub_
ros::Publisher left_markers_img_pub_
message_filters::Subscriber< sensor_msgs::Image > image_right_sub_
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
boost::array< ::geometry_msgs::Point_< std::allocator< void > >, 8 > BoundingBox
This class represents a marker. It is a vector of the fours corners ot the marker.
std::map< int, geometry_msgs::Pose > getMarkerPoses(const std::vector< aruco::Marker > &left_markers)
#define ROS_DEBUG_STREAM(args)
std::string image_right_cam_info_topic_
ros::ServiceServer get_recognizer_service_
boost::shared_ptr< ApproximateSync > sync_policy_
ros::ServiceClient object_mesh_service_client_
std::string image_left_cam_info_topic_
void subscribe(ros::NodeHandle &nh, const std::string &topic, uint32_t queue_size, const ros::TransportHints &transport_hints=ros::TransportHints(), ros::CallbackQueueInterface *callback_queue=0)
void imageCallback(const sensor_msgs::ImageConstPtr &input_img_left, const sensor_msgs::ImageConstPtr &input_img_right, const sensor_msgs::CameraInfoConstPtr &cam_info_left, const sensor_msgs::CameraInfoConstPtr &cam_info_right)
The ros callback which is called when new images are received.
static const std::string GET_RECOGNIZER_SERVICE_NAME("get_recognizer")
bool getParam(const std::string &key, std::string &s) const
ros::Publisher asr_objects_pub_
static const std::string OBJECT_DB_SERVICE_META_DATA("/asr_object_database/object_meta_data")
ros::ServiceServer release_recognizer_service_
dynamic_reconfigure::Server< ArucoMarkerRecognitionConfig > reconfigure_server_
visualization_msgs::Marker createSquareMarker(int id, const geometry_msgs::Pose &pose, const string &frame_id)
Create a ros marker from a given pose of a found marker.
bool processReleaseRecognizerRequest(ReleaseRecognizer::Request &req, ReleaseRecognizer::Response &res)
std::vector< aruco::Marker > detect(const cv::Mat &image, CameraId id, const ArucoMarkerRecognitionConfig &config)
Detects markers in the given image with the camera parameters of the camera with the given id...
void configCallback(ArucoMarkerRecognitionConfig &config_, uint32_t level)
The callback function which is called when the configuration file has changed.
ROSCPP_DECL void spinOnce()
static const std::string RELEASE_RECOGNIZER_SERVICE_NAME("release_recognizer")
ArucoMarkerRecognitionConfig config_
message_filters::Synchronizer< ApproximatePolicy > ApproximateSync
message_filters::sync_policies::ApproximateTime< sensor_msgs::Image, sensor_msgs::Image, sensor_msgs::CameraInfo, sensor_msgs::CameraInfo > ApproximatePolicy
static const double DEFAULT_MARKER_SIZE(0.05)