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"
83 int main(
int argc,
char **argv) {
85 Optionpk<string> attribute_opt(
"n",
"name",
"names of the point attribute to select: intensity, return, nreturn, z",
"z");
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");
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)");
115 percentile_opt.setHide(1);
116 nodata_opt.setHide(1);
117 option_opt.setHide(1);
118 colorTable_opt.setHide(1);
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);
145 catch(
string predefinedString){
146 std::cout << predefinedString << std::endl;
152 cout <<
"pklas2img -i lasfile -o output" << endl;
154 std::cout <<
"short option -h shows basic options only, use long option --help to show all options" << std::endl;
160 double dfComplete=0.0;
161 const char* pszMessage;
162 void* pProgressArg=NULL;
163 GDALProgressFunc pfnProgress=GDALTermProgress;
171 GDALDataType theType=GDT_Unknown;
173 cout <<
"possible output data types: ";
174 for(
int iType = 0; iType < GDT_TypeCount; ++iType){
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;
183 if(theType==GDT_Unknown)
184 cout <<
"Unknown output pixel type: " << otype_opt[0] << endl;
186 cout <<
"Output pixel type: " << GDALGetDataTypeName(theType) << endl;
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){
201 lasReader.open(input_opt[iinput]);
203 catch(
string errorString){
204 cerr << errorString << endl;
208 cerr <<
"Error opening input " << input_opt[iinput] << endl;
211 nPoints=lasReader.getPointCount();
212 totalPoints+=nPoints;
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);
220 ulx=ulx-dx_opt[0]/2.0;
221 lrx=ulx+dx_opt[0]/2.0;
224 uly=lry+dy_opt[0]/2.0;
225 lry=lry-dy_opt[0]/2.0;
228 maxLRX=(lrx>maxLRX)?lrx:maxLRX;
229 maxULY=(uly>maxULY)?uly:maxULY;
230 minULX=(ulx<minULX)?ulx:minULX;
231 minLRY=(lry<minLRY)?lry:minLRY;
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;
254 int ncol=ceil(maxLRX-minULX)/dx_opt[0];
255 int nrow=ceil(maxULY-minLRY)/dy_opt[0];
257 int nband=(composite_opt[0]==
"profile")? nbin_opt[0] : 1;
258 if(!output_opt.size()){
259 cerr <<
"Error: no output file defined" << endl;
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]);
274 outputWriter.setGeoTransform(gt);
275 if(projection_opt.size()){
276 string projectionString=outputWriter.setProjectionProj4(projection_opt[0]);
278 cout <<
"projection: " << projectionString << endl;
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]);
286 inputData.resize(nrow,ncol);
288 for(
int irow=0;irow<nrow;++irow)
289 for(
int icol=0;icol<ncol;++icol)
290 outputData[irow][icol]=0;
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){
297 lasReader.open(input_opt[iinput]);
299 catch(
string errorString){
300 cout << errorString << endl;
304 if(lasReader.isCompressed())
305 cout <<
"Reading compressed point cloud " << input_opt[iinput]<< endl;
307 cout <<
"Reading uncompressed point cloud " << input_opt[iinput] << endl;
312 if(returns_opt.size())
313 lasReader.addReturnsFilter(returns_opt);
314 if(classes_opt.size())
315 lasReader.addClassFilter(classes_opt);
316 lasReader.setFilters();
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"){
324 std::cout <<
"writing intensity" << std::endl;
327 else if(*ait==
"return"){
329 std::cout <<
"writing return number" << std::endl;
332 else if(*ait==
"nreturn"){
334 std::cout <<
"writing number of returns" << std::endl;
338 attribute_opt.erase(ait);
341 liblas::Point thePoint(&(lasReader.getHeader()));
342 while(lasReader.readNextPoint(thePoint)){
343 progress=
static_cast<float>(ipoint)/totalPoints;
344 pfnProgress(progress,pszMessage,pProgressArg);
346 cout <<
"reading point " << ipoint << endl;
347 if(thePoint.GetX()<minULX||thePoint.GetX()>=maxLRX||thePoint.GetY()>=maxULY||thePoint.GetY()<minLRY)
349 if((filter_opt[0]==
"single")&&(thePoint.GetNumberOfReturns()!=1))
351 if((filter_opt[0]==
"multiple")&&(thePoint.GetNumberOfReturns()<2))
353 if((filter_opt[0]==
"last")&&(thePoint.GetReturnNumber()!=thePoint.GetNumberOfReturns()))
355 if((filter_opt[0]==
"first")&&(thePoint.GetReturnNumber()!=1))
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){
366 if(icol<0||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());
386 std::string errorString=
"attribute not supported";
392 std::cout <<
"number of points: " << ipoint << std::endl;
396 pfnProgress(progress,pszMessage,pProgressArg);
398 std::cout <<
"processing LiDAR points" << std::endl;
400 pfnProgress(progress,pszMessage,pProgressArg);
408 for(
int irow=0;irow<nrow;++irow){
409 if(composite_opt[0]==
"number")
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])));
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]);
442 stat.minmax(inputData[irow][icol],inputData[irow][icol].begin(),inputData[irow][icol].end(),min,max);
444 std::cout <<
"min,max: " << min <<
"," << max << std::endl;
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];
452 for(
int iband=0;iband<nband;++iband)
453 outputProfile[iband][icol]=max;
457 std::cout <<
"Error: composite_opt " << composite_opt[0] <<
" not supported" << std::endl;
462 if(composite_opt[0]==
"profile"){
463 for(
int iband=0;iband<nband;++iband){
465 assert(outputProfile[iband].size()==outputWriter.nrOfCol());
467 outputWriter.writeData(outputProfile[iband],GDT_Float64,irow,iband);
469 catch(std::string errorString){
470 cout << errorString << endl;
475 progress=
static_cast<float>(irow)/outputWriter.nrOfRow();
476 pfnProgress(progress,pszMessage,pProgressArg);
479 pfnProgress(progress,pszMessage,pProgressArg);
578 if(composite_opt[0]!=
"profile"){
580 std::cout <<
"writing output raster file" << std::endl;
582 pfnProgress(progress,pszMessage,pProgressArg);
583 for(
int irow=0;irow<nrow;++irow){
585 assert(outputData.size()==outputWriter.nrOfRow());
586 assert(outputData[0].size()==outputWriter.nrOfCol());
587 outputWriter.writeData(outputData[irow],GDT_Float64,irow,0);
589 catch(std::string errorString){
590 cout << errorString << endl;
593 progress=
static_cast<float>(irow)/outputWriter.nrOfRow();
594 pfnProgress(progress,pszMessage,pProgressArg);
598 pfnProgress(progress,pszMessage,pProgressArg);
600 std::cout <<
"closing lasReader" << std::endl;
601 outputWriter.close();