CPCtoOCRegistration.cpp
Go to the documentation of this file.
00001 /******************************************************************************
00002  * \file
00003  *
00004  * $Id:$
00005  *
00006  * Copyright (C) Brno University of Technology
00007  *
00008  * This file is part of software developed by dcgm-robotics@FIT group.
00009  *
00010  * Author: Vit Stancl (stancl@fit.vutbr.cz)
00011  * Supervised by: Michal Spanel (spanel@fit.vutbr.cz)
00012  * Date: 25/1/2012
00013  *
00014  * This file is free software: you can redistribute it and/or modify
00015  * it under the terms of the GNU Lesser General Public License as published by
00016  * the Free Software Foundation, either version 3 of the License, or
00017  * (at your option) any later version.
00018  *
00019  * This file is distributed in the hope that it will be useful,
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022  * GNU Lesser General Public License for more details.
00023  *
00024  * You should have received a copy of the GNU Lesser General Public License
00025  * along with this file.  If not, see <http://www.gnu.org/licenses/>.
00026  */
00027 
00028 #include <srs_env_model/but_server/registration/CPCtoOCRegistration.h>
00029 
00030 
00031 #include <srs_env_model/but_server/registration/pcl_registration_module.h>
00032 #include <srs_env_model/topics_list.h>
00033 #include <pcl_ros/transforms.h>
00034 #include <pcl/io/io.h>
00035 
00036 
00040 srs_env_model::COcPatchMaker::COcPatchMaker()
00041 : m_bTransformCamera( false )
00042 , m_pcFrameId("/map")
00043 , m_bSpinThread( false )
00044 , m_bCamModelInitialized(false)
00045 , m_camera_stereo_offset_left(0)
00046 , m_camera_stereo_offset_right(0)
00047 , m_bPublishCloud(false)
00048 , m_fracX(1.5)
00049 , m_fracY(1.5)
00050 {
00051 
00052 }
00053 
00057 void srs_env_model::COcPatchMaker::init(ros::NodeHandle & node_handle)
00058 {
00059         ROS_DEBUG("Initializing CCompressedPointCloudPlugin");
00060 
00061         if ( m_bSpinThread )
00062         {
00063                 // if we're spinning our own thread, we'll also need our own callback queue
00064                 node_handle.setCallbackQueue( &callback_queue_ );
00065 
00066                 need_to_terminate_ = false;
00067                 spin_thread_.reset( new boost::thread(boost::bind(&COcPatchMaker::spinThread, this)) );
00068                 node_handle_ = node_handle;
00069         }
00070 
00071         // Read parameters
00072         {
00073                 // Where to get camera position information
00074                 node_handle.param("camera_info_topic_name", m_cameraInfoTopic, CPC_CAMERA_INFO_PUBLISHER_NAME );
00075         }
00076 
00077 
00078         // Subscribe to position topic
00079         // Create subscriber
00080         m_camPosSubscriber = node_handle.subscribe<sensor_msgs::CameraInfo>( m_cameraInfoTopic, 10, &srs_env_model::COcPatchMaker::onCameraChangedCB, this );
00081 
00082         if (!m_camPosSubscriber)
00083         {
00084                 ROS_ERROR("Not subscribed...");
00085                 ROS_ERROR( "Cannot subscribe to the camera position publisher..." );
00086         }
00087 
00088         // stereo cam params for sensor cone:
00089 //      node_handle.param<int> ("compressed_pc_camera_stereo_offset_left", m_camera_stereo_offset_left, 0); // 128
00090 //      node_handle.param<int> ("compressed_pc_camera_stereo_offset_right", m_camera_stereo_offset_right, 0);
00091 
00092         node_handle.param("registration_patch_view_fraction_x", m_fracX, m_fracX );
00093         node_handle.param("registration_patch_view_fraction_y", m_fracY, m_fracY );
00094 
00095         node_handle.param("registration_patch_publish_cloud", m_bPublishCloud, m_bPublishCloud );
00096 
00097         if( m_bPublishCloud )
00098                 // Create publisher - simple point cloud
00099                 m_pubConstrainedPC = node_handle.advertise<sensor_msgs::PointCloud2> (REGISTRATION_CONSTRAINED_CLOUD_PUBLISHER_NAME, 5, false);
00100 
00101 }
00102 
00106 bool srs_env_model::COcPatchMaker::computeCloud( const SMapWithParameters & par, const ros::Time & time )
00107 {
00108         ROS_DEBUG( "CCompressedPointCloudPlugin: onFrameStart" );
00109 
00110         // Copy buffered camera normal and d parameter
00111         boost::recursive_mutex::scoped_lock lock( m_camPosMutex );
00112 
00113         // Clear data
00114         m_cloud.clear();
00115         m_ocFrameId = par.frameId;
00116         m_DataTimeStamp = m_time_stamp = time;
00117 
00118         bool bTransformOutput = m_ocFrameId != m_pcFrameId;
00119 
00120         // Output transform matrix
00121         Eigen::Matrix4f pcOutTM;
00122 
00123         // If different frame id
00124         if( bTransformOutput )
00125         {
00126                 tf::StampedTransform ocToPcTf;
00127 
00128                 // Get transform
00129                 try {
00130                         // Transformation - to, from, time, waiting time
00131                         m_tfListener.waitForTransform(m_pcFrameId, m_ocFrameId,
00132                                         m_time_stamp, ros::Duration(5));
00133 
00134                         m_tfListener.lookupTransform(m_pcFrameId, m_ocFrameId,
00135                                         m_time_stamp, ocToPcTf);
00136 
00137                 } catch (tf::TransformException& ex) {
00138                         ROS_ERROR_STREAM("Transform error: " << ex.what() << ", quitting callback");
00139                         ROS_ERROR_STREAM( "Transform error.");
00140                         return false;
00141                 }
00142 
00143 
00144                 // Get transformation matrix
00145                 pcl_ros::transformAsMatrix(ocToPcTf, pcOutTM);  // Sensor TF to defined base TF
00146 
00147         }
00148 
00149         if( m_cameraFrameId.size() == 0 )
00150         {
00151                 ROS_ERROR_STREAM("Wrong camera frame id...");
00152                 m_bTransformCamera = false;
00153                 return false;
00154         }
00155 
00156         m_bTransformCamera = m_cameraFrameId != m_ocFrameId;
00157 
00158 
00159         // Store camera information
00160         m_camera_size = m_camera_size_buffer;
00161         m_camera_model.fromCameraInfo( m_camera_info_buffer);
00162 
00163         // Transform camera model to the cloud time and frame id
00164         {
00165                 tf::StampedTransform camTf;
00166 
00167                 // Modify camera position to the current time
00168                 if( m_bTransformCamera )
00169                 {
00170                         // We need camera to octomap transfor
00171                         try {
00172                                         // Transformation - to, from, time, waiting time
00173                         //      std::cerr << "T1, try to get transform from " << m_cameraFrameId << " to " << m_ocFrameId << ", time: " << par.currentTime << std::endl;
00174                                         m_tfListener.waitForTransform(m_ocFrameId, m_cameraFrameId,
00175                                                         m_time_stamp, ros::Duration(5.0));
00176 
00177                                         m_tfListener.lookupTransform(m_ocFrameId, m_cameraFrameId,
00178                                                         m_time_stamp, camTf);
00179 
00180                                 } catch (tf::TransformException& ex) {
00181                                         ROS_ERROR_STREAM("Transform error1: " << ex.what() << ", quitting callback");
00182                                         return false;
00183                                 }
00184 
00185                 }
00186                 else
00187                 {
00188                         // Just move camera position "in time"
00189                         try {
00190                                         // Time transformation - target frame, target time, source frame, source time, fixed frame, time, waiting time
00191                                         m_tfListener.waitForTransform(m_cameraFrameId, m_time_stamp,
00192                                                                                                   m_cameraFrameId, m_camera_info_buffer.header.stamp,
00193                                                                                                   "/map", ros::Duration(1.0));
00194 
00195                                         m_tfListener.lookupTransform( m_cameraFrameId, m_time_stamp,
00196                                                                                                   m_cameraFrameId, m_camera_info_buffer.header.stamp,
00197                                                                                                   "/map", camTf);
00198 
00199                                 } catch (tf::TransformException& ex) {
00200                                         ROS_ERROR_STREAM("Transform error2: " << ex.what() << ", quitting callback");
00201                                         return false;
00202                                 }
00203                 }
00204 
00205                 // We have transform so convert it to the eigen matrix
00206                 m_to_sensorTf = camTf.inverse();
00207         }
00208 
00209         // Initialize leaf iterators
00210         tButServerOcTree & tree( par.map->getTree() );
00211         srs_env_model::tButServerOcTree::leaf_iterator it, itEnd( tree.end_leafs() );
00212 
00213         // Compute fraction matrix
00214     m_fracMatrix = btMatrix3x3::getIdentity().scaled( tf::Point( 1.0 / m_fracX, 1.0 / m_fracY, 1.0 ) );
00215 
00216         // Crawl through nodes
00217         for ( it = tree.begin_leafs(par.treeDepth); it != itEnd; ++it)
00218         {
00219                 // Node is occupied?
00220                 if (tree.isNodeOccupied(*it))
00221                 {
00222                         handleOccupiedNode(it, par);
00223                 }// Node is occupied?
00224 
00225         } // Iterate through octree
00226 
00227         if( bTransformOutput )
00228         {
00229                 // transform point cloud from octomap frame to the preset frame
00230                 pcl::transformPointCloud< tPclPoint >(m_cloud, m_cloud, pcOutTM);
00231         }
00232 
00233         if( m_bPublishCloud )
00234                 publishInternal( m_DataTimeStamp );
00235 
00236         return true;
00237 }
00238 
00242 void srs_env_model::COcPatchMaker::handleOccupiedNode(srs_env_model::tButServerOcTree::iterator& it, const SMapWithParameters & mp)
00243 {
00244 //      PERROR("OnHandleOccupied");
00245 
00246         if( ! m_bCamModelInitialized )
00247                 return;
00248 
00249         // Test input point
00250         tf::Point pos(it.getX(), it.getY(), it.getZ());
00251 //      if( m_bTransformCamera )
00252         pos = m_to_sensorTf(pos);
00253 
00254         pos = pos * m_fracMatrix;
00255 
00256         if( pos.z() < 0 )
00257                 return;
00258 
00259         cv::Point2d uv = m_camera_model.project3dToPixel(cv::Point3d( pos.x(), pos.y(), pos.z()));
00260 
00261         // ignore point if not in sensor cone
00262         if (!inSensorCone(uv))
00263                 return;
00264 
00265         // Ok, add it...
00266         //      std::cerr << "PCP: handle occupied" << std::endl;
00267         tPclPoint point;
00268 
00269         // Set position
00270         point.x = it.getX();
00271         point.y = it.getY();
00272         point.z = it.getZ();
00273 
00274         // Set color
00275         point.r = it->r();
00276         point.g = it->g();
00277         point.b = it->b();
00278 
00279 //      std::cerr << "Occupied node r " << (int)point.r << ", g " << (int)point.g << ", b " << (int)point.b << std::endl;
00280 
00281         m_cloud.push_back( point );
00282 }
00283 
00287 void srs_env_model::COcPatchMaker::onCameraChangedCB(const sensor_msgs::CameraInfo::ConstPtr &cam_info)
00288 {
00289         boost::recursive_mutex::scoped_lock lock( m_camPosMutex );
00290 
00291         //PERROR("OnCameraChange.");
00292 
00293         //      ROS_DEBUG( "CCompressedPointCloudPlugin: onCameraChangedCB" );
00294 
00295         // Set camera position frame id
00296         m_cameraFrameId = cam_info->header.frame_id;
00297 
00298 
00299         ROS_DEBUG("COcToPcl: Set camera info: %d x %d\n", cam_info->height, cam_info->width);
00300         m_camera_model_buffer.fromCameraInfo(*cam_info);
00301         m_camera_size_buffer = m_camera_model_buffer.fullResolution();
00302 
00303         // Set flag
00304         m_bCamModelInitialized = true;
00305 
00306         m_camera_info_buffer = *cam_info;
00307 }
00308 
00309 
00313 bool srs_env_model::COcPatchMaker::inSensorCone(const cv::Point2d& uv) const
00314 {
00315         const double x_offset( 0.0 ), y_offset( 0.0 );
00316 
00317         //PERROR( uv.y <<       " > " << 1 << " && " << uv.y << " < " << m_camera_size.height - 2 );
00318         // Check if projected 2D coordinate in pixel range.
00319                 // This check is a little more restrictive than it should be by using
00320                 // 1 pixel less to account for rounding / discretization errors.
00321                 // Otherwise points on the corner are accounted to be in the sensor cone.
00322                 bool rv((uv.x > m_camera_stereo_offset_left + 1 - x_offset) &&
00323                                 (uv.x < m_camera_size.width + m_camera_stereo_offset_right - 2 + x_offset) &&
00324                                 (uv.y > 1 - y_offset) &&
00325                                 (uv.y < m_camera_size.height - 2 + y_offset));
00326 
00327                 if( ! rv )
00328                 {
00329 //                      std::cerr << uv.x << ", "  << uv.y << " > " << m_camera_size.width << ", "  << m_camera_size.height << std::endl;
00330                 }
00331 
00332                 return rv;
00333 }
00334 
00338 void srs_env_model::COcPatchMaker::spinThread()
00339 {
00340         while (node_handle_.ok())
00341                 {
00342                         if (need_to_terminate_)
00343                         {
00344                                 break;
00345                         }
00346                         callback_queue_.callAvailable(ros::WallDuration(0.033f));
00347                 }
00348 }
00349 
00353 void srs_env_model::COcPatchMaker::publishInternal(const ros::Time & timestamp)
00354 {
00355         // Convert data
00356         sensor_msgs::PointCloud2 msg;
00357         pcl::toROSMsg< tPclPoint >(m_cloud, msg);
00358 
00359         // Set message parameters and publish
00360         msg.header.frame_id = m_pcFrameId;
00361         msg.header.stamp = m_cloud.header.stamp;
00362 
00363         // Publish data
00364         m_pubConstrainedPC.publish( msg );
00365 }
00366 
00367 //=============================================================================
00368 //      CPcToOcRegistration
00369 //=============================================================================
00370 
00374 srs_env_model::CPcToOcRegistration::CPcToOcRegistration()
00375 : m_resampledCloud( new sensor_msgs::PointCloud2 () )
00376 {
00377 
00378 }
00379 
00383 void srs_env_model::CPcToOcRegistration::init(ros::NodeHandle & node_handle)
00384 {
00385         // Initialize modules
00386         m_patchMaker.init( node_handle );
00387         m_registration.init( node_handle );
00388 }
00389 
00393 bool srs_env_model::CPcToOcRegistration::registerCloud( tPointCloudPtr & cloud, const SMapWithParameters & map )
00394 {
00395         if( !m_registration.isRegistering() )
00396         {
00397                 ROS_ERROR( "No registration method selected." );
00398                 return false;
00399         }
00400 
00401 //      std::cerr << "Reg start" << std::endl;
00402 
00403         // Get patch
00404         m_patchMaker.setCloudFrameId( map.frameId );
00405         m_patchMaker.computeCloud( map, cloud->header.stamp );
00406 
00407         if( m_patchMaker.getCloud().size() == 0 )
00408                 return false;
00409 
00410         // Resample input cloud
00411         sensor_msgs::PointCloud2::Ptr cloudMsg(new sensor_msgs::PointCloud2 ());
00412 
00413         pcl::toROSMsg( *cloud, *cloudMsg);
00414 //      std::cerr << "Patch size: " << m_patchMaker.getCloud().size() << ", " << cloudMsg->data.size() << std::endl;
00415 
00416         m_gridFilter.setInputCloud( cloudMsg );
00417         m_gridFilter.setLeafSize( map.resolution, map.resolution, map.resolution );
00418         m_gridFilter.filter( *m_resampledCloud );
00419 
00420 //      std::cerr << "Voxel grid size: " << m_resampledCloud->data.size() << std::endl;
00421 
00422         // Try to register cloud
00423         tPointCloudPtr cloudSource( new tPointCloud() );
00424         tPointCloudPtr cloudBuffer( new tPointCloud() );
00425         tPointCloudPtr cloudTarget( new tPointCloud() );
00426         pcl::fromROSMsg( *m_resampledCloud, *cloudSource );
00427         pcl::copyPointCloud( m_patchMaker.getCloud(), *cloudTarget );
00428 
00429 //      std::cerr << "Calling registration: " << cloudSource->size() << ", " << cloudTarget->size() << std::endl;
00430 
00431         bool rv( m_registration.process( cloudSource, cloudTarget, cloudBuffer ) );
00432 
00433         if( ! rv )
00434                 std::cerr << "Registration failed" << std::endl;
00435 
00436         return rv;
00437 }


srs_env_model
Author(s): Vit Stancl (stancl@fit.vutbr.cz), Tomas Lokaj, Jan Gorig, Michal Spanel (spanel@fit.vutbr.cz)
autogenerated on Sun Jan 5 2014 11:50:48