pcl_converter.cpp
Go to the documentation of this file.
00001 
00045 #include <ros/ros.h>
00046 // PCL specific includes
00047 #include <ros/package.h>
00048 #include <sensor_msgs/PointCloud2.h>
00049 #include <pcl_conversions/pcl_conversions.h>
00050 #include <pcl/point_cloud.h>
00051 #include <pcl/point_types.h>
00052 #include <math.h>
00053 
00054 using namespace ros;
00055 
00056 #include "pcl_converter/gnuplotPaletteReader.h"
00057 
00058 ros::Publisher pub;
00059 
00060 GnuPlotPalette pal;
00061 bool usingPal = false;
00062 
00063 bool ignoreIntensityMissing = true;
00064 
00065 double minRange = 255.99 * 0.25;
00066 double maxRange = 0.00;
00067 float minRangeGreyVal = 0.0;
00068 float maxRangeGreyVal = 255.99;
00069 
00070 int numEchoOutput = 1;
00071 
00072 class ParamSettings
00073 {
00074 private:
00075   bool dump2csv;
00076 public:
00077   bool isDump2csv() const
00078   {
00079     return dump2csv;
00080   }
00081 
00082   void setDump2csv(bool dump2csv)
00083   {
00084     ParamSettings::dump2csv = dump2csv;
00085   }
00086 
00087 };
00088 
00089 ParamSettings paramSettings;
00090 
00091 
00092 void dump2csv(const sensor_msgs::PointCloud2ConstPtr &cloud, int x_offset, int y_offset, int z_offset)
00093 {
00094   static int cnt = 0;
00095   char szFileName[255] = {0};
00096   sprintf(szFileName,"/tmp/cloud_dump_%04d.csv", cnt);
00097   FILE *fout;
00098   fout = fopen(szFileName,"w");
00099   if (fout != NULL)
00100   {
00101     int i,j;
00102     fprintf(fout,"%-8s;%-8s;%-8s;%-8s;%-8s;%-8s\n","X(col)","Y(Col)","X","Y","Z","Range");
00103     for (i = 0; i < cloud->height; i++)
00104     {
00105       for (j = 0; j < cloud->width; j++)
00106       {
00107         float xRange,yRange,zRange;
00108         float range;
00109         memcpy(&xRange, &(cloud->data[x_offset]), sizeof(float));
00110         memcpy(&yRange, &(cloud->data[y_offset]), sizeof(float));
00111         memcpy(&zRange, &(cloud->data[z_offset]), sizeof(float));
00112         range = sqrt(xRange*xRange + yRange*yRange + zRange*zRange);
00113         fprintf(fout,"%5d;%5d;", i, j);
00114         fprintf(fout,"%8.3f;%8.3f;%8.3f;%8.3f", xRange, yRange, zRange, range);
00115         fprintf(fout,"\n");
00116 
00117         x_offset += cloud->point_step;
00118         y_offset += cloud->point_step;
00119         z_offset += cloud->point_step;
00120       }
00121     }
00122   }
00123   fclose(fout);
00124   cnt++;
00125 }
00126 
00127 
00128 
00129 
00130 
00138 void
00139 cloud2image_cb(const sensor_msgs::PointCloud2ConstPtr &cloud)
00140 {
00141   sensor_msgs::Image msg;
00142   sensor_msgs::Image msgVGA;
00143   int rgb_index = -1;
00144   int x_index = -1;
00145   int y_index = -1;
00146   int z_index = -1;
00147 
00148   int conversionTask = 3;
00149   float range_eps = 0.1;
00150 
00151 
00152   int heightUsed = cloud->height;
00153   if (numEchoOutput == 1)
00154   {
00155     if (heightUsed > 24)
00156     {
00157       heightUsed = 24;
00158     }
00159   }
00160   // Get the index we need
00161   for (size_t d = 0; d < cloud->fields.size(); ++d)
00162   {
00163     if (cloud->fields[d].name == "intensity")
00164     {
00165       rgb_index = static_cast<int>(d); // relative index for each field entry
00166 
00167     }
00168     if (cloud->fields[d].name == "x")
00169     {
00170       x_index = static_cast<int>(d);
00171 
00172     }
00173     if (cloud->fields[d].name == "y")
00174     {
00175       y_index = static_cast<int>(d);
00176 
00177     }
00178     if (cloud->fields[d].name == "z")
00179     {
00180       z_index = static_cast<int>(d);
00181 
00182     }
00183   }
00184   if (rgb_index == -1)
00185   {
00186     if (ignoreIntensityMissing)
00187     {
00188       return;
00189       // intensity flag is missing - ignore the scan
00190     }
00191     else
00192     {
00193       throw std::runtime_error("No intensity entry!!");
00194     }
00195   }
00196 
00197 
00198 
00199   int heightStretch = 5;
00200 
00201   int imgChannelCnt = 0;
00202 
00203   const int maxAllowedEncodings = 2;
00204   bool encodeFlagArray[maxAllowedEncodings] = {0};
00205   bool useHDFormat = false;
00206   if (conversionTask & 1)
00207   {
00208     encodeFlagArray[0] = true;
00209     imgChannelCnt++;
00210   }
00211   if (conversionTask & 2)
00212   {
00213     encodeFlagArray[1] = true;
00214     imgChannelCnt++;
00215   }
00216 
00217   if (cloud->width == 0 && heightUsed == 0)
00218   {
00219     throw std::runtime_error("Needs to be a dense like cloud!!");
00220   }
00221   else
00222   {
00223     msg.height = heightStretch * heightUsed * imgChannelCnt;
00224     msg.width = cloud->width;
00225     if (useHDFormat)
00226     {
00227       if (1080 > msg.height)
00228       {
00229         msg.height = 1080;
00230       }
00231       if (1920 > msg.width)
00232       {
00233         msg.width = 1920;
00234       }
00235     }
00236   }
00237   int rgb_offset = cloud->fields[rgb_index].offset;
00238   int x_offset = cloud->fields[x_index].offset;
00239   int y_offset = cloud->fields[y_index].offset;
00240   int z_offset = cloud->fields[z_index].offset;
00241 
00242 
00243 
00244   int point_step = cloud->point_step;
00245 
00246   /*
00247    * point_step: size of each element
00248    * x_offset etc: relative index
00249    *
00250    */
00251   if (paramSettings.isDump2csv())
00252   {
00253     dump2csv(cloud, x_offset, y_offset, z_offset);
00254   }
00255   // pcl::image_encodings::BGR8;
00256   msg.encoding = "bgr8";
00257   msg.step = static_cast<uint32_t>(msg.width * sizeof(uint8_t) * 3);
00258   msg.data.resize(msg.step * msg.height);
00259 
00260 
00261   int maxY = imgChannelCnt * heightStretch * heightUsed;
00262 
00263   for (size_t y = 0; y < heightUsed; y++)
00264   {
00265     for (size_t x = 0; x < cloud->width; x++)
00266     {
00267       for (int chIdx = 0; chIdx < imgChannelCnt; chIdx++)
00268       {
00269         int encodingCnt = 0;
00270         int encodeIdx = -1; // Kanal, fuer den encodiert werden soll....
00271         for (int j = 0; j < maxAllowedEncodings; j++)
00272         {
00273           if (encodeFlagArray[j])
00274           {
00275             if (chIdx == encodingCnt)
00276             {
00277               encodeIdx = j;
00278               break;
00279             }
00280             encodingCnt++;
00281           }
00282         }
00283 
00284         for (int rowInner = 0; rowInner < heightStretch; rowInner++)
00285         {
00286           int rowTmp = (y * heightStretch + rowInner);
00287           rowTmp += encodingCnt * heightStretch * heightUsed;
00288 
00289           int rowInnerIdx = maxY - (rowTmp) - 1;
00290           int xTmp = x;
00291           xTmp = cloud->width - 1 - x;
00292           uint8_t *pixel = &(msg.data[rowInnerIdx * msg.step + xTmp * 3]);
00293           uint8_t *pixelVGA = NULL;
00294 
00295           float intensity;
00296           float xRange;
00297           float yRange;
00298           float zRange;
00299           float range = 0.0;
00300           memcpy(&xRange, &(cloud->data[x_offset]), sizeof(float));
00301           memcpy(&yRange, &(cloud->data[y_offset]), sizeof(float));
00302           memcpy(&zRange, &(cloud->data[z_offset]), sizeof(float));
00303           range = sqrt(xRange * xRange + yRange * yRange + zRange * zRange);
00304           memcpy(&intensity, &(cloud->data[rgb_offset]), sizeof(float));
00305           if (intensity > 255.0)
00306           {
00307             intensity = 255.0;
00308           }
00309           if (intensity < 0.0)
00310           {
00311             intensity = 0.0;
00312           }
00313           unsigned char r, g, b;
00314           unsigned char grey = 0;
00315           if (encodeIdx == 0)
00316           {
00317             grey = (unsigned char) intensity;
00318           }
00319 
00320           float minRealRange = (minRange < maxRange) ? minRange : maxRange;
00321           float maxRealRange = (minRange < maxRange) ? maxRange : minRange;
00322 
00323           if (encodeIdx == 1)
00324           {
00325             bool setBlack = false;
00326             if (range < range_eps)
00327             {
00328               setBlack = true;
00329             }
00330             if (range < minRealRange)
00331             {
00332               range = minRealRange;
00333 
00334             }
00335             if (range > maxRealRange)
00336             {
00337               range = maxRealRange;
00338             }
00339             // calculate from range to grey value
00340             range = (range - minRange) / (maxRange - minRange) * (maxRangeGreyVal - minRangeGreyVal);
00341             range += minRangeGreyVal;
00342 
00343             grey = (unsigned char) range;
00344             if (setBlack)
00345             {
00346               grey = 0;
00347             }
00348           }
00349 
00350           // grey = 0xFF;
00351           r = grey;
00352           g = grey;
00353           b = grey;
00354 
00355 
00356           if (usingPal)
00357           {
00358             r = pal.getRbgValue(grey, 0);
00359             g = pal.getRbgValue(grey, 1);
00360             b = pal.getRbgValue(grey, 2);
00361           }
00362           pixel[2] = r;
00363           pixel[1] = g;
00364           pixel[0] = b;
00365 
00366           //memcpy(pixel, &(cloud->data[rgb_offset]), 3 * sizeof (uint8_t));
00367         }
00368       }
00369       rgb_offset += point_step;
00370       x_offset += point_step;
00371       y_offset += point_step;
00372       z_offset += point_step;
00373 
00374     }
00375 
00376   }
00377 
00378 // Publish the data.
00379   pub.publish(msg);
00380 }
00381 
00382 void argUsage()
00383 {
00384   printf("sick_pcl_converter <input_pointcloud2-topic> <output_image-topic>");
00385 }
00386 
00387 int
00388 main(int argc, char **argv)
00389 {
00390   bool dumpCsvFlag = false;
00391   // Initialize ROS
00392   if (argc < 3)
00393   {
00394     argUsage();
00395     exit(-1);
00396   }
00397 
00398   // sensor_msgs::PointCloud2 pclTmp;
00399 
00400   std::string inputTopic = argv[1];
00401   std::string outputTopic = argv[2];
00402   ros::init(argc, argv, "sick_pcl_converter");
00403 
00404 
00405   ros::NodeHandle nh("sick_pcl_converter");
00406   std::string heatMap;
00407   nh.getParam("heat_map", heatMap);
00408 
00409   nh.getParam("dump_csv", dumpCsvFlag);
00410 
00411   paramSettings.setDump2csv(dumpCsvFlag);
00412 
00413   if (paramSettings.isDump2csv())
00414   {
00415     ROS_INFO("Dump to csv file for debugging enabled.\n Files will be dumped at /tmp ");
00416   }
00417 
00418   std::string path = ros::package::getPath("sick_scan");
00419 
00420   if (heatMap.length() > 0)
00421   {
00422     std::string heatMapFileName = path + "/config/" + heatMap;
00423     pal.load(heatMapFileName);
00424     usingPal = true;
00425   }
00426   ROS_INFO("Subscribing to %s and publishing images to %s\n", inputTopic.c_str(), outputTopic.c_str());
00427   // Create a ROS subscriber for the input point cloud
00428 //  ros::Subscriber sub = nh.subscribe (inputTopic, 1, cloud_cb);
00429   ros::Subscriber sub = nh.subscribe(inputTopic, 1, cloud2image_cb);
00430 
00431 
00432   // Create a ROS publisher for the output point cloud
00433 //  pub = nh.advertise<sensor_msgs::PointCloud2> (outputTopic, 1);
00434   pub = nh.advertise<sensor_msgs::Image>(outputTopic, 1);
00435 
00436   // Spin
00437   ros::spin();
00438 }


sick_scan
Author(s): Michael Lehning , Jochen Sprickerhof , Martin Günther
autogenerated on Tue Jul 9 2019 05:05:34