main.cpp 13.6 KB
Newer Older
Sven Schneider's avatar
Sven Schneider committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
#include <iostream>
#include <iomanip>
#include <vector>
#include <fstream>  // std::ifstream
#include <string>

#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/console/parse.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/console/time.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/filters/passthrough.h>

// Boost
#include <boost/filesystem.hpp>

// libLAS library
#include <liblas/liblas.hpp>

// OpenCV
//#include <opencv2/core/core.hpp>
//#include <opencv2/viz/vizcore.hpp>


//include own libs and classes here
#include "./src/miscFunctions.hpp"
#include "./src/hull2d.hpp"
#include "./src/CondEuclClustering.hpp"
#include "./h/cloudsubtractor.h"
#include "./src/pcl_las_helper.hpp"
#include "./h/extractfacade.h"
#include "./h/areafromconcavehull.h"
#include "./h/removeconcavehullframe.h"

#define PI atan(1.)*4.0L

typedef pcl::PointXYZI PointT;

using namespace std;


void processFacades(std::vector< pcl::PointCloud<PointT> > facadeVec,                    
                    const std::vector<double> &minXYZValues)
{
    float facadeArea = 0;
    float windowArea = 0;



    std::vector<float> facadeAreaVec, windowAreaVec;

    for (int f=0 ; f < facadeVec.size(); f++)
    {
        pcl::PointCloud<PointT>::Ptr tmpFacade (new pcl::PointCloud<PointT>);
        pcl::PointCloud<PointT>::Ptr invertedCloud (new pcl::PointCloud<PointT>);
        pcl::PointCloud<PointT>::Ptr concaveCloud (new pcl::PointCloud<PointT>);
        pcl::PointCloud<PointT>::Ptr lines (new pcl::PointCloud<PointT>);
        pcl::PointCloud<PointT>::Ptr cloudWithWindows (new pcl::PointCloud<PointT>);

        *tmpFacade = facadeVec.at(f);
        facadeArea = 0;
        windowArea = 0;
        viewer<PointT> (tmpFacade);


        //AreaFromConcaveHull<PointT> AObj;
       // AObj.setInputCloud(tmpFacade);
        //AObj.greedyArea(facadeArea);

        facadeAreaVec.push_back(facadeArea);

        // read CLoudSubtractor values from config file
        std::vector<float> params;
        readParamsFromFile("../cfg/cloudSubtractor.cfg", params, true);


        // create cloudSubtractor object and call the necessary input functions
        CloudSubtractor<PointT> cs(params[0], params[1], params[2]);
        /*
        CloudSubtractor<PointT> cs;
        cs.setPointIncrement(params[0]);  // grid spacing between points for the grid / plane creation
        cs.setKdTreeRadius(params[2]);      // kdtree search radius for point search in original point cloud for point cloud subtraction.
        cs.setKdTreeRadiusPCA(0.05);
        cs.setPlaneDistThreshold(params[1]);*/
        cs.setInputCloud(tmpFacade);
        cs.applyCloudSubtraction(invertedCloud);

        // run again for inverted cloud.
        applyHull(invertedCloud, concaveCloud);
        //viewer<PointT> (concaveCloud);


        RemoveConcaveHullFrame<PointT> rmFrame;
        rmFrame.setInputCloud(concaveCloud);
        rmFrame.setTollerance(0.1);
        rmFrame.apply(concaveCloud);
        viewer<PointT> (concaveCloud);

        // write output to xyz for 3d tiles convertsion
        std::vector< std::vector< double > > pointVec;
        std::vector< unsigned int > intensityVec;
        addMinValues<PointT>(concaveCloud,pointVec,intensityVec, minXYZValues);
        toXYZ("hull", pointVec, intensityVec);

/*
        AreaFromConcaveHull<PointT> AreaObj;
        AreaObj.setInputCloud(tmpFacade);
        AreaObj.greedyArea();

        AreaObj.setInputCloud(concaveCloud);
        AreaObj.setLineDistThreshold(0.2);
        AreaObj.detectLines(lines);

        viewer<PointT> (lines);
*/

         CondEuclClustering(concaveCloud,cloudWithWindows);
         pointVec.clear();
         intensityVec.clear();
         addMinValues<PointT>(cloudWithWindows,pointVec,intensityVec, minXYZValues);
         toXYZ("cloudWithWindows", pointVec, intensityVec);


        int maxLabel = 3; // assuming -2 and 2 for too small and too large clusters, respectively
        int nObj = 0;
        for (int p=0; p<concaveCloud->points.size(); p++)
            if (maxLabel < concaveCloud->points[p].intensity ){
                maxLabel = concaveCloud->points[p].intensity;
                nObj++;
            }


        int label = 4; //assuming first true label == 4, see CondEuclClustering
        pcl::PointCloud<PointT>::Ptr tmpWindow (new pcl::PointCloud<PointT>);
        pcl::PointCloud<PointT>::Ptr boxCloud (new pcl::PointCloud<PointT>);   //store the four corners of the bounding box in here
        tmpFacade.reset();

        for (int obj=0; obj < nObj; obj++, label+=2 ) { //assuming min label == 4 and a label difference of 2

            // Create the filtering object
             pcl::PassThrough<PointT> pass;
             pass.setInputCloud (concaveCloud);
             pass.setFilterFieldName ("intensity");
             pass.setFilterLimits (label, label);  // get only one window with that specific label
             //pass.setFilterLimitsNegative (true);
             pass.filter (*tmpWindow);  // this variable stores the potential window points

            tmpWindow->width = tmpWindow->points.size();
            tmpWindow->height = 1;

            std::vector<Eigen::Vector3f> bBox;
            float aspectRatio, tmpA;
            findBoundingBox(tmpWindow, bBox);  // apply fit bounding box in openCV

            //windowArea += calcAreaFromBbox(bBox,aspectRatio);
            tmpA = calcAreaFromBbox(bBox,aspectRatio);
            if (aspectRatio > 0.33){
                windowArea += tmpA;
                std::cout << "accumulated window area: " << std::setprecision(4) << windowArea << " sqm" << std::endl;
            }
            else
                continue;


            //for (int ptNr=0; ptNr < bBox.size(); ptNr++){  // for all 4 corners store one point in the the boxCloud variable
            for (int ptNr=0; ptNr < 4; ptNr++){
                PointT pt;
                Eigen::Vector3f tmp(bBox.at(ptNr) );
                pt.x = tmp(0);
                pt.y = tmp(1);
                pt.z = tmp(2);
                pt.intensity = label;
                boxCloud->points.push_back( pt );  // store point
                //tmpFacadel->points.push_back( pt );
            }

            boxCloud->width = boxCloud->points.size();
            boxCloud->height = 1;

        }
        windowAreaVec.push_back(windowArea);

      /* std::cout<< "Total window Area / Facade area = " << windowArea << " / " <<
                    facadeArea << " = " << windowArea / facadeArea <<
                    " = window-to-wall ratio." <<
                    "But the facadeArea was calculated without windows." << std::endl;
        std::cout << "corrected ratio is: windowArea / (windowArea+FacadeArea)= " <<
                     windowArea / (windowArea+facadeArea) << std::endl;
                     */

       // viewer<PointT>(boxCloud);
        //viewer<PointT>(tmpWindow);

        //std::vector< std::vector< double > > pointVec;
        //std::vector< unsigned int > intensityVec;
        pointVec.clear();
        intensityVec.clear();
        addMinValues<PointT>(boxCloud,pointVec,intensityVec, minXYZValues);
        toXYZ("STEP_05_bBox", pointVec, intensityVec);


        pointVec.clear();
        intensityVec.clear();
        addMinValuesToBBOX<PointT>(boxCloud,pointVec,intensityVec, minXYZValues);
        toXYZ("STEP_05_bBoxForVIS", pointVec, intensityVec);


        std::stringstream ss;
        pcl::PCDWriter writer;
        ss << "STEP_05_bBox.pcd";
        writer.write<PointT> (ss.str (), *boxCloud, false); //*




    }
}

int  main (int argc, char** argv){


   if (argc == 1){
        PCL_ERROR ("No file has been specified... aborting.");
        return -1;
    }

   //check if pcd or las file was given
   std::string extension = boost::filesystem::extension(argv[1]);
   bool isPCD = false;
   if ( (extension.compare(1,3,".pcd",1,3) == 0 ) ||  ( (extension.compare(1,3,".PCD",1,3)) == 0 ) )
      isPCD = true;
   else if ( ( (extension.compare(1,3,".las",1,3)) == 0 ) ||  ( (extension.compare(1,3,".LAS",1,3)) == 0 ) )
       isPCD = false;
   else{
       PCL_ERROR ("Wrong file extension. Aborting.\n .pcd or .las is required");
       return -1;
   }


 //  pcl::PointCloud<PointT>::Ptr cloudIn = boost::make_shared<pcl::PointCloud<PointT> >();
  pcl::PointCloud<PointT>::Ptr cloudIn (new pcl::PointCloud<PointT>);
  pcl::PointCloud<PointT>::Ptr cloudFiltered (new pcl::PointCloud<PointT>);
  pcl::PointCloud<PointT>::Ptr invertedCloud (new pcl::PointCloud<PointT>);



// Checking parameters and input arguments
  if (argc < 2){
      pcl::console::print_error ("Syntax is: %%s <LAS-INPUT>  \t are mandatory.\nOtional are: \n "
                                         "-setZero: setMinXYZ to zero  no value required. If flag is set it is applied. \n "
                                         "-downsample: float [0.02,1] \n", argv[0]);
      return -1;
   }

    // check optional parameters for subtracting the min Values of the coordinates from all x,y,z coordinates respectively
    // this is done to work around problems caused by the loss of precision using float data types. -> poor PCD point clouds.
    bool subtractMinVals = true;
    subtractMinVals = pcl::console::parse (argc, argv, "-setZero", subtractMinVals);

    // check if the user wants to downsample the point cloud using the voxelgrid function. Specfiy standard values for the leafSize.
    float gridLeafSize = 0.25;
    bool LeafSize_specified = pcl::console::find_switch (argc, argv, "-downsample");
    if (LeafSize_specified){
        pcl::console::parse (argc, argv, "-downsample", gridLeafSize);
        if (gridLeafSize > 1){
            pcl::console::print_highlight("Warning: LeafSize is out of bounds [0, 1]. Setting it to default to proceed (0.25).\n");
            gridLeafSize = 0.25;
        }
    }


    ///// end checking parameters.


    // store minvalues to restore the original coordinates later after processing is completed
    std::vector<double> minXYZValues;

    if (isPCD){  // if pcd no values will be subtracted because pcd cannot store this precision anyway
        // load pcd file
        if(pcl::io::loadPCDFile<PointT> (argv[1], *cloudIn) == -1) // load the file
         {
           PCL_ERROR ("Couldn't read file ");
           return -1;
         }

        if (gridLeafSize > 0.029 && gridLeafSize < 1 && LeafSize_specified){
          std::cout << "\nApplying Uniform downsampling with leafSize " << gridLeafSize << ". Processing...";

          pcl::UniformSampling<PointT> uniform_sampling;
          uniform_sampling.setInputCloud (cloudIn);
          uniform_sampling.setRadiusSearch (gridLeafSize); //the 3D grid leaf size
          uniform_sampling.filter(*cloudFiltered);
          pcl::copyPointCloud(*cloudFiltered, *cloudIn);  // cloud is given by reference so the downsampled cloud has to be copied in there

          /*
          std::string fileToWrite = string(argv[1]) + "_downsampled.pcd";
          std::cout << "Writing PCD output file: " << fileToWrite << std::endl;
          pcl::io::savePCDFile (fileToWrite, *cloudFiltered,true);
          std::cerr << "Saved " << cloudFiltered->points.size () << " Points to " << fileToWrite << std::endl;*/

        }


    }
    else{


        // reading in LAS file and returning a PCD cloud XYZI data.
        readLAS2PCD<PointT>(argv[1], cloudIn, minXYZValues, gridLeafSize, subtractMinVals);
    }

    viewer<PointT> (cloudIn);

    //extract planes from point cloud
    std::vector< pcl::PointCloud<PointT> > facadeVec;  //construct a vector containing the all vertical planes, i.e. hopfully all facades

    getFacades<PointT>(cloudIn, facadeVec, 0.4).applyFilter(facadeVec);  //template class  / function to obtain all vertical planes / facades

    processFacades(facadeVec, minXYZValues);


    if (invertedCloud->points.size() > 0){
      pcl::PCDWriter writer;
      writer.write<PointT> ("inverted_subtracted_Cloud.pcd", *invertedCloud, true);
    }


  // tt.tic();
   //std::cout << "starting to compute something...." << std::endl;

   //applyHull(invertedCloud, concaveHull, convexHull);
   //applyHull(invertedCloud, concaveHull);

  // viewer<PointT> (concaveHull);
 //  std::cout << "Number of points after processing " << concaveHull->points.size () << " .\nAll in all it took " << tt.toc() / 1000. << " seconds." << std::endl;
 //  viewer<PointT> (convexHull);

 //  tt.tic();
  // std::cout << " starting conditional Euclidean clustering..." << std::endl;
 //  CondEuclClustering(invertedCloud,cloudFiltered);
  // std::cout << "Conditional Euclidean  clustering applied to " << invertedCloud->points.size () << " points took: " << tt.toc() / 1000. << " seconds." << std::endl;


/*

    //////////////////////////////////////////////////////////////
    // Visualization of keypoints along with the original cloud
     pcl::visualization::PCLVisualizer viewer("PCL Viewer");
     pcl::visualization::PointCloudColorHandlerCustom<PointT> keypoints_color_handler (concaveHull, 0, 255, 0);
     pcl::visualization::PointCloudColorHandlerCustom<PointT> cloud_color_handler (cloudIn, 255, 0, 0);
     pcl::visualization::PointCloudColorHandlerCustom<PointT> outputfinal_color_handler (convexHull, 0, 0, 255);
     viewer.setBackgroundColor( 0.0, 0.0, 0.0 );
     viewer.addPointCloud(cloudIn, cloud_color_handler, "cloud");

     viewer.addPointCloud(concaveHull, keypoints_color_handler, "keypoints");
     viewer.addPointCloud(convexHull, outputfinal_color_handler, "outputfinal");
     viewer.setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 4, "keypoints");
     viewer.setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "outputfinal");

     while(!viewer.wasStopped ())
     {
     viewer.spinOnce ();
     }
*/
    return (0);
}