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, spacing, 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, absmin, absmax, 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");
96 Optionpk<short> angle_min_opt(
"angle_min",
"angle_min",
"Minimum scan angle to read points.");
97 Optionpk<short> angle_max_opt(
"angle_max",
"angle_max",
"Maximum scan angle to read points.");
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).",
"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",
"percentile",
"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;
188 if(attribute_opt[0]==
"spacing"){
189 if(theType!=GDT_Float32||theType!=GDT_Float64)
193 if(theType==GDT_Unknown)
194 cout <<
"Unknown output pixel type: " << otype_opt[0] << endl;
196 cout <<
"Output pixel type: " << GDALGetDataTypeName(theType) << endl;
204 unsigned long int totalPoints=0;
205 unsigned long int nPoints=0;
206 unsigned long int ipoint=0;
207 for(
int iinput=0;iinput<input_opt.size();++iinput){
211 lasReader.open(input_opt[iinput]);
213 catch(
string errorString){
214 cerr << errorString << endl;
218 cerr <<
"Error opening input " << input_opt[iinput] << endl;
221 nPoints=lasReader.getPointCount();
222 totalPoints+=nPoints;
224 if(ulx_opt[0]>=lrx_opt[0]||uly_opt[0]<=lry_opt[0]){
225 double ulx,uly,lrx,lry;
226 lasReader.getExtent(ulx,uly,lrx,lry);
230 ulx=ulx-dx_opt[0]/2.0;
231 lrx=ulx+dx_opt[0]/2.0;
234 uly=lry+dy_opt[0]/2.0;
235 lry=lry-dy_opt[0]/2.0;
238 maxLRX=(lrx>maxLRX)?lrx:maxLRX;
239 maxULY=(uly>maxULY)?uly:maxULY;
240 minULX=(ulx<minULX)?ulx:minULX;
241 minLRY=(lry<minLRY)?lry:minLRY;
259 std::cout << setprecision(12) <<
"--ulx=" << minULX <<
" --uly=" << maxULY <<
" --lrx=" << maxLRX <<
" --lry=" << minLRY << std::endl;
260 std::cout <<
"total number of points before filtering: " << totalPoints << std::endl;
261 std::cout <<
"filter set to " << filter_opt[0] << std::endl;
262 if(angle_min_opt.size())
263 std::cout <<
"minimum scan angle: " << angle_min_opt[0] << std::endl;
264 if(angle_max_opt.size())
265 std::cout <<
"maximum scan angle: " << angle_max_opt[0] << std::endl;
268 int ncol=ceil(maxLRX-minULX)/dx_opt[0];
269 int nrow=ceil(maxULY-minLRY)/dy_opt[0];
271 int nband=(composite_opt[0]==
"profile")? nbin_opt[0] : 1;
272 if(!output_opt.size()){
273 cerr <<
"Error: no output file defined" << endl;
277 cout <<
"opening output file " << output_opt[0] << endl;
278 outputWriter.
open(output_opt[0],ncol,nrow,nband,theType,oformat_opt[0],option_opt);
289 if(projection_opt.size()){
293 cout <<
"Warning: output image " << output_opt[0] <<
" is not georeferenced!" << endl;
294 if(colorTable_opt.size())
298 inputData.resize(nrow,ncol);
300 for(
int irow=0;irow<nrow;++irow)
301 for(
int icol=0;icol<ncol;++icol)
302 outputData[irow][icol]=0;
304 cout <<
"Reading " << input_opt.size() <<
" point cloud files" << endl;
305 pfnProgress(progress,pszMessage,pProgressArg);
306 for(
int iinput=0;iinput<input_opt.size();++iinput){
309 lasReader.open(input_opt[iinput]);
311 catch(
string errorString){
312 cout << errorString << endl;
316 if(lasReader.isCompressed())
317 cout <<
"Reading compressed point cloud " << input_opt[iinput]<< endl;
319 cout <<
"Reading uncompressed point cloud " << input_opt[iinput] << endl;
324 if(returns_opt.size())
325 lasReader.addReturnsFilter(returns_opt);
326 if(classes_opt.size())
327 lasReader.addClassFilter(classes_opt);
328 lasReader.setFilters();
330 if(attribute_opt[0]!=
"z"){
331 vector<boost::uint16_t> returnsVector;
332 vector<string>::iterator ait=attribute_opt.begin();
333 while(ait!=attribute_opt.end()){
334 if(*ait==
"intensity"){
336 std::cout <<
"writing intensity" << std::endl;
339 else if(*ait==
"angle"){
341 std::cout <<
"writing angle" << std::endl;
344 else if(*ait==
"return"){
346 std::cout <<
"writing return number" << std::endl;
349 else if(*ait==
"nreturn"){
351 std::cout <<
"writing number of returns" << std::endl;
354 else if(*ait==
"spacing"){
356 std::cout <<
"writing spacing" << std::endl;
360 attribute_opt.erase(ait);
369 if(attribute_opt[0]==
"spacing"){
370 ogrPoint.assignSpatialReference(&projectionRef);
371 ogrCenter.assignSpatialReference(&projectionRef);
373 while(lasReader.getReader()->ReadNextPoint()){
374 liblas::Point
const& thePoint = lasReader.getReader()->GetPoint();
376 progress=
static_cast<float>(ipoint)/totalPoints;
377 pfnProgress(progress,pszMessage,pProgressArg);
378 double theX=thePoint.GetX();
379 double theY=thePoint.GetY();
381 cout <<
"reading point " << ipoint << endl;
382 if(theX<minULX||theX>=maxLRX||theY>=maxULY||theY<minLRY)
384 if((filter_opt[0]==
"single")&&(thePoint.GetNumberOfReturns()!=1))
386 if((filter_opt[0]==
"multiple")&&(thePoint.GetNumberOfReturns()<2))
388 if((filter_opt[0]==
"last")&&(thePoint.GetReturnNumber()!=thePoint.GetNumberOfReturns()))
390 if((filter_opt[0]==
"first")&&(thePoint.GetReturnNumber()!=1))
392 if(angle_min_opt.size()){
393 if(angle_min_opt[0]>thePoint.GetScanAngleRank())
396 if(angle_max_opt.size()){
397 if(angle_max_opt[0]<thePoint.GetScanAngleRank())
401 outputWriter.
geo2image(theX,theY,dcol,drow);
402 int icol=
static_cast<int>(dcol);
403 int irow=
static_cast<int>(drow);
404 if(irow<0||irow>=nrow){
409 if(icol<0||icol>=ncol){
418 if(composite_opt[0]==
"number")
419 outputData[irow][icol]+=1;
420 else if(attribute_opt[0]==
"z")
421 inputData[irow][icol].push_back(thePoint.GetZ());
422 else if(attribute_opt[0]==
"intensity")
423 inputData[irow][icol].push_back(thePoint.GetIntensity());
424 else if(attribute_opt[0]==
"angle")
425 inputData[irow][icol].push_back(thePoint.GetScanAngleRank());
426 else if(attribute_opt[0]==
"return")
427 inputData[irow][icol].push_back(thePoint.GetReturnNumber());
428 else if(attribute_opt[0]==
"nreturn")
429 inputData[irow][icol].push_back(thePoint.GetNumberOfReturns());
430 else if(attribute_opt[0]==
"spacing"){
435 outputWriter.
image2geo(icol,irow,centerX,centerY);
436 ogrCenter.setX(centerX);
437 ogrCenter.setY(centerY);
438 inputData[irow][icol].push_back(ogrPoint.Distance(&ogrCenter));
441 std::string errorString=
"attribute not supported";
447 std::cout <<
"number of points: " << ipoint << std::endl;
451 pfnProgress(progress,pszMessage,pProgressArg);
453 std::cout <<
"processing LiDAR points" << std::endl;
455 pfnProgress(progress,pszMessage,pProgressArg);
463 for(
int irow=0;irow<nrow;++irow){
464 if(composite_opt[0]==
"number")
467 for(
int icol=0;icol<ncol;++icol){
468 std::vector<double> profile;
469 if(!inputData[irow][icol].size())
470 outputData[irow][icol]=(
static_cast<double>((nodata_opt[0])));
473 if(composite_opt[0]==
"min")
474 outputData[irow][icol]=stat.mymin(inputData[irow][icol]);
475 else if(composite_opt[0]==
"max")
476 outputData[irow][icol]=stat.mymax(inputData[irow][icol]);
477 else if(composite_opt[0]==
"absmin")
478 outputData[irow][icol]=stat.absmin(inputData[irow][icol]);
479 else if(composite_opt[0]==
"absmax")
480 outputData[irow][icol]=stat.absmax(inputData[irow][icol]);
481 else if(composite_opt[0]==
"median")
482 outputData[irow][icol]=stat.median(inputData[irow][icol]);
483 else if(composite_opt[0]==
"percentile")
484 outputData[irow][icol]=stat.percentile(inputData[irow][icol],inputData[irow][icol].begin(),inputData[irow][icol].end(),percentile_opt[0]);
485 else if(composite_opt[0]==
"mean")
486 outputData[irow][icol]=stat.mean(inputData[irow][icol]);
487 else if(composite_opt[0]==
"sum")
488 outputData[irow][icol]=stat.sum(inputData[irow][icol]);
489 else if(composite_opt[0]==
"first")
490 outputData[irow][icol]=inputData[irow][icol][0];
491 else if(composite_opt[0]==
"last")
492 outputData[irow][icol]=inputData[irow][icol].back();
493 else if(composite_opt[0]==
"profile"){
494 if(inputData[irow][icol].size()<2){
495 for(
int iband=0;iband<nband;++iband)
496 outputProfile[iband][icol]=static_cast<double>(nodata_opt[0]);
501 stat.minmax(inputData[irow][icol],inputData[irow][icol].begin(),inputData[irow][icol].end(),min,max);
503 std::cout <<
"min,max: " << min <<
"," << max << std::endl;
505 stat.percentiles(inputData[irow][icol],inputData[irow][icol].begin(),inputData[irow][icol].end(),profile,nband,min,max);
506 assert(profile.size()==nband);
507 for(
int iband=0;iband<nband;++iband)
508 outputProfile[iband][icol]=profile[iband];
511 for(
int iband=0;iband<nband;++iband)
512 outputProfile[iband][icol]=max;
516 std::cout <<
"Error: composite_opt " << composite_opt[0] <<
" not supported" << std::endl;
521 if(composite_opt[0]==
"profile"){
522 for(
int iband=0;iband<nband;++iband){
524 assert(outputProfile[iband].size()==outputWriter.
nrOfCol());
526 outputWriter.
writeData(outputProfile[iband],irow,iband);
528 catch(std::string errorString){
529 cout << errorString << endl;
534 progress=
static_cast<float>(irow)/outputWriter.
nrOfRow();
535 pfnProgress(progress,pszMessage,pProgressArg);
538 pfnProgress(progress,pszMessage,pProgressArg);
637 if(composite_opt[0]!=
"profile"){
639 std::cout <<
"writing output raster file" << std::endl;
641 pfnProgress(progress,pszMessage,pProgressArg);
642 for(
int irow=0;irow<nrow;++irow){
644 assert(outputData.size()==outputWriter.
nrOfRow());
645 assert(outputData[0].size()==outputWriter.
nrOfCol());
646 outputWriter.
writeData(outputData[irow],irow,0);
648 catch(std::string errorString){
649 cout << errorString << endl;
652 progress=
static_cast<float>(irow)/outputWriter.
nrOfRow();
653 pfnProgress(progress,pszMessage,pProgressArg);
657 pfnProgress(progress,pszMessage,pProgressArg);
659 std::cout <<
"closing lasReader" << std::endl;
660 outputWriter.
close();
bool geo2image(double x, double y, double &i, double &j) const
Convert georeferenced coordinates (x and y) to image coordinates (column and row) ...
CPLErr setProjectionProj4(const std::string &projection)
Set the projection for this dataset from user input (supports epsg:<number> format) ...
int nrOfCol(void) const
Get the number of columns of this dataset.
void setColorTable(const std::string &filename, int band=0)
Set the color table using an (ASCII) file with 5 columns (value R G B alpha)
int nrOfRow(void) const
Get the number of rows of this dataset.
bool image2geo(double i, double j, double &x, double &y) const
Convert image coordinates (column and row) to georeferenced coordinates (x and y) ...
CPLErr setGeoTransform(double *gt)
Set the geotransform data for this dataset.
bool isGeoRef() const
Is this dataset georeferenced (pixel size in y must be negative) ?
bool writeData(T &value, int col, int row, int band=0)
Write a single pixel cell value at a specific column and row for a specific band (all indices start c...
void open(const std::string &filename, const ImgReaderGdal &imgSrc, const std::vector< std::string > &options=std::vector< std::string >())
Open an image for writing, copying image attributes from a source image. Image is directly written to...
std::string getProjectionRef(void) const
Get the projection reference.
void close(void)
Close the image.
CPLErr GDALSetNoDataValue(double noDataValue, int band=0)
Set the GDAL (internal) no data value for this data set. Only a single no data value per band is supp...