pktools  2.6.4
Processing Kernel for geospatial data
pklas2img.cc
1 /**********************************************************************
2 pklas2img.cc: Rasterize LAS/LAZ point clouds with filtering/compositing options
3 Copyright (C) 2008-2014 Pieter Kempeneers
4 
5 This file is part of pktools
6 
7 pktools is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 pktools is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with pktools. If not, see <http://www.gnu.org/licenses/>.
19 ***********************************************************************/
20 #include <iostream>
21 #include "base/Optionpk.h"
22 #include "imageclasses/ImgReaderGdal.h"
23 #include "imageclasses/ImgWriterGdal.h"
24 #include "imageclasses/ImgReaderOgr.h"
25 #include "lasclasses/FileReaderLas.h"
26 #include "algorithms/StatFactory.h"
27 #include "algorithms/Filter2d.h"
28 
29 /******************************************************************************/
81 using namespace std;
82 
83 int main(int argc,char **argv) {
84  Optionpk<string> input_opt("i", "input", "Input las file");
85  Optionpk<string> attribute_opt("n", "name", "names of the point attribute to select: intensity, return, nreturn, z", "z");
86  // Optionpk<bool> disc_opt("circ", "circular", "circular disc kernel for dilation and erosion", false);
87  // Optionpk<double> maxSlope_opt("s", "maxSlope", "Maximum slope used for morphological filtering", 0.0);
88  // Optionpk<double> hThreshold_opt("ht", "maxHeight", "initial and maximum height threshold for progressive morphological filtering (e.g., -ht 0.2 -ht 2.5)", 0.2);
89  // Optionpk<short> maxIter_opt("maxit", "maxit", "Maximum number of iterations in post filter", 5);
90  Optionpk<unsigned short> returns_opt("ret", "ret", "number(s) of returns to include");
91  Optionpk<unsigned short> classes_opt("class", "class", "classes to keep: 0 (created, never classified), 1 (unclassified), 2 (ground), 3 (low vegetation), 4 (medium vegetation), 5 (high vegetation), 6 (building), 7 (low point, noise), 8 (model key-point), 9 (water), 10 (reserved), 11 (reserved), 12 (overlap)");
92  Optionpk<string> composite_opt("comp", "comp", "composite for multiple points in cell (min, max, median, mean, sum, first, last, profile (percentile height values), percentile, number (point density)). Last: overwrite cells with latest point", "last");
93  Optionpk<string> filter_opt("fir", "filter", "filter las points (first,last,single,multiple,all).", "all");
94  // Optionpk<string> postFilter_opt("pf", "pfilter", "post processing filter (etew_min,promorph (progressive morphological filter),bunting (adapted promorph),open,close,none).", "none");
95  // Optionpk<short> dimx_opt("dimx", "dimx", "Dimension X of postFilter", 3);
96  // Optionpk<short> dimy_opt("dimy", "dimy", "Dimension Y of postFilter", 3);
97  Optionpk<string> output_opt("o", "output", "Output image file");
98  Optionpk<string> projection_opt("a_srs", "a_srs", "assign the projection for the output file in epsg code, e.g., epsg:3035 for European LAEA projection");
99  Optionpk<double> ulx_opt("ulx", "ulx", "Upper left x value bounding box (in geocoordinates if georef is true). 0 is read from input file", 0.0);
100  Optionpk<double> uly_opt("uly", "uly", "Upper left y value bounding box (in geocoordinates if georef is true). 0 is read from input file", 0.0);
101  Optionpk<double> lrx_opt("lrx", "lrx", "Lower right x value bounding box (in geocoordinates if georef is true). 0 is read from input file", 0.0);
102  Optionpk<double> lry_opt("lry", "lry", "Lower right y value bounding box (in geocoordinates if georef is true). 0 is read from input file", 0.0);
103  Optionpk<string> otype_opt("ot", "otype", "Data type for output image ({Byte/Int16/UInt16/UInt32/Int32/Float32/Float64/CInt16/CInt32/CFloat32/CFloat64}). Empty string: inherit type from input image", "Byte");
104  Optionpk<string> oformat_opt("of", "oformat", "Output image format (see also gdal_translate). Empty string: inherit from input image", "GTiff");
105  Optionpk<double> dx_opt("dx", "dx", "Output resolution in x (in meter)", 1.0);
106  Optionpk<double> dy_opt("dy", "dy", "Output resolution in y (in meter)", 1.0);
107  Optionpk<short> nbin_opt("nbin", "nbin", "Number of percentile bins for calculating percentile height value profile (=number of output bands)", 10.0);
108  Optionpk<double> percentile_opt("perc","perc","Percentile value used for rule percentile",95);
109  Optionpk<short> nodata_opt("nodata", "nodata", "nodata value to put in image", 0);
110  Optionpk<string> option_opt("co", "co", "Creation option for output file. Multiple options can be specified.");
111  Optionpk<string> colorTable_opt("ct", "ct", "color table (file with 5 columns: id R G B ALFA (0: transparent, 255: solid)");
112  Optionpk<short> verbose_opt("v", "verbose", "verbose mode", 0,2);
113 
114  nbin_opt.setHide(1);
115  percentile_opt.setHide(1);
116  nodata_opt.setHide(1);
117  option_opt.setHide(1);
118  colorTable_opt.setHide(1);
119 
120  bool doProcess;//stop process when program was invoked with help option (-h --help)
121  try{
122  doProcess=input_opt.retrieveOption(argc,argv);
123  attribute_opt.retrieveOption(argc,argv);
124  returns_opt.retrieveOption(argc,argv);
125  classes_opt.retrieveOption(argc,argv);
126  composite_opt.retrieveOption(argc,argv);
127  filter_opt.retrieveOption(argc,argv);
128  output_opt.retrieveOption(argc,argv);
129  projection_opt.retrieveOption(argc,argv);
130  ulx_opt.retrieveOption(argc,argv);
131  uly_opt.retrieveOption(argc,argv);
132  lrx_opt.retrieveOption(argc,argv);
133  lry_opt.retrieveOption(argc,argv);
134  otype_opt.retrieveOption(argc,argv);
135  oformat_opt.retrieveOption(argc,argv);
136  dx_opt.retrieveOption(argc,argv);
137  dy_opt.retrieveOption(argc,argv);
138  nbin_opt.retrieveOption(argc,argv);
139  percentile_opt.retrieveOption(argc,argv);
140  nodata_opt.retrieveOption(argc,argv);
141  option_opt.retrieveOption(argc,argv);
142  colorTable_opt.retrieveOption(argc,argv);
143  verbose_opt.retrieveOption(argc,argv);
144  }
145  catch(string predefinedString){
146  std::cout << predefinedString << std::endl;
147  exit(0);
148  }
149 
150  if(!doProcess){
151  cout << endl;
152  cout << "pklas2img -i lasfile -o output" << endl;
153  cout << endl;
154  std::cout << "short option -h shows basic options only, use long option --help to show all options" << std::endl;
155  exit(0);//help was invoked, stop processing
156  }
157  //todo: is this needed?
158  GDALAllRegister();
159 
160  double dfComplete=0.0;
161  const char* pszMessage;
162  void* pProgressArg=NULL;
163  GDALProgressFunc pfnProgress=GDALTermProgress;
164  double progress=0;
165 
166  Vector2d<vector<double> > inputData;//row,col,point
167 
168 
169  ImgReaderGdal maskReader;
170  ImgWriterGdal outputWriter;
171  GDALDataType theType=GDT_Unknown;
172  if(verbose_opt[0])
173  cout << "possible output data types: ";
174  for(int iType = 0; iType < GDT_TypeCount; ++iType){
175  if(verbose_opt[0])
176  cout << " " << GDALGetDataTypeName((GDALDataType)iType);
177  if( GDALGetDataTypeName((GDALDataType)iType) != NULL
178  && EQUAL(GDALGetDataTypeName((GDALDataType)iType),
179  otype_opt[0].c_str()))
180  theType=(GDALDataType) iType;
181  }
182  if(verbose_opt[0]){
183  if(theType==GDT_Unknown)
184  cout << "Unknown output pixel type: " << otype_opt[0] << endl;
185  else
186  cout << "Output pixel type: " << GDALGetDataTypeName(theType) << endl;
187  }
188 
189  double maxLRX=0;
190  double maxULY=0;
191  double minULX=0;
192  double minLRY=0;
193 
194  unsigned long int totalPoints=0;
195  unsigned long int nPoints=0;
196  unsigned long int ipoint=0;
197  for(int iinput=0;iinput<input_opt.size();++iinput){
198  // assert(input_opt[iinput].find(".las")!=string::npos);
199  FileReaderLas lasReader;
200  try{
201  lasReader.open(input_opt[iinput]);
202  }
203  catch(string errorString){
204  cerr << errorString << endl;
205  exit(1);
206  }
207  catch(...){
208  cerr << "Error opening input " << input_opt[iinput] << endl;
209  exit(2);
210  }
211  nPoints=lasReader.getPointCount();
212  totalPoints+=nPoints;
213 
214  if(ulx_opt[0]>=lrx_opt[0]||uly_opt[0]<=lry_opt[0]){
215  double ulx,uly,lrx,lry;
216  lasReader.getExtent(ulx,uly,lrx,lry);
217  lrx+=dx_opt[0];//pixel coordinates are referenced to upper left corner (las coordinates are centres)
218  lry-=dy_opt[0];//pixel coordinates are referenced to upper left corner (las coordinates are centres)
219  if(ulx>=lrx){
220  ulx=ulx-dx_opt[0]/2.0;
221  lrx=ulx+dx_opt[0]/2.0;
222  }
223  if(uly<=lry){
224  uly=lry+dy_opt[0]/2.0;
225  lry=lry-dy_opt[0]/2.0;
226  }
227  if(maxLRX>minULX){
228  maxLRX=(lrx>maxLRX)?lrx:maxLRX;
229  maxULY=(uly>maxULY)?uly:maxULY;
230  minULX=(ulx<minULX)?ulx:minULX;
231  minLRY=(lry<minLRY)?lry:minLRY;
232  }
233  else{//initialize
234  maxLRX=lrx;
235  maxULY=uly;
236  minULX=ulx;
237  minLRY=lry;
238  }
239  }
240  else{
241  maxLRX=lrx_opt[0];
242  maxULY=uly_opt[0];
243  minULX=ulx_opt[0];
244  minLRY=lry_opt[0];
245  }
246  lasReader.close();
247  }
248  if(verbose_opt[0]){
249  std::cout << setprecision(12) << "--ulx=" << minULX << " --uly=" << maxULY << " --lrx=" << maxLRX << " --lry=" << minLRY << std::endl;
250  std::cout << "total number of points before filtering: " << totalPoints << std::endl;
251  std::cout << "filter set to " << filter_opt[0] << std::endl;
252  // std::cout << "postFilter set to " << postFilter_opt[0] << std::endl;
253  }
254  int ncol=ceil(maxLRX-minULX)/dx_opt[0];//number of columns in outputGrid
255  int nrow=ceil(maxULY-minLRY)/dy_opt[0];//number of rows in outputGrid
256  //todo: multiple bands
257  int nband=(composite_opt[0]=="profile")? nbin_opt[0] : 1;
258  if(!output_opt.size()){
259  cerr << "Error: no output file defined" << endl;
260  exit(1);
261  }
262  if(verbose_opt[0])
263  cout << "opening output file " << output_opt[0] << endl;
264  outputWriter.open(output_opt[0],ncol,nrow,nband,theType,oformat_opt[0],option_opt);
265  outputWriter.GDALSetNoDataValue(nodata_opt[0]);
266  //set projection
267  double gt[6];
268  gt[0]=minULX;
269  gt[1]=dx_opt[0];
270  gt[2]=0;
271  gt[3]=maxULY;
272  gt[4]=0;
273  gt[5]=-dy_opt[0];
274  outputWriter.setGeoTransform(gt);
275  if(projection_opt.size()){
276  string projectionString=outputWriter.setProjectionProj4(projection_opt[0]);
277  if(verbose_opt[0])
278  cout << "projection: " << projectionString << endl;
279  }
280  if(!outputWriter.isGeoRef())
281  cout << "Warning: output image " << output_opt[0] << " is not georeferenced!" << endl;
282  if(colorTable_opt.size())
283  outputWriter.setColorTable(colorTable_opt[0]);
284 
285  inputData.clear();
286  inputData.resize(nrow,ncol);
287  Vector2d<double> outputData(nrow,ncol);
288  for(int irow=0;irow<nrow;++irow)
289  for(int icol=0;icol<ncol;++icol)
290  outputData[irow][icol]=0;
291 
292  cout << "Reading " << input_opt.size() << " point cloud files" << endl;
293  pfnProgress(progress,pszMessage,pProgressArg);
294  for(int iinput=0;iinput<input_opt.size();++iinput){
295  FileReaderLas lasReader;
296  try{
297  lasReader.open(input_opt[iinput]);
298  }
299  catch(string errorString){
300  cout << errorString << endl;
301  exit(1);
302  }
303  if(verbose_opt[0]){
304  if(lasReader.isCompressed())
305  cout << "Reading compressed point cloud " << input_opt[iinput]<< endl;
306  else
307  cout << "Reading uncompressed point cloud " << input_opt[iinput] << endl;
308  }
309  //set bounding filter
310  // lasReader.addBoundsFilter(minULX,maxULY,maxLRX,minLRY);
311  //set returns filter
312  if(returns_opt.size())
313  lasReader.addReturnsFilter(returns_opt);
314  if(classes_opt.size())
315  lasReader.addClassFilter(classes_opt);
316  lasReader.setFilters();
317 
318  if(attribute_opt[0]!="z"){
319  vector<boost::uint16_t> returnsVector;
320  vector<string>::iterator ait=attribute_opt.begin();
321  while(ait!=attribute_opt.end()){
322  if(*ait=="intensity"){
323  if(verbose_opt[0])
324  std::cout << "writing intensity" << std::endl;
325  ++ait;
326  }
327  else if(*ait=="return"){
328  if(verbose_opt[0])
329  std::cout << "writing return number" << std::endl;
330  ++ait;
331  }
332  else if(*ait=="nreturn"){
333  if(verbose_opt[0])
334  std::cout << "writing number of returns" << std::endl;
335  ++ait;
336  }
337  else
338  attribute_opt.erase(ait);
339  }
340  }
341  liblas::Point thePoint(&(lasReader.getHeader()));
342  while(lasReader.readNextPoint(thePoint)){
343  progress=static_cast<float>(ipoint)/totalPoints;
344  pfnProgress(progress,pszMessage,pProgressArg);
345  if(verbose_opt[0]>1)
346  cout << "reading point " << ipoint << endl;
347  if(thePoint.GetX()<minULX||thePoint.GetX()>=maxLRX||thePoint.GetY()>=maxULY||thePoint.GetY()<minLRY)
348  continue;
349  if((filter_opt[0]=="single")&&(thePoint.GetNumberOfReturns()!=1))
350  continue;
351  if((filter_opt[0]=="multiple")&&(thePoint.GetNumberOfReturns()<2))
352  continue;
353  if((filter_opt[0]=="last")&&(thePoint.GetReturnNumber()!=thePoint.GetNumberOfReturns()))
354  continue;
355  if((filter_opt[0]=="first")&&(thePoint.GetReturnNumber()!=1))
356  continue;
357  double dcol,drow;
358  outputWriter.geo2image(thePoint.GetX(),thePoint.GetY(),dcol,drow);
359  int icol=static_cast<int>(dcol);
360  int irow=static_cast<int>(drow);
361  if(irow<0||irow>=nrow){
362  // //test
363  // cout << "Error: thePoint.GetX(),thePoint.GetY(),dcol,drow" << thePoint.GetX() << ", " << thePoint.GetY() << ", " << dcol << ", " << drow << endl;
364  continue;
365  }
366  if(icol<0||icol>=ncol){
367  // //test
368  // cout << "Error: thePoint.GetX(),thePoint.GetY(),dcol,drow" << thePoint.GetX() << ", " << thePoint.GetY() << ", " << dcol << ", " << drow << endl;
369  continue;
370  }
371  assert(irow>=0);
372  assert(irow<nrow);
373  assert(icol>=0);
374  assert(icol<ncol);
375  if(composite_opt[0]=="number")
376  outputData[irow][icol]+=1;
377  else if(attribute_opt[0]=="z")
378  inputData[irow][icol].push_back(thePoint.GetZ());
379  else if(attribute_opt[0]=="intensity")
380  inputData[irow][icol].push_back(thePoint.GetIntensity());
381  else if(attribute_opt[0]=="return")
382  inputData[irow][icol].push_back(thePoint.GetReturnNumber());
383  else if(attribute_opt[0]=="nreturn")
384  inputData[irow][icol].push_back(thePoint.GetNumberOfReturns());
385  else{
386  std::string errorString="attribute not supported";
387  throw(errorString);
388  }
389  ++ipoint;
390  }
391  if(verbose_opt[0])
392  std::cout << "number of points: " << ipoint << std::endl;
393  lasReader.close();
394  }
395  progress=1;
396  pfnProgress(progress,pszMessage,pProgressArg);
397 
398  std::cout << "processing LiDAR points" << std::endl;
399  progress=0;
400  pfnProgress(progress,pszMessage,pProgressArg);
402  //fill inputData in outputData
403  // if(composite_opt[0]=="profile"){
404  // assert(postFilter_opt[0]=="none");
405  // for(int iband=0;iband<nband;++iband)
406  // outputProfile[iband].resize(nrow,ncol);
407  // }
408  for(int irow=0;irow<nrow;++irow){
409  if(composite_opt[0]=="number")
410  continue;//outputData already set
411  Vector2d<double> outputProfile(nband,ncol);
412  for(int icol=0;icol<ncol;++icol){
413  std::vector<double> profile;
414  if(!inputData[irow][icol].size())
415  outputData[irow][icol]=(static_cast<double>((nodata_opt[0])));
416  else{
418  if(composite_opt[0]=="min")
419  outputData[irow][icol]=stat.mymin(inputData[irow][icol]);
420  else if(composite_opt[0]=="max")
421  outputData[irow][icol]=stat.mymax(inputData[irow][icol]);
422  else if(composite_opt[0]=="median")
423  outputData[irow][icol]=stat.median(inputData[irow][icol]);
424  else if(composite_opt[0]=="percentile")
425  outputData[irow][icol]=stat.percentile(inputData[irow][icol],inputData[irow][icol].begin(),inputData[irow][icol].end(),percentile_opt[0]);
426  else if(composite_opt[0]=="mean")
427  outputData[irow][icol]=stat.mean(inputData[irow][icol]);
428  else if(composite_opt[0]=="sum")
429  outputData[irow][icol]=stat.sum(inputData[irow][icol]);
430  else if(composite_opt[0]=="first")
431  outputData[irow][icol]=inputData[irow][icol][0];
432  else if(composite_opt[0]=="last")
433  outputData[irow][icol]=inputData[irow][icol].back();
434  else if(composite_opt[0]=="profile"){
435  if(inputData[irow][icol].size()<2){
436  for(int iband=0;iband<nband;++iband)
437  outputProfile[iband][icol]=static_cast<double>(nodata_opt[0]);
438  continue;
439  }
440  double min=0;
441  double max=0;
442  stat.minmax(inputData[irow][icol],inputData[irow][icol].begin(),inputData[irow][icol].end(),min,max);
443  if(verbose_opt[0])
444  std::cout << "min,max: " << min << "," << max << std::endl;
445  if(max>min){
446  stat.percentiles(inputData[irow][icol],inputData[irow][icol].begin(),inputData[irow][icol].end(),profile,nband,min,max);
447  assert(profile.size()==nband);
448  for(int iband=0;iband<nband;++iband)
449  outputProfile[iband][icol]=profile[iband];
450  }
451  else{
452  for(int iband=0;iband<nband;++iband)
453  outputProfile[iband][icol]=max;
454  }
455  }
456  else{
457  std::cout << "Error: composite_opt " << composite_opt[0] << " not supported" << std::endl;
458  exit(2);
459  }
460  }
461  }
462  if(composite_opt[0]=="profile"){
463  for(int iband=0;iband<nband;++iband){
464  // assert(outputProfile[iband].size()==outputWriter.nrOfRow());
465  assert(outputProfile[iband].size()==outputWriter.nrOfCol());
466  try{
467  outputWriter.writeData(outputProfile[iband],GDT_Float64,irow,iband);
468  }
469  catch(std::string errorString){
470  cout << errorString << endl;
471  exit(1);
472  }
473  }
474  }
475  progress=static_cast<float>(irow)/outputWriter.nrOfRow();
476  pfnProgress(progress,pszMessage,pProgressArg);
477  }
478  progress=1;
479  pfnProgress(progress,pszMessage,pProgressArg);
480  inputData.clear();//clean up memory
481  //apply post filter
482  // std::cout << "Applying post processing filter: " << postFilter_opt[0] << std::endl;
483  // if(postFilter_opt[0]=="etew_min"){
484  // if(composite_opt[0]!="min")
485  // std::cout << "Warning: composite option is not set to min!" << std::endl;
486  // //Elevation Threshold with Expand Window (ETEW) Filter (p.73 frmo Airborne LIDAR Data Processing and Analysis Tools ALDPAT 1.0)
487  // //first iteration is performed assuming only minima are selected using options -fir all -comp min
488  // unsigned long int nchange=1;
489  // //increase cells and thresholds until no points from the previous iteration are discarded.
490  // int dimx=dimx_opt[0];
491  // int dimy=dimy_opt[0];
492  // filter2d::Filter2d morphFilter;
493  // // morphFilter.setNoValue(0);
494  // Vector2d<float> currentOutput=outputData;
495  // int iteration=1;
496  // while(nchange&&iteration<=maxIter_opt[0]){
497  // double hThreshold=maxSlope_opt[0]*dimx;
498  // Vector2d<float> newOutput;
499  // nchange=morphFilter.morphology(currentOutput,newOutput,"erode",dimx,dimy,disc_opt[0],hThreshold);
500  // currentOutput=newOutput;
501  // dimx+=2;//change from theory: originally double cellCize
502  // dimy+=2;//change from theory: originally double cellCize
503  // std::cout << "iteration " << iteration << ": " << nchange << " pixels changed" << std::endl;
504  // ++iteration;
505  // }
506  // outputData=currentOutput;
507  // }
508  // else if(postFilter_opt[0]=="promorph"||postFilter_opt[0]=="bunting"){
509  // if(composite_opt[0]!="min")
510  // std::cout << "Warning: composite option is not set to min!" << std::endl;
511  // assert(hThreshold_opt.size()>1);
512  // //Progressive morphological filter tgrs2003_zhang vol41 pp 872-882
513  // //first iteration is performed assuming only minima are selected using options -fir all -comp min
514  // //increase cells and thresholds until no points from the previous iteration are discarded.
515  // int dimx=dimx_opt[0];
516  // int dimy=dimy_opt[0];
517  // filter2d::Filter2d theFilter;
518  // // theFilter.setNoValue(0);
519  // Vector2d<float> currentOutput=outputData;
520  // double hThreshold=hThreshold_opt[0];
521  // int iteration=1;
522  // while(iteration<=maxIter_opt[0]){
523  // std::cout << "iteration " << iteration << " with window size " << dimx << " and dh_max: " << hThreshold << std::endl;
524  // Vector2d<float> newOutput;
525  // try{
526  // theFilter.morphology(outputData,currentOutput,"erode",dimx,dimy,disc_opt[0],hThreshold);
527  // theFilter.morphology(currentOutput,outputData,"dilate",dimx,dimy,disc_opt[0],hThreshold);
528  // if(postFilter_opt[0]=="bunting"){
529  // theFilter.doit(outputData,currentOutput,"median",dimx,dimy,1,disc_opt[0]);
530  // outputData=currentOutput;
531  // }
532  // }
533  // catch(std::string errorString){
534  // cout << errorString << endl;
535  // exit(1);
536  // }
537  // int newdimx=(dimx==1)? 3: 2*(dimx-1)+1;
538  // int newdimy=(dimx==1)? 3: 2*(dimy-1)+1;//from PE&RS vol 71 pp313-324
539  // hThreshold=hThreshold_opt[0]+maxSlope_opt[0]*(newdimx-dimx)*dx_opt[0];
540  // dimx=newdimx;
541  // dimy=newdimy;
542  // if(hThreshold>hThreshold_opt[1])
543  // hThreshold=hThreshold_opt[1];
544  // ++iteration;
545  // }
546  // outputData=currentOutput;
547  // }
548  // else if(postFilter_opt[0]=="open"){
549  // if(composite_opt[0]!="min")
550  // std::cout << "Warning: composite option is not set to min!" << std::endl;
551  // filter2d::Filter2d morphFilter;
552  // // morphFilter.setNoValue(0);
553  // Vector2d<float> filterInput=outputData;
554  // try{
555  // morphFilter.morphology(outputData,filterInput,"erode",dimx_opt[0],dimy_opt[0],disc_opt[0],maxSlope_opt[0]);
556  // morphFilter.morphology(filterInput,outputData,"dilate",dimx_opt[0],dimy_opt[0],disc_opt[0],maxSlope_opt[0]);
557  // }
558  // catch(std::string errorString){
559  // cout << errorString << endl;
560  // exit(1);
561  // }
562  // }
563  // else if(postFilter_opt[0]=="close"){
564  // if(composite_opt[0]!="max")
565  // std::cout << "Warning: composite option is not set to max!" << std::endl;
566  // filter2d::Filter2d morphFilter;
567  // // morphFilter.setNoValue(0);
568  // Vector2d<float> filterInput=outputData;
569  // try{
570  // morphFilter.morphology(outputData,filterInput,"dilate",dimx_opt[0],dimy_opt[0],disc_opt[0],maxSlope_opt[0]);
571  // morphFilter.morphology(filterInput,outputData,"erode",dimx_opt[0],dimy_opt[0],disc_opt[0],maxSlope_opt[0]);
572  // }
573  // catch(std::string errorString){
574  // cout << errorString << endl;
575  // exit(1);
576  // }
577  // }
578  if(composite_opt[0]!="profile"){
579  //write output file
580  std::cout << "writing output raster file" << std::endl;
581  progress=0;
582  pfnProgress(progress,pszMessage,pProgressArg);
583  for(int irow=0;irow<nrow;++irow){
584  try{
585  assert(outputData.size()==outputWriter.nrOfRow());
586  assert(outputData[0].size()==outputWriter.nrOfCol());
587  outputWriter.writeData(outputData[irow],GDT_Float64,irow,0);
588  }
589  catch(std::string errorString){
590  cout << errorString << endl;
591  exit(1);
592  }
593  progress=static_cast<float>(irow)/outputWriter.nrOfRow();
594  pfnProgress(progress,pszMessage,pProgressArg);
595  }
596  }
597  progress=1;
598  pfnProgress(progress,pszMessage,pProgressArg);
599  if(verbose_opt[0])
600  std::cout << "closing lasReader" << std::endl;
601  outputWriter.close();
602 }