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"
85 int main(
int argc,
char **argv) {
87 Optionpk<string> attribute_opt(
"n",
"name",
"names of the point attribute to select: intensity, angle, return, nreturn, angle, z",
"z");
93 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)");
94 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");
95 Optionpk<string> filter_opt(
"fir",
"filter",
"filter las points (first,last,single,multiple,all).",
"all");
102 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");
103 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);
104 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);
105 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);
106 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);
107 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");
108 Optionpk<string> oformat_opt(
"of",
"oformat",
"Output image format (see also gdal_translate). Empty string: inherit from input image",
"GTiff");
109 Optionpk<double> dx_opt(
"dx",
"dx",
"Output resolution in x (in meter)", 1.0);
110 Optionpk<double> dy_opt(
"dy",
"dy",
"Output resolution in y (in meter)", 1.0);
111 Optionpk<short> nbin_opt(
"nbin",
"nbin",
"Number of percentile bins for calculating percentile height value profile (=number of output bands)", 10.0);
112 Optionpk<double> percentile_opt(
"perc",
"perc",
"Percentile value used for rule percentile",95);
113 Optionpk<short> nodata_opt(
"nodata",
"nodata",
"nodata value to put in image", 0);
114 Optionpk<string> option_opt(
"co",
"co",
"Creation option for output file. Multiple options can be specified.");
115 Optionpk<string> colorTable_opt(
"ct",
"ct",
"color table (file with 5 columns: id R G B ALFA (0: transparent, 255: solid)");
119 percentile_opt.setHide(1);
120 nodata_opt.setHide(1);
121 option_opt.setHide(1);
122 colorTable_opt.setHide(1);
126 doProcess=input_opt.retrieveOption(argc,argv);
127 attribute_opt.retrieveOption(argc,argv);
128 returns_opt.retrieveOption(argc,argv);
129 classes_opt.retrieveOption(argc,argv);
130 composite_opt.retrieveOption(argc,argv);
131 filter_opt.retrieveOption(argc,argv);
132 angle_min_opt.retrieveOption(argc,argv);
133 angle_max_opt.retrieveOption(argc,argv);
134 output_opt.retrieveOption(argc,argv);
135 projection_opt.retrieveOption(argc,argv);
136 ulx_opt.retrieveOption(argc,argv);
137 uly_opt.retrieveOption(argc,argv);
138 lrx_opt.retrieveOption(argc,argv);
139 lry_opt.retrieveOption(argc,argv);
140 otype_opt.retrieveOption(argc,argv);
141 oformat_opt.retrieveOption(argc,argv);
142 dx_opt.retrieveOption(argc,argv);
143 dy_opt.retrieveOption(argc,argv);
144 nbin_opt.retrieveOption(argc,argv);
145 percentile_opt.retrieveOption(argc,argv);
146 nodata_opt.retrieveOption(argc,argv);
147 option_opt.retrieveOption(argc,argv);
148 colorTable_opt.retrieveOption(argc,argv);
149 verbose_opt.retrieveOption(argc,argv);
151 catch(
string predefinedString){
152 std::cout << predefinedString << std::endl;
158 cout <<
"pklas2img -i lasfile -o output" << endl;
160 std::cout <<
"short option -h shows basic options only, use long option --help to show all options" << std::endl;
166 double dfComplete=0.0;
167 const char* pszMessage;
168 void* pProgressArg=NULL;
169 GDALProgressFunc pfnProgress=GDALTermProgress;
177 GDALDataType theType=GDT_Unknown;
179 cout <<
"possible output data types: ";
180 for(
int iType = 0; iType < GDT_TypeCount; ++iType){
182 cout <<
" " << GDALGetDataTypeName((GDALDataType)iType);
183 if( GDALGetDataTypeName((GDALDataType)iType) != NULL
184 && EQUAL(GDALGetDataTypeName((GDALDataType)iType),
185 otype_opt[0].c_str()))
186 theType=(GDALDataType) iType;
189 if(theType==GDT_Unknown)
190 cout <<
"Unknown output pixel type: " << otype_opt[0] << endl;
192 cout <<
"Output pixel type: " << GDALGetDataTypeName(theType) << endl;
200 unsigned long int totalPoints=0;
201 unsigned long int nPoints=0;
202 unsigned long int ipoint=0;
203 for(
int iinput=0;iinput<input_opt.size();++iinput){
207 lasReader.open(input_opt[iinput]);
209 catch(
string errorString){
210 cerr << errorString << endl;
214 cerr <<
"Error opening input " << input_opt[iinput] << endl;
217 nPoints=lasReader.getPointCount();
218 totalPoints+=nPoints;
220 if(ulx_opt[0]>=lrx_opt[0]||uly_opt[0]<=lry_opt[0]){
221 double ulx,uly,lrx,lry;
222 lasReader.getExtent(ulx,uly,lrx,lry);
226 ulx=ulx-dx_opt[0]/2.0;
227 lrx=ulx+dx_opt[0]/2.0;
230 uly=lry+dy_opt[0]/2.0;
231 lry=lry-dy_opt[0]/2.0;
234 maxLRX=(lrx>maxLRX)?lrx:maxLRX;
235 maxULY=(uly>maxULY)?uly:maxULY;
236 minULX=(ulx<minULX)?ulx:minULX;
237 minLRY=(lry<minLRY)?lry:minLRY;
255 std::cout << setprecision(12) <<
"--ulx=" << minULX <<
" --uly=" << maxULY <<
" --lrx=" << maxLRX <<
" --lry=" << minLRY << std::endl;
256 std::cout <<
"total number of points before filtering: " << totalPoints << std::endl;
257 std::cout <<
"filter set to " << filter_opt[0] << std::endl;
258 if(angle_min_opt.size())
259 std::cout <<
"minimum scan angle: " << angle_min_opt[0] << std::endl;
260 if(angle_max_opt.size())
261 std::cout <<
"maximum scan angle: " << angle_max_opt[0] << std::endl;
264 int ncol=ceil(maxLRX-minULX)/dx_opt[0];
265 int nrow=ceil(maxULY-minLRY)/dy_opt[0];
267 int nband=(composite_opt[0]==
"profile")? nbin_opt[0] : 1;
268 if(!output_opt.size()){
269 cerr <<
"Error: no output file defined" << endl;
273 cout <<
"opening output file " << output_opt[0] << endl;
274 outputWriter.open(output_opt[0],ncol,nrow,nband,theType,oformat_opt[0],option_opt);
275 outputWriter.GDALSetNoDataValue(nodata_opt[0]);
284 outputWriter.setGeoTransform(gt);
285 if(projection_opt.size()){
286 string projectionString=outputWriter.setProjectionProj4(projection_opt[0]);
288 cout <<
"projection: " << projectionString << endl;
290 if(!outputWriter.isGeoRef())
291 cout <<
"Warning: output image " << output_opt[0] <<
" is not georeferenced!" << endl;
292 if(colorTable_opt.size())
293 outputWriter.setColorTable(colorTable_opt[0]);
296 inputData.resize(nrow,ncol);
298 for(
int irow=0;irow<nrow;++irow)
299 for(
int icol=0;icol<ncol;++icol)
300 outputData[irow][icol]=0;
302 cout <<
"Reading " << input_opt.size() <<
" point cloud files" << endl;
303 pfnProgress(progress,pszMessage,pProgressArg);
304 for(
int iinput=0;iinput<input_opt.size();++iinput){
307 lasReader.open(input_opt[iinput]);
309 catch(
string errorString){
310 cout << errorString << endl;
314 if(lasReader.isCompressed())
315 cout <<
"Reading compressed point cloud " << input_opt[iinput]<< endl;
317 cout <<
"Reading uncompressed point cloud " << input_opt[iinput] << endl;
322 if(returns_opt.size())
323 lasReader.addReturnsFilter(returns_opt);
324 if(classes_opt.size())
325 lasReader.addClassFilter(classes_opt);
326 lasReader.setFilters();
328 if(attribute_opt[0]!=
"z"){
329 vector<boost::uint16_t> returnsVector;
330 vector<string>::iterator ait=attribute_opt.begin();
331 while(ait!=attribute_opt.end()){
332 if(*ait==
"intensity"){
334 std::cout <<
"writing intensity" << std::endl;
339 std::cout <<
"writing angle" << std::endl;
342 else if(*ait==
"return"){
344 std::cout <<
"writing return number" << std::endl;
347 else if(*ait==
"nreturn"){
349 std::cout <<
"writing number of returns" << std::endl;
353 attribute_opt.erase(ait);
356 liblas::Point thePoint(&(lasReader.getHeader()));
357 while(lasReader.readNextPoint(thePoint)){
358 progress=
static_cast<float>(ipoint)/totalPoints;
359 pfnProgress(progress,pszMessage,pProgressArg);
361 cout <<
"reading point " << ipoint << endl;
362 if(thePoint.GetX()<minULX||thePoint.GetX()>=maxLRX||thePoint.GetY()>=maxULY||thePoint.GetY()<minLRY)
364 if((filter_opt[0]==
"single")&&(thePoint.GetNumberOfReturns()!=1))
366 if((filter_opt[0]==
"multiple")&&(thePoint.GetNumberOfReturns()<2))
368 if((filter_opt[0]==
"last")&&(thePoint.GetReturnNumber()!=thePoint.GetNumberOfReturns()))
370 if((filter_opt[0]==
"first")&&(thePoint.GetReturnNumber()!=1))
372 if(angle_min_opt.size()){
373 if(angle_min_opt[0]>thePoint.GetScanAngleRank())
376 if(angle_max_opt.size()){
377 if(angle_max_opt[0]<thePoint.GetScanAngleRank())
381 outputWriter.geo2image(thePoint.GetX(),thePoint.GetY(),dcol,drow);
382 int icol=
static_cast<int>(dcol);
383 int irow=
static_cast<int>(drow);
384 if(irow<0||irow>=nrow){
389 if(icol<0||icol>=ncol){
398 if(composite_opt[0]==
"number")
399 outputData[irow][icol]+=1;
400 else if(attribute_opt[0]==
"z")
401 inputData[irow][icol].push_back(thePoint.GetZ());
402 else if(attribute_opt[0]==
"intensity")
403 inputData[irow][icol].push_back(thePoint.GetIntensity());
404 else if(attribute_opt[0]==
"angle")
405 inputData[irow][icol].push_back(thePoint.GetScanAngleRank());
406 else if(attribute_opt[0]==
"return")
407 inputData[irow][icol].push_back(thePoint.GetReturnNumber());
408 else if(attribute_opt[0]==
"nreturn")
409 inputData[irow][icol].push_back(thePoint.GetNumberOfReturns());
411 std::string errorString=
"attribute not supported";
417 std::cout <<
"number of points: " << ipoint << std::endl;
421 pfnProgress(progress,pszMessage,pProgressArg);
423 std::cout <<
"processing LiDAR points" << std::endl;
425 pfnProgress(progress,pszMessage,pProgressArg);
433 for(
int irow=0;irow<nrow;++irow){
434 if(composite_opt[0]==
"number")
437 for(
int icol=0;icol<ncol;++icol){
438 std::vector<double> profile;
439 if(!inputData[irow][icol].size())
440 outputData[irow][icol]=(
static_cast<double>((nodata_opt[0])));
443 if(composite_opt[0]==
"min")
444 outputData[irow][icol]=stat.mymin(inputData[irow][icol]);
445 else if(composite_opt[0]==
"max")
446 outputData[irow][icol]=stat.mymax(inputData[irow][icol]);
447 else if(composite_opt[0]==
"median")
448 outputData[irow][icol]=stat.median(inputData[irow][icol]);
449 else if(composite_opt[0]==
"percentile")
450 outputData[irow][icol]=stat.percentile(inputData[irow][icol],inputData[irow][icol].begin(),inputData[irow][icol].end(),percentile_opt[0]);
451 else if(composite_opt[0]==
"mean")
452 outputData[irow][icol]=stat.mean(inputData[irow][icol]);
453 else if(composite_opt[0]==
"sum")
454 outputData[irow][icol]=stat.sum(inputData[irow][icol]);
455 else if(composite_opt[0]==
"first")
456 outputData[irow][icol]=inputData[irow][icol][0];
457 else if(composite_opt[0]==
"last")
458 outputData[irow][icol]=inputData[irow][icol].back();
459 else if(composite_opt[0]==
"profile"){
460 if(inputData[irow][icol].size()<2){
461 for(
int iband=0;iband<nband;++iband)
462 outputProfile[iband][icol]=static_cast<double>(nodata_opt[0]);
467 stat.minmax(inputData[irow][icol],inputData[irow][icol].begin(),inputData[irow][icol].end(),min,max);
469 std::cout <<
"min,max: " << min <<
"," << max << std::endl;
471 stat.percentiles(inputData[irow][icol],inputData[irow][icol].begin(),inputData[irow][icol].end(),profile,nband,min,max);
472 assert(profile.size()==nband);
473 for(
int iband=0;iband<nband;++iband)
474 outputProfile[iband][icol]=profile[iband];
477 for(
int iband=0;iband<nband;++iband)
478 outputProfile[iband][icol]=max;
482 std::cout <<
"Error: composite_opt " << composite_opt[0] <<
" not supported" << std::endl;
487 if(composite_opt[0]==
"profile"){
488 for(
int iband=0;iband<nband;++iband){
490 assert(outputProfile[iband].size()==outputWriter.nrOfCol());
492 outputWriter.writeData(outputProfile[iband],GDT_Float64,irow,iband);
494 catch(std::string errorString){
495 cout << errorString << endl;
500 progress=
static_cast<float>(irow)/outputWriter.nrOfRow();
501 pfnProgress(progress,pszMessage,pProgressArg);
504 pfnProgress(progress,pszMessage,pProgressArg);
603 if(composite_opt[0]!=
"profile"){
605 std::cout <<
"writing output raster file" << std::endl;
607 pfnProgress(progress,pszMessage,pProgressArg);
608 for(
int irow=0;irow<nrow;++irow){
610 assert(outputData.size()==outputWriter.nrOfRow());
611 assert(outputData[0].size()==outputWriter.nrOfCol());
612 outputWriter.writeData(outputData[irow],GDT_Float64,irow,0);
614 catch(std::string errorString){
615 cout << errorString << endl;
618 progress=
static_cast<float>(irow)/outputWriter.nrOfRow();
619 pfnProgress(progress,pszMessage,pProgressArg);
623 pfnProgress(progress,pszMessage,pProgressArg);
625 std::cout <<
"closing lasReader" << std::endl;
626 outputWriter.close();