00001 00002 #include <sensor_msgs/PointCloud2.h> 00003 #include <sensor_msgs/PointField.h> 00004 #include <pcl/common/io.h> 00005 00006 #include "point_cloud_color/point_iterator.h" 00007 00008 namespace point_cloud_color { 00009 00010 template <bool SAFE> PointCloud2Iterator<SAFE>::PointCloud2Iterator(sensor_msgs::PointCloud2::Ptr pcl, std::vector<std::string> fieldNames): 00011 pcl(pcl), fieldNames(fieldNames) { 00012 fieldOffsets.resize(fieldNames.size(), 0); 00013 fieldDataTypes.resize(fieldNames.size(), 0); 00014 for (size_t i = 0; i < fieldNames.size(); i++) { 00015 int fieldIndex = pcl::getFieldIndex(*pcl, fieldNames[i]); 00016 if (fieldIndex < 0) { 00017 fieldsAvailable[i] = false; 00018 fieldOffsets[i] = 0; 00019 fieldDataTypes[i] = 0; 00020 fieldDataSizes[i] = 0; 00021 } else { 00022 fieldsAvailable[i] = true; 00023 fieldOffsets[i] = pcl->fields[fieldIndex].offset; 00024 fieldDataTypes[i] = pcl->fields[fieldIndex].datatype; 00025 switch (pcl->fields[fieldIndex].datatype) { 00026 case sensor_msgs::PointField::INT8: 00027 case sensor_msgs::PointField::UINT8: 00028 fieldDataSizes[i] = 1; 00029 break; 00030 case sensor_msgs::PointField::INT16: 00031 case sensor_msgs::PointField::UINT16: 00032 fieldDataSizes[i] = 2; 00033 break; 00034 case sensor_msgs::PointField::FLOAT32: 00035 case sensor_msgs::PointField::INT32: 00036 case sensor_msgs::PointField::UINT32: 00037 fieldDataSizes[i] = 4; 00038 break; 00039 case sensor_msgs::PointField::FLOAT64: 00040 fieldDataSizes[i] = 8; 00041 break; 00042 } 00043 } 00044 } 00045 } 00046 00047 //bool PointCloud2Iterator::isFieldAvailable(uint32_t fieldIndex) { 00048 // return fieldsAvailable[fieldIndex]; 00049 //} 00050 //void PointCloud2Iterator::checkFieldAvailable(uint32_t fieldIndex) { 00051 // if (!isFieldAvailable(fieldIndex)) { 00052 // throw std::runtime_error("Field not available."); 00053 // } 00054 //} 00055 template <bool SAFE, class T> T PointCloud2Iterator<SAFE>::getField<T>(uint32_t pointIndex, uint32_t fieldIndex) { 00056 checkFieldAvailable(fieldIndex); 00057 return *reinterpret_cast<T*>(pcl->data.data() + pointIndex * pcl->point_step + fieldOffsets[fieldIndex]); 00058 } 00059 template <bool SAFE, class T> float PointCloud2Iterator<SAFE>::getField<T>(uint32_t pointIndex, uint32_t fieldIndex) { 00060 // checkFieldAvailable(fieldIndex); 00061 return *reinterpret_cast<float*>(pcl->data.data() + pointIndex * pcl->point_step + fieldOffsets[fieldIndex]); 00062 } 00063 template <class T> void PointCloud2Iterator<SAFE>::setField<T>(uint32_t pointIndex, uint32_t fieldIndex, T value) { 00064 // checkFieldAvailable(fieldIndex); 00065 *reinterpret_cast<T*>(pcl->data.data() + pointIndex * pcl->point_step + fieldOffsets[fieldIndex]) = value; 00066 } 00067 template <> void PointCloud2Iterator<SAFE>::setField<T>(uint32_t pointIndex, uint32_t fieldIndex, float value) { 00068 // checkFieldAvailable(fieldIndex); 00069 *reinterpret_cast<float*>(pcl->data.data() + pointIndex * pcl->point_step + fieldOffsets[fieldIndex]) = value; 00070 } 00071 00072 } // namespace point_cloud_color 00073 00074 /* 00075 void PclColor::pointCloud2Callback(const PointCloud2::ConstPtr &pclPtr) { 00076 size_t numPoints = pclPtr->width * pclPtr->height; 00077 NODELET_INFO("PclColor::pointCloud2Callback: Point cloud received (%lu points).", numPoints); 00078 00079 // Transform the points to a fixed frame. 00080 PointCloud2::Ptr pclFixed(new PointCloud2); 00081 if (!transformListener.waitForTransform(fixedFrame, pclPtr->header.frame_id, pclPtr->header.stamp, ros::Duration(3.0)) 00082 || !pcl_ros::transformPointCloud(fixedFrame, *pclPtr, *pclFixed, transformListener)) { 00083 NODELET_WARN("Cannot transform point cloud to the fixed frame %s.", fixedFrame.data()); 00084 return; 00085 } 00086 00087 // Prepare color point cloud. 00088 PointCloud2::Ptr pclColor(new PointCloud2); 00089 pclColor->header = pclPtr->header; 00090 pclColor->width = pclPtr->width; 00091 pclColor->height = pclPtr->height; 00092 pclColor->is_bigendian = pclPtr->is_bigendian; 00093 pclColor->is_dense = pclPtr->is_dense; 00094 PointField rgbaField; 00095 rgbaField.count = 1; 00096 rgbaField.datatype = PointField::UINT32; 00097 rgbaField.name = "rgba"; 00098 rgbaField.offset = 0; 00099 pclColor->fields.push_back(rgbaField); 00100 pclColor->point_step = 4; 00101 pclColor->row_step = pclColor->point_step * pclColor->width; 00102 pclColor->data.resize(pclColor->row_step * pclColor->height); 00103 vector<string> pclColorFieldNames; 00104 pclColorFieldNames.push_back("rgba"); 00105 PointCloud2Iterator pclColorIter(pclColor, pclColorFieldNames); 00106 00107 // Initialize vector with projection distances from image center, used as a quality measure. 00108 vector<double> dist(numPoints, DBL_MAX); 00109 map<string, cv_bridge::CvImageConstPtr>::iterator itImages; 00110 for (itImages = images.begin(); itImages != images.end(); itImages++) { 00111 string cameraFrame = (*itImages).first; 00112 cv_bridge::CvImageConstPtr imagePtr = images[cameraFrame]; 00113 sensor_msgs::CameraInfoConstPtr cameraInfoPtr = cameraInfos[cameraFrame]; 00114 NODELET_DEBUG("Map key %s, image frame %s, camera info frame %s.", cameraFrame.data(), imagePtr->header.frame_id.data(), cameraInfoPtr->header.frame_id.data()); 00115 00116 image_geometry::PinholeCameraModel cameraModel; 00117 if (!cameraModel.fromCameraInfo(cameraInfoPtr)) { 00118 NODELET_WARN("Camera model could not be constructed from camera info. Skipping the image..."); 00119 continue; 00120 } 00121 00122 // Check relative age of the point cloud and the image. Skip the image if the time span is to large. 00123 double imageAge = (pclPtr->header.stamp - imagePtr->header.stamp).toSec(); 00124 if (imageAge > maxImageAge) { 00125 NODELET_WARN("Image %.1f s > %.1f s older than point cloud. Skipping the image...", imageAge, maxImageAge); 00126 continue; 00127 } 00128 NODELET_DEBUG("PclColor::pointCloud2Callback: Using camera %s, image age %.1f s.", cameraFrame.data(), imageAge); 00129 00130 // Transform point cloud into camera frame, skip the image if the transform is not available. 00131 PointCloud2::Ptr pclCam(new PointCloud2); 00132 if (!transformListener.waitForTransform(cameraFrame, fixedFrame, imagePtr->header.stamp, ros::Duration(3.0)) 00133 || !pcl_ros::transformPointCloud(cameraFrame, *pclFixed, *pclCam, transformListener)) { 00134 NODELET_WARN("Cannot transform point cloud to camera frame %s. Skipping the image...", cameraFrame.data()); 00135 continue; 00136 } 00137 00138 vector<string> pclFieldNames; 00139 pclFieldNames.push_back("x"); 00140 pclFieldNames.push_back("y"); 00141 pclFieldNames.push_back("z"); 00142 PointCloud2Iterator pclCamIter(pclCam, pclFieldNames); 00143 pclCamIter.resetIterator(pclCam); 00144 pclColorIter.resetIterator(pclColor); 00145 00146 int iPoint = 0; 00147 while (pclCamIter.next() && pclColorIter.next()) { 00148 // Skip points behind the camera. 00149 if (pclCamIter.getField<float>(2) < 0) { 00150 continue; 00151 } 00152 cv::Point3d p3 = cv::Point3d(pclCamIter.getField<float>(0), pclCamIter.getField<float>(1), pclCamIter.getField<float>(2)); 00153 // Get rectified image coordinates. 00154 cv::Point2d p2 = cameraModel.project3dToPixel(p3); 00155 if (unrectify) { 00156 p2 = cameraModel.unrectifyPoint(p2); 00157 } 00158 double d = hypot(cameraInfoPtr->width / 2.0 - p2.x, cameraInfoPtr->height / 2.0 - p2.y); 00159 if (d >= dist[iPoint]) { 00160 // Keep color from the previous projection which we assume is better. 00161 continue; 00162 } 00163 // TODO: Linear interpolation. 00164 int x = round(p2.x); 00165 int y = round(p2.y); 00166 // Skip points outside the image. 00167 if (x < 0 || y < 0 || x >= cameraInfoPtr->width || y >= cameraInfoPtr->height) { 00168 continue; 00169 } 00170 dist[iPoint] = d; 00171 cv::Vec3b px = imagePtr->image.at<cv::Vec3b>(y, x); 00172 pclColorIter.setField<uint32_t>(0, uint32_t(px.val[2]) << 24 | uint32_t(px.val[1]) << 16 | uint32_t(px.val[0]) << 8 | 0xffu); 00173 iPoint++; 00174 } 00175 } 00176 00177 // Prepare output point cloud. 00178 PointCloud2::Ptr pclOut(new PointCloud2); 00179 pcl::concatenateFields(*pclPtr, *pclColor, *pclOut); 00180 pointCloud2Pub.publish(pclOut); 00181 } 00182 */