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 <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
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
00072 {
00073
00074 node_handle.param("camera_info_topic_name", m_cameraInfoTopic, CPC_CAMERA_INFO_PUBLISHER_NAME );
00075 }
00076
00077
00078
00079
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
00089
00090
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
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
00111 boost::recursive_mutex::scoped_lock lock( m_camPosMutex );
00112
00113
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
00121 Eigen::Matrix4f pcOutTM;
00122
00123
00124 if( bTransformOutput )
00125 {
00126 tf::StampedTransform ocToPcTf;
00127
00128
00129 try {
00130
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
00145 pcl_ros::transformAsMatrix(ocToPcTf, pcOutTM);
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
00160 m_camera_size = m_camera_size_buffer;
00161 m_camera_model.fromCameraInfo( m_camera_info_buffer);
00162
00163
00164 {
00165 tf::StampedTransform camTf;
00166
00167
00168 if( m_bTransformCamera )
00169 {
00170
00171 try {
00172
00173
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
00189 try {
00190
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
00206 m_to_sensorTf = camTf.inverse();
00207 }
00208
00209
00210 tButServerOcTree & tree( par.map->getTree() );
00211 srs_env_model::tButServerOcTree::leaf_iterator it, itEnd( tree.end_leafs() );
00212
00213
00214 m_fracMatrix = btMatrix3x3::getIdentity().scaled( tf::Point( 1.0 / m_fracX, 1.0 / m_fracY, 1.0 ) );
00215
00216
00217 for ( it = tree.begin_leafs(par.treeDepth); it != itEnd; ++it)
00218 {
00219
00220 if (tree.isNodeOccupied(*it))
00221 {
00222 handleOccupiedNode(it, par);
00223 }
00224
00225 }
00226
00227 if( bTransformOutput )
00228 {
00229
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
00245
00246 if( ! m_bCamModelInitialized )
00247 return;
00248
00249
00250 tf::Point pos(it.getX(), it.getY(), it.getZ());
00251
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
00262 if (!inSensorCone(uv))
00263 return;
00264
00265
00266
00267 tPclPoint point;
00268
00269
00270 point.x = it.getX();
00271 point.y = it.getY();
00272 point.z = it.getZ();
00273
00274
00275 point.r = it->r();
00276 point.g = it->g();
00277 point.b = it->b();
00278
00279
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
00292
00293
00294
00295
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
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
00318
00319
00320
00321
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
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
00356 sensor_msgs::PointCloud2 msg;
00357 pcl::toROSMsg< tPclPoint >(m_cloud, msg);
00358
00359
00360 msg.header.frame_id = m_pcFrameId;
00361 msg.header.stamp = m_cloud.header.stamp;
00362
00363
00364 m_pubConstrainedPC.publish( msg );
00365 }
00366
00367
00368
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
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
00402
00403
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
00411 sensor_msgs::PointCloud2::Ptr cloudMsg(new sensor_msgs::PointCloud2 ());
00412
00413 pcl::toROSMsg( *cloud, *cloudMsg);
00414
00415
00416 m_gridFilter.setInputCloud( cloudMsg );
00417 m_gridFilter.setLeafSize( map.resolution, map.resolution, map.resolution );
00418 m_gridFilter.filter( *m_resampledCloud );
00419
00420
00421
00422
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
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 }