pktools  2.6.3
Processing Kernel for geospatial data
pkcomposite.cc
1 /**********************************************************************
2 pkcomposite.cc: program to mosaic and composite geo-referenced images
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 <algorithm>
21 #include <vector>
22 #include <iostream>
23 #include <string>
24 #include "imageclasses/ImgReaderGdal.h"
25 #include "imageclasses/ImgWriterGdal.h"
26 #include "imageclasses/ImgReaderOgr.h"
27 #include "base/Vector2d.h"
28 #include "base/Optionpk.h"
29 #include "algorithms/StatFactory.h"
30 
31 /******************************************************************************/
111 namespace crule{
112  enum CRULE_TYPE {overwrite=0, maxndvi=1, maxband=2, minband=3, validband=4, mean=5, mode=6, median=7,sum=8,minallbands=9,maxallbands=10,stdev=11};
113 }
114 
115 using namespace std;
116 
117 int main(int argc, char *argv[])
118 {
119  Optionpk<string> input_opt("i", "input", "Input image file(s). If input contains multiple images, a multi-band output is created");
120  Optionpk<string> output_opt("o", "output", "Output image file");
121  Optionpk<int> band_opt("b", "band", "band index(es) to crop (leave empty if all bands must be retained)");
122  Optionpk<double> dx_opt("dx", "dx", "Output resolution in x (in meter) (empty: keep original resolution)");
123  Optionpk<double> dy_opt("dy", "dy", "Output resolution in y (in meter) (empty: keep original resolution)");
124  Optionpk<string> extent_opt("e", "extent", "get boundary from extent from polygons in vector file");
125  Optionpk<double> ulx_opt("ulx", "ulx", "Upper left x value bounding box", 0.0);
126  Optionpk<double> uly_opt("uly", "uly", "Upper left y value bounding box", 0.0);
127  Optionpk<double> lrx_opt("lrx", "lrx", "Lower right x value bounding box", 0.0);
128  Optionpk<double> lry_opt("lry", "lry", "Lower right y value bounding box", 0.0);
129  Optionpk<string> crule_opt("cr", "crule", "Composite rule (overwrite, maxndvi, maxband, minband, mean, mode (only for byte images), median, sum, maxallbands, minallbands, stdev", "overwrite");
130  Optionpk<int> ruleBand_opt("cb", "cband", "band index used for the composite rule (e.g., for ndvi, use --cband=0 --cband=1 with 0 and 1 indices for red and nir band respectively", 0);
131  Optionpk<double> srcnodata_opt("srcnodata", "srcnodata", "invalid value(s) for input raster dataset");
132  Optionpk<int> bndnodata_opt("bndnodata", "bndnodata", "Band(s) in input image to check if pixel is valid (used for srcnodata, min and max options)", 0);
133  Optionpk<double> minValue_opt("min", "min", "flag values smaller or equal to this value as invalid.");
134  Optionpk<double> maxValue_opt("max", "max", "flag values larger or equal to this value as invalid.");
135  Optionpk<double> dstnodata_opt("dstnodata", "dstnodata", "nodata value to put in output raster dataset if not valid or out of bounds.", 0);
136  Optionpk<string> resample_opt("r", "resampling-method", "Resampling method (near: nearest neighbor, bilinear: bi-linear interpolation).", "near");
137  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", "");
138  Optionpk<string> oformat_opt("of", "oformat", "Output image format (see also gdal_translate). Empty string: inherit from input image");
139  Optionpk<string> option_opt("co", "co", "Creation option for output file. Multiple options can be specified.");
140  Optionpk<string> projection_opt("a_srs", "a_srs", "Override the spatial reference for the output file (leave blank to copy from input file, use epsg:3035 to use European projection and force to European grid");
141  Optionpk<short> file_opt("file", "file", "write number of observations (1) or sequence nr of selected file (2) for each pixels as additional layer in composite", 0);
142  Optionpk<short> weight_opt("w", "weight", "Weights (type: short) for the composite, use one weight for each input file in same order as input files are provided). Use value 1 for equal weights.", 1);
143  Optionpk<short> class_opt("c", "class", "classes for multi-band output image: each band represents the number of observations for one specific class. Use value 0 for no multi-band output image.", 0);
144  Optionpk<string> colorTable_opt("ct", "ct", "color table file with 5 columns: id R G B ALFA (0: transparent, 255: solid)");
145  Optionpk<string> description_opt("d", "description", "Set image description");
146  Optionpk<short> verbose_opt("v", "verbose", "verbose", 0,2);
147 
148  file_opt.setHide(1);
149  weight_opt.setHide(1);
150  class_opt.setHide(1);
151  colorTable_opt.setHide(1);
152  description_opt.setHide(1);
153 
154  bool doProcess;//stop process when program was invoked with help option (-h --help)
155  try{
156  doProcess=input_opt.retrieveOption(argc,argv);
157  output_opt.retrieveOption(argc,argv);
158  band_opt.retrieveOption(argc,argv);
159  dx_opt.retrieveOption(argc,argv);
160  dy_opt.retrieveOption(argc,argv);
161  extent_opt.retrieveOption(argc,argv);
162  ulx_opt.retrieveOption(argc,argv);
163  uly_opt.retrieveOption(argc,argv);
164  lrx_opt.retrieveOption(argc,argv);
165  lry_opt.retrieveOption(argc,argv);
166  crule_opt.retrieveOption(argc,argv);
167  ruleBand_opt.retrieveOption(argc,argv);
168  srcnodata_opt.retrieveOption(argc,argv);
169  bndnodata_opt.retrieveOption(argc,argv);
170  minValue_opt.retrieveOption(argc,argv);
171  maxValue_opt.retrieveOption(argc,argv);
172  dstnodata_opt.retrieveOption(argc,argv);
173  resample_opt.retrieveOption(argc,argv);
174  otype_opt.retrieveOption(argc,argv);
175  oformat_opt.retrieveOption(argc,argv);
176  option_opt.retrieveOption(argc,argv);
177  projection_opt.retrieveOption(argc,argv);
178  file_opt.retrieveOption(argc,argv);
179  weight_opt.retrieveOption(argc,argv);
180  class_opt.retrieveOption(argc,argv);
181  colorTable_opt.retrieveOption(argc,argv);
182  description_opt.retrieveOption(argc,argv);
183  verbose_opt.retrieveOption(argc,argv);
184  }
185  catch(string predefinedString){
186  std::cout << predefinedString << std::endl;
187  exit(0);
188  }
189  if(!doProcess){
190  cout << endl;
191  cout << "Usage: pkcomposite -i input [-i input]* -o output" << endl;
192  cout << endl;
193  std::cout << "short option -h shows basic options only, use long option --help to show all options" << std::endl;
194  exit(0);//help was invoked, stop processing
195  }
196 
197  std::map<std::string, crule::CRULE_TYPE> cruleMap;
198  // //initialize cruleMap
199  // enum CRULE_TYPE {overwrite=0, maxndvi=1, maxband=2, minband=3, validband=4, mean=5, mode=6, median=7,sum=8};
200 
201  cruleMap["overwrite"]=crule::overwrite;
202  cruleMap["maxndvi"]=crule::maxndvi;
203  cruleMap["maxband"]=crule::maxband;
204  cruleMap["minband"]=crule::minband;
205  cruleMap["validband"]=crule::validband;
206  cruleMap["mean"]=crule::mean;
207  cruleMap["mode"]=crule::mode;
208  cruleMap["median"]=crule::median;
209  cruleMap["sum"]=crule::sum;
210  cruleMap["maxallbands"]=crule::maxallbands;
211  cruleMap["minallbands"]=crule::minallbands;
212  cruleMap["stdev"]=crule::stdev;
213 
214  if(srcnodata_opt.size()){
215  while(srcnodata_opt.size()<bndnodata_opt.size())
216  srcnodata_opt.push_back(srcnodata_opt[0]);
217  }
218  while(bndnodata_opt.size()<srcnodata_opt.size())
219  bndnodata_opt.push_back(bndnodata_opt[0]);
220  if(minValue_opt.size()){
221  while(minValue_opt.size()<bndnodata_opt.size())
222  minValue_opt.push_back(minValue_opt[0]);
223  while(bndnodata_opt.size()<minValue_opt.size())
224  bndnodata_opt.push_back(bndnodata_opt[0]);
225  }
226  if(maxValue_opt.size()){
227  while(maxValue_opt.size()<bndnodata_opt.size())
228  maxValue_opt.push_back(maxValue_opt[0]);
229  while(bndnodata_opt.size()<maxValue_opt.size())
230  bndnodata_opt.push_back(bndnodata_opt[0]);
231  }
232  RESAMPLE theResample;
233  if(resample_opt[0]=="near"){
234  theResample=NEAR;
235  if(verbose_opt[0])
236  cout << "resampling: nearest neighbor" << endl;
237  }
238  else if(resample_opt[0]=="bilinear"){
239  theResample=BILINEAR;
240  if(verbose_opt[0])
241  cout << "resampling: bilinear interpolation" << endl;
242  }
243  else{
244  std::cout << "Error: resampling method " << resample_opt[0] << " not supported" << std::endl;
245  exit(1);
246  }
247 
248  if(input_opt.empty()){
249  std::cerr << "No input file provided (use option -i). Use --help for help information" << std::endl;
250  exit(0);
251  }
252  int nband=0;
253  int nwriteBand=0;
254  int writeBand=0;
255  vector<short> bands;
256 
257  //get bounding box
258  double maxLRX=0;
259  double maxULY=0;
260  double minULX=0;
261  double minLRY=0;
262  double magic_x=1,magic_y=1;//magic pixel for GDAL map info
263 
264  GDALDataType theType=GDT_Unknown;
265  if(verbose_opt[0])
266  cout << "possible output data types: ";
267  for(int iType = 0; iType < GDT_TypeCount; ++iType){
268  if(verbose_opt[0])
269  cout << " " << GDALGetDataTypeName((GDALDataType)iType);
270  if( GDALGetDataTypeName((GDALDataType)iType) != NULL
271  && EQUAL(GDALGetDataTypeName((GDALDataType)iType),
272  otype_opt[0].c_str()))
273  theType=(GDALDataType) iType;
274  }
275  if(verbose_opt[0]){
276  cout << endl;
277  if(theType==GDT_Unknown)
278  cout << "Unknown output pixel type: " << otype_opt[0] << endl;
279  else
280  cout << "Output pixel type: " << GDALGetDataTypeName(theType) << endl;
281  }
282 
283  double dx=0;
284  double dy=0;
285  //get bounding box from extentReader if defined
286  ImgReaderOgr extentReader;
287  if(extent_opt.size()){
288  extentReader.open(extent_opt[0]);
289  if(!(extentReader.getExtent(ulx_opt[0],uly_opt[0],lrx_opt[0],lry_opt[0]))){
290  cerr << "Error: could not get extent from " << extent_opt[0] << endl;
291  exit(1);
292  }
293  else if(verbose_opt[0])
294  cout << "--ulx=" << ulx_opt[0] << " --uly=" << uly_opt[0] << " --lrx=" << lrx_opt[0] << " --lry=" << lry_opt[0] << endl;
295  }
296 
297  ImgReaderGdal imgReader;
298  string theProjection="";
299  GDALColorTable* theColorTable=NULL;
300  string imageType;
301  bool init=false;
302  for(int ifile=0;ifile<input_opt.size();++ifile){
303  try{
304  imgReader.open(input_opt[ifile]);
305  }
306  catch(string errorstring){
307  cerr << errorstring << " " << input_opt[ifile] << endl;
308  }
309  if(colorTable_opt.empty())
310  if(imgReader.getColorTable())
311  theColorTable=(imgReader.getColorTable()->Clone());
312  if(projection_opt.empty())
313  theProjection=imgReader.getProjection();
314  if(option_opt.findSubstring("INTERLEAVE=")==option_opt.end()){
315  string theInterleave="INTERLEAVE=";
316  theInterleave+=imgReader.getInterleave();
317  option_opt.push_back(theInterleave);
318  }
319 
320  if((ulx_opt[0]||uly_opt[0]||lrx_opt[0]||lry_opt[0])&&(!imgReader.covers(ulx_opt[0],uly_opt[0],lrx_opt[0],lry_opt[0]))){
321  if(verbose_opt[0])
322  cout << input_opt[ifile] << " not within bounding box, skipping..." << endl;
323  imgReader.close();
324  continue;
325  }
326  double theULX, theULY, theLRX, theLRY;
327  imgReader.getBoundingBox(theULX,theULY,theLRX,theLRY);
328  if(theLRY>theULY){
329  cerr << "Error: " << input_opt[ifile] << " is not georeferenced, only referenced images are supported for pkcomposite " << endl;
330  exit(1);
331  }
332  if(verbose_opt[0])
333  cout << "Bounding Box (ULX ULY LRX LRY): " << fixed << setprecision(6) << theULX << " " << theULY << " " << theLRX << " " << theLRY << endl;
334  if(!init){
335  if(verbose_opt[0]){
336  switch(cruleMap[crule_opt[0]]){
337  default:
338  case(crule::overwrite):
339  cout << "Composite rule: overwrite" << endl;
340  break;
341  case(crule::maxndvi):
342  cout << "Composite rule: max ndvi" << endl;
343  break;
344  case(crule::maxband):
345  cout << "Composite rule: max band" << endl;
346  break;
347  case(crule::minband):
348  cout << "Composite rule: min band" << endl;
349  break;
350  case(crule::validband):
351  cout << "Composite rule: valid band" << endl;
352  break;
353  case(crule::mean):
354  cout << "Composite rule: mean value" << endl;
355  break;
356  case(crule::mode):
357  cout << "Composite rule: max voting (only for byte images)" << endl;
358  break;
359  case(crule::median):
360  cout << "Composite rule: median" << endl;
361  break;
362  case(crule::stdev):
363  cout << "Composite rule: stdev" << endl;
364  break;
365  case(crule::sum):
366  cout << "Composite rule: sum" << endl;
367  break;
368  case(crule::minallbands):
369  cout << "Composite rule: minallbands" << endl;
370  break;
371  case(crule::maxallbands):
372  cout << "Composite rule: maxallbands" << endl;
373  break;
374  }
375  }
376  if(band_opt.size()){
377  nband=band_opt.size();
378  bands.resize(band_opt.size());
379  for(int iband=0;iband<band_opt.size();++iband){
380  bands[iband]=band_opt[iband];
381  assert(bands[iband]<imgReader.nrOfBand());
382  }
383  }
384  else{
385  nband=imgReader.nrOfBand();
386  bands.resize(nband);
387  for(int iband=0;iband<nband;++iband)
388  bands[iband]=iband;
389  }
390  for(int iband=0;iband<bndnodata_opt.size();++iband){
391  assert(bndnodata_opt[iband]>=0&&bndnodata_opt[iband]<nband);
392  }
393  //if output type not set, get type from input image
394  if(theType==GDT_Unknown){
395  theType=imgReader.getDataType();
396  if(verbose_opt[0])
397  cout << "Using data type from input image: " << GDALGetDataTypeName(theType) << endl;
398  }
399 
400  if(oformat_opt.size())//default
401  imageType=oformat_opt[0];
402  else
403  imageType=imgReader.getImageType();
404 
405  // dataType=imgReader.getDataType(0);
406  if(verbose_opt[0]){
407  cout << "type of data for " << input_opt[ifile] << ": " << theType << endl;
408  cout << "nband: " << nband << endl;
409  }
410 
411  maxLRX=theLRX;
412  maxULY=theULY;
413  minULX=theULX;
414  minLRY=theLRY;
415  if(dx_opt.size())
416  dx=dx_opt[0];
417  else
418  dx=imgReader.getDeltaX();
419  if(dy_opt.size())
420  dy=dy_opt[0];
421  else
422  dy=imgReader.getDeltaY();
423  // imgReader.getMagicPixel(magic_x,magic_y);
424  init=true;
425  }
426  else{
427  //convert bounding box to magic coordinates
428  //check uniformity magic pixel
429  // double test_x,test_y;
430  // imgReader.getMagicPixel(test_x,test_y);
431  // if(verbose_opt[0]){
432  // cout << "magic_x, magic_y: " << magic_x << ", " << magic_y << endl;
433  // }
434  // assert(magic_x==test_x);
435  // assert(magic_y==test_y);
436  maxLRX=(theLRX>maxLRX)?theLRX:maxLRX;
437  maxULY=(theULY>maxULY)?theULY:maxULY;
438  minULX=(theULX<minULX)?theULX:minULX;
439  minLRY=(theLRY<minLRY)?theLRY:minLRY;
440  }
441  imgReader.close();
442  }
443  if(verbose_opt[0])
444  cout << "bounding box input images (ULX ULY LRX LRY): " << fixed << setprecision(6) << minULX << " " << maxULY << " " << maxLRX << " " << minLRY << endl;
445  if(ulx_opt[0]||uly_opt[0]||lrx_opt[0]||lry_opt[0]){
446  maxLRX=lrx_opt[0];
447  maxULY=uly_opt[0];
448  minULX=ulx_opt[0];
449  minLRY=lry_opt[0];
450  }
451 
452  bool forceEUgrid=false;
453  if(projection_opt.size())
454  forceEUgrid=(!(projection_opt[0].compare("EPSG:3035"))||!(projection_opt[0].compare("EPSG:3035"))||projection_opt[0].find("ETRS-LAEA")!=string::npos);
455  if(forceEUgrid){
456  //force to LAEA grid
457  minULX=floor(minULX);
458  minULX-=static_cast<int>(minULX)%(static_cast<int>(dx));
459  maxULY=ceil(maxULY);
460  if(static_cast<int>(maxULY)%static_cast<int>(dy))
461  maxULY+=dy;
462  maxULY-=static_cast<int>(maxULY)%(static_cast<int>(dy));
463  maxLRX=ceil(maxLRX);
464  if(static_cast<int>(maxLRX)%static_cast<int>(dx))
465  maxLRX+=dx;
466  maxLRX-=static_cast<int>(maxLRX)%(static_cast<int>(dx));
467  minLRY=floor(minLRY);
468  minLRY-=static_cast<int>(minLRY)%(static_cast<int>(dy));
469  }
470 
471  if(verbose_opt[0])
472  cout << "bounding box composite image (ULX ULY LRX LRY): " << fixed << setprecision(6) << minULX << " " << maxULY << " " << maxLRX << " " << minLRY << endl;
473  //initialize image
474  if(verbose_opt[0])
475  cout << "initializing composite image..." << endl;
476 // double dcol=(maxLRX-minULX+dx-1)/dx;
477 // double drow=(maxULY-minLRY+dy-1)/dy;
478 // int ncol=static_cast<int>(dcol);
479 // int nrow=static_cast<int>(drow);
480 
481  int ncol=ceil((maxLRX-minULX)/dx);
482  int nrow=ceil((maxULY-minLRY)/dy);
483 
484  if(verbose_opt[0])
485  cout << "composite image dim (nrow x ncol): " << nrow << " x " << ncol << endl;
486  ImgWriterGdal imgWriter;
487  while(weight_opt.size()<input_opt.size())
488  weight_opt.push_back(weight_opt[0]);
489  if(verbose_opt[0]){
490  std::cout << weight_opt << std::endl;
491  }
492  if(cruleMap[crule_opt[0]]==crule::mode){
493  nwriteBand=(file_opt[0])? class_opt.size()+1:class_opt.size();
494  }
495  else
496  nwriteBand=(file_opt[0])? bands.size()+1:bands.size();
497  if(output_opt.empty()){
498  std::cerr << "No output file provided (use option -o). Use --help for help information" << std::endl;
499  exit(0);
500  }
501  if(verbose_opt[0])
502  cout << "open output image " << output_opt[0] << " with " << nwriteBand << " bands" << endl << flush;
503  try{
504  imgWriter.open(output_opt[0],ncol,nrow,nwriteBand,theType,imageType,option_opt);
505  for(int iband=0;iband<nwriteBand;++iband)
506  imgWriter.GDALSetNoDataValue(dstnodata_opt[0],iband);
507  }
508  catch(string error){
509  cout << error << endl;
510  }
511  if(description_opt.size())
512  imgWriter.setImageDescription(description_opt[0]);
513  double gt[6];
514  gt[0]=minULX;
515  gt[1]=dx;
516  gt[2]=0;
517  gt[3]=maxULY;
518  gt[4]=0;
519  gt[5]=-dy;
520  imgWriter.setGeoTransform(gt);
521  // imgWriter.setGeoTransform(minULX,maxULY,dx,dy,0,0);
522  if(projection_opt.size()){
523  if(verbose_opt[0])
524  cout << "projection: " << projection_opt[0] << endl;
525  imgWriter.setProjectionProj4(projection_opt[0]);
526  }
527  else if(theProjection!=""){
528  if(verbose_opt[0])
529  cout << "projection: " << theProjection << endl;
530  imgWriter.setProjection(theProjection);
531  }
532  if(imgWriter.getDataType()==GDT_Byte){
533  if(colorTable_opt.size()){
534  if(colorTable_opt[0]!="none")
535  imgWriter.setColorTable(colorTable_opt[0]);
536  }
537  else if(theColorTable)
538  imgWriter.setColorTable(theColorTable);
539  }
540  //create composite image
541  if(verbose_opt[0])
542  cout << "creating composite image" << endl;
543  Vector2d<double> writeBuffer(nband,imgWriter.nrOfCol());
544  vector<short> fileBuffer(ncol);//holds the number of used files
545  Vector2d<short> maxBuffer;//buffer used for maximum voting
546  Vector2d<double> readBuffer(nband);
548  if(cruleMap[crule_opt[0]]==crule::maxndvi)//ndvi
549  assert(ruleBand_opt.size()==2);
550  if(cruleMap[crule_opt[0]]==crule::mode){//max voting
551  maxBuffer.resize(imgWriter.nrOfCol(),256);//use only byte images for max voting
552  for(int iclass=0;iclass<class_opt.size();++iclass)
553  assert(class_opt[iclass]<maxBuffer.size());
554  }
555  int jb=0;
556  double readRow=0;
557  double readCol=0;
558  double lowerCol=0;
559  double upperCol=0;
560  const char* pszMessage;
561  void* pProgressArg=NULL;
562  GDALProgressFunc pfnProgress=GDALTermProgress;
563  double progress=0;
564  pfnProgress(progress,pszMessage,pProgressArg);
565  for(int irow=0;irow<imgWriter.nrOfRow();++irow){
566  Vector2d< vector<double> > storeBuffer;
567  vector<bool> writeValid(ncol);
568 
569  if(cruleMap[crule_opt[0]]==crule::mean ||
570  cruleMap[crule_opt[0]]==crule::median ||
571  cruleMap[crule_opt[0]]==crule::sum ||
572  cruleMap[crule_opt[0]]==crule::minallbands ||
573  cruleMap[crule_opt[0]]==crule::maxallbands ||
574  cruleMap[crule_opt[0]]==crule::stdev)
575  storeBuffer.resize(nband,ncol);
576  for(int icol=0;icol<imgWriter.nrOfCol();++icol){
577  writeValid[icol]=false;
578  fileBuffer[icol]=0;
579  if(cruleMap[crule_opt[0]]==crule::mode){//max voting
580  for(int iclass=0;iclass<256;++iclass)
581  maxBuffer[icol][iclass]=0;
582  }
583  else{
584  for(int iband=0;iband<nband;++iband)
585  writeBuffer[iband][icol]=dstnodata_opt[0];
586  }
587  }
588  for(int ifile=0;ifile<input_opt.size();++ifile){
589  try{
590  imgReader.open(input_opt[ifile]);
591  }
592  catch(string error){
593  cout << error << endl;
594  }
595  // assert(imgReader.getDataType()==theType);
596  assert(imgReader.nrOfBand()>=nband);
597  if(!imgReader.covers(minULX,maxULY,maxLRX,minLRY)){
598  imgReader.close();
599  continue;
600  }
601  double uli,ulj,lri,lrj;
602  imgReader.geo2image(minULX+(magic_x-1.0)*imgReader.getDeltaX(),maxULY-(magic_y-1.0)*imgReader.getDeltaY(),uli,ulj);
603  imgReader.geo2image(maxLRX+(magic_x-2.0)*imgReader.getDeltaX(),minLRY-(magic_y-2.0)*imgReader.getDeltaY(),lri,lrj);
604  uli=floor(uli);
605  ulj=floor(ulj);
606  lri=floor(lri);
607  lrj=floor(lrj);
608 
609  double startCol=uli;
610  double endCol=lri;
611  if(uli<0)
612  startCol=0;
613  else if(uli>=imgReader.nrOfCol())
614  startCol=imgReader.nrOfCol()-1;
615  if(lri<0)
616  endCol=0;
617  else if(lri>=imgReader.nrOfCol())
618  endCol=imgReader.nrOfCol()-1;
619  int readncol=endCol-startCol+1;
620 
621  //convert irow to geo
622  double x=0;
623  double y=0;
624  imgWriter.image2geo(0,irow,x,y);
625  //lookup corresponding row for irow in this file
626  imgReader.geo2image(x,y,readCol,readRow);
627  if(readRow<0||readRow>=imgReader.nrOfRow()){
628  imgReader.close();
629  continue;
630  }
631  // for(int iband=0;iband<imgReader.nrOfBand();++iband){
632  for(int iband=0;iband<nband;++iband){
633  int readBand=(band_opt.size()>iband)? band_opt[iband] : iband;
634  readBuffer[iband].resize(readncol);
635  try{
636  imgReader.readData(readBuffer[iband],GDT_Float64,startCol,endCol,readRow,readBand,theResample);
637  }
638  catch(string error){
639  cerr << "error reading image " << input_opt[ifile] << ": " << endl;
640  throw;
641  }
642  }
643 
644  for(int ib=0;ib<ncol;++ib){
645  assert(imgWriter.image2geo(ib,irow,x,y));
646  //lookup corresponding row for irow in this file
647  imgReader.geo2image(x,y,readCol,readRow);
648  if(readCol<0||readCol>=imgReader.nrOfCol())
649  continue;
650  double val_current=0;
651  double val_new=0;
652  bool readValid=true;
653  switch(theResample){
654  case(BILINEAR):
655  lowerCol=readCol-0.5;
656  lowerCol=static_cast<int>(lowerCol);
657  upperCol=readCol+0.5;
658  upperCol=static_cast<int>(upperCol);
659  if(lowerCol<0)
660  lowerCol=0;
661  if(upperCol>=imgReader.nrOfCol())
662  upperCol=imgReader.nrOfCol()-1;
663  for(int vband=0;vband<bndnodata_opt.size();++vband){
664  val_new=(readCol-0.5-lowerCol)*readBuffer[bndnodata_opt[vband]][upperCol-startCol]+(1-readCol+0.5+lowerCol)*readBuffer[bndnodata_opt[vband]][lowerCol-startCol];
665  if(minValue_opt.size()>vband){
666  if(val_new<=minValue_opt[vband]){
667  readValid=false;
668  break;
669  }
670  }
671  if(maxValue_opt.size()>vband){
672  if(val_new>=maxValue_opt[vband]){
673  readValid=false;
674  break;
675  }
676  }
677  if(srcnodata_opt.size()>vband){
678  if(val_new==srcnodata_opt[vband]){
679  readValid=false;
680  break;
681  }
682  }
683  }
684  break;
685  default:
686  readCol=static_cast<int>(readCol);
687  for(int vband=0;vband<bndnodata_opt.size();++vband){
688  val_new=readBuffer[bndnodata_opt[vband]][readCol-startCol];
689  if(minValue_opt.size()>vband){
690  if(val_new<=minValue_opt[vband]){
691  readValid=false;
692  break;
693  }
694  }
695  if(maxValue_opt.size()>vband){
696  if(val_new>=maxValue_opt[vband]){
697  readValid=false;
698  break;
699  }
700  }
701  if(srcnodata_opt.size()>vband){
702  if(val_new==srcnodata_opt[vband]){
703  readValid=false;
704  break;
705  }
706  }
707  }
708  break;
709  }
710  if(readValid){
711  if(file_opt[0]==1)
712  ++fileBuffer[ib];
713  if(writeValid[ib]){
714  int iband=0;
715  switch(cruleMap[crule_opt[0]]){
716  case(crule::maxndvi):{//max ndvi
717  double red_current=writeBuffer[ruleBand_opt[0]][ib];
718  double nir_current=writeBuffer[ruleBand_opt[1]][ib];
719  double ndvi_current=0;
720  if(red_current+nir_current>0&&red_current>=0&&nir_current>=0)
721  ndvi_current=(nir_current-red_current)/(nir_current+red_current);
722  double ndvi_new=0;
723  double red_new=0;
724  double nir_new=0;
725  switch(theResample){
726  case(BILINEAR):
727  lowerCol=readCol-0.5;
728  lowerCol=static_cast<int>(lowerCol);
729  upperCol=readCol+0.5;
730  upperCol=static_cast<int>(upperCol);
731  if(lowerCol<0)
732  lowerCol=0;
733  if(upperCol>=imgReader.nrOfCol())
734  upperCol=imgReader.nrOfCol()-1;
735  red_new=(readCol-0.5-lowerCol)*readBuffer[ruleBand_opt[0]][upperCol-startCol]+(1-readCol+0.5+lowerCol)*readBuffer[ruleBand_opt[0]][lowerCol-startCol];
736  nir_new=(readCol-0.5-lowerCol)*readBuffer[ruleBand_opt[1]][upperCol-startCol]+(1-readCol+0.5+lowerCol)*readBuffer[ruleBand_opt[1]][lowerCol-startCol];
737  if(red_new+nir_new>0&&red_new>=0&&nir_new>=0)
738  ndvi_new=(nir_new-red_new)/(nir_new+red_new);
739  if(ndvi_new>=ndvi_current){
740  for(iband=0;iband<nband;++iband){
741  val_new=(readCol-0.5-lowerCol)*readBuffer[iband][upperCol-startCol]+(1-readCol+0.5+lowerCol)*readBuffer[iband][lowerCol-startCol];
742  writeBuffer[iband][ib]=val_new;
743  }
744  if(file_opt[0]>1)
745  fileBuffer[ib]=ifile;
746  }
747  break;
748  default:
749  readCol=static_cast<int>(readCol);
750  red_new=readBuffer[ruleBand_opt[0]][readCol-startCol];
751  nir_new=readBuffer[ruleBand_opt[1]][readCol-startCol];
752  if(red_new+nir_new>0&&red_new>=0&&nir_new>=0)
753  ndvi_new=(nir_new-red_new)/(nir_new+red_new);
754  if(ndvi_new>=ndvi_current){
755  for(iband=0;iband<nband;++iband){
756  val_new=readBuffer[iband][readCol-startCol];
757  writeBuffer[iband][ib]=val_new;
758  }
759  if(file_opt[0]>1)
760  fileBuffer[ib]=ifile;
761  }
762  break;
763  }
764  break;
765  }
766  case(crule::maxband):
767  case(crule::minband):
768  case(crule::validband)://max,min,valid band
769  val_current=writeBuffer[ruleBand_opt[0]][ib];
770  switch(theResample){
771  case(BILINEAR):
772  lowerCol=readCol-0.5;
773  lowerCol=static_cast<int>(lowerCol);
774  upperCol=readCol+0.5;
775  upperCol=static_cast<int>(upperCol);
776  if(lowerCol<0)
777  lowerCol=0;
778  if(upperCol>=imgReader.nrOfCol())
779  upperCol=imgReader.nrOfCol()-1;
780  val_new=(readCol-0.5-lowerCol)*readBuffer[ruleBand_opt[0]][upperCol-startCol]+(1-readCol+0.5+lowerCol)*readBuffer[ruleBand_opt[0]][lowerCol-startCol];
781  val_new*=weight_opt[ifile];
782  if((cruleMap[crule_opt[0]]==crule::maxband&&val_new>val_current)||(cruleMap[crule_opt[0]]==crule::minband&&val_new<val_current)||(cruleMap[crule_opt[0]]==crule::validband)){//&&val_new>minValue_opt[0]&&val_new<maxValue_opt[0])){
783  for(iband=0;iband<nband;++iband){
784  val_new=(readCol-0.5-lowerCol)*readBuffer[iband][upperCol-startCol]+(1-readCol+0.5+lowerCol)*readBuffer[iband][lowerCol-startCol];
785  val_new*=weight_opt[ifile];
786  writeBuffer[iband][ib]=val_new;
787  }
788  if(file_opt[0]>1)
789  fileBuffer[ib]=ifile;
790  }
791  break;
792  default:
793  readCol=static_cast<int>(readCol);
794  val_new=readBuffer[ruleBand_opt[0]][readCol-startCol];
795  val_new*=weight_opt[ifile];
796  if((cruleMap[crule_opt[0]]==crule::maxband&&val_new>val_current)||(cruleMap[crule_opt[0]]==crule::minband&&val_new<val_current)||(cruleMap[crule_opt[0]]==crule::validband)){//&&val_new>minValue_opt[0]&&val_new<maxValue_opt[0])){
797  for(iband=0;iband<nband;++iband){
798  val_new=readBuffer[iband][readCol-startCol];
799  val_new*=weight_opt[ifile];
800  writeBuffer[iband][ib]=val_new;
801  }
802  if(file_opt[0]>1)
803  fileBuffer[ib]=ifile;
804  }
805  break;
806  }
807  break;
808  case(crule::mode)://max voting (only for Byte images)
809  switch(theResample){
810  case(BILINEAR):
811  lowerCol=readCol-0.5;
812  lowerCol=static_cast<int>(lowerCol);
813  upperCol=readCol+0.5;
814  upperCol=static_cast<int>(upperCol);
815  if(lowerCol<0)
816  lowerCol=0;
817  if(upperCol>=imgReader.nrOfCol())
818  upperCol=imgReader.nrOfCol()-1;
819  for(iband=0;iband<nband;++iband){
820  val_new=(readCol-0.5-lowerCol)*readBuffer[iband][upperCol-startCol]+(1-readCol+0.5+lowerCol)*readBuffer[iband][lowerCol-startCol];
821  maxBuffer[ib][val_new]=maxBuffer[ib][val_new]+weight_opt[ifile];
822  // ++(maxBuffer[ib][val_new]);
823  }
824  break;
825  default:
826  readCol=static_cast<int>(readCol);
827  for(iband=0;iband<nband;++iband){
828  val_new=readBuffer[iband][readCol-startCol];
829  maxBuffer[ib][val_new]=maxBuffer[ib][val_new]+weight_opt[ifile];
830  }
831  break;
832  }
833  break;
834  case(crule::mean)://mean value
835  case(crule::median)://median value
836  case(crule::sum)://sum value
837  case(crule::minallbands)://minimum for each and every band
838  case(crule::maxallbands)://maximum for each and every band
839  case(crule::stdev)://maximum for each and every band
840  switch(theResample){
841  case(BILINEAR):
842  lowerCol=readCol-0.5;
843  lowerCol=static_cast<int>(lowerCol);
844  upperCol=readCol+0.5;
845  upperCol=static_cast<int>(upperCol);
846  if(lowerCol<0)
847  lowerCol=0;
848  if(upperCol>=imgReader.nrOfCol())
849  upperCol=imgReader.nrOfCol()-1;
850  for(iband=0;iband<nband;++iband){
851  val_new=(readCol-0.5-lowerCol)*readBuffer[iband][upperCol-startCol]+(1-readCol+0.5+lowerCol)*readBuffer[iband][lowerCol-startCol];
852  val_new*=weight_opt[ifile];
853  storeBuffer[iband][ib].push_back(val_new);
854  }
855  break;
856  default:
857  readCol=static_cast<int>(readCol);
858  for(iband=0;iband<nband;++iband){
859  val_new=readBuffer[iband][readCol-startCol];
860  val_new*=weight_opt[ifile];
861  storeBuffer[iband][ib].push_back(val_new);
862  assert(ifile>0);
863  // assert(weight_opt[ifile]>=0);
864  // assert(storeBuffer[iband][ib].back()>=0);
865  }
866  break;
867  }
868  if(file_opt[0]>1)
869  fileBuffer[ib]=ifile;
870  break;
871  case(crule::overwrite):
872  default:
873  switch(theResample){
874  case(BILINEAR):
875  lowerCol=readCol-0.5;
876  lowerCol=static_cast<int>(lowerCol);
877  upperCol=readCol+0.5;
878  upperCol=static_cast<int>(upperCol);
879  if(lowerCol<0)
880  lowerCol=0;
881  if(upperCol>=imgReader.nrOfCol())
882  upperCol=imgReader.nrOfCol()-1;
883  for(iband=0;iband<nband;++iband){
884  val_new=(readCol-0.5-lowerCol)*readBuffer[iband][upperCol-startCol]+(1-readCol+0.5+lowerCol)*readBuffer[iband][lowerCol-startCol];
885  val_new*=weight_opt[ifile];
886  writeBuffer[iband][ib]=val_new;
887  }
888  break;
889  default:
890  readCol=static_cast<int>(readCol);
891  for(iband=0;iband<nband;++iband){
892  val_new=readBuffer[iband][readCol-startCol];
893  val_new*=weight_opt[ifile];
894  writeBuffer[iband][ib]=val_new;
895  }
896  break;
897  }
898  if(file_opt[0]>1)
899  fileBuffer[ib]=ifile;
900  break;
901  }
902  }
903  else{
904  writeValid[ib]=true;//readValid was true
905  int iband=0;
906  switch(cruleMap[crule_opt[0]]){
907  case(crule::mean):
908  case(crule::median):
909  case(crule::sum):
910  case(crule::minallbands):
911  case(crule::maxallbands):
912  case(crule::stdev):
913  switch(theResample){
914  case(BILINEAR):
915  lowerCol=readCol-0.5;
916  lowerCol=static_cast<int>(lowerCol);
917  upperCol=readCol+0.5;
918  upperCol=static_cast<int>(upperCol);
919  if(lowerCol<0)
920  lowerCol=0;
921  if(upperCol>=imgReader.nrOfCol())
922  upperCol=imgReader.nrOfCol()-1;
923  for(iband=0;iband<nband;++iband){
924  val_new=(readCol-0.5-lowerCol)*readBuffer[iband][upperCol-startCol]+(1-readCol+0.5+lowerCol)*readBuffer[iband][lowerCol-startCol];
925  val_new*=weight_opt[ifile];
926  storeBuffer[iband][ib].push_back(val_new);
927  }
928  break;
929  default:
930  readCol=static_cast<int>(readCol);
931  for(iband=0;iband<nband;++iband){
932  val_new=readBuffer[iband][readCol-startCol];
933  val_new*=weight_opt[ifile];
934  storeBuffer[iband][ib].push_back(val_new);
935  }
936  break;
937  }
938  if(file_opt[0]>1)
939  fileBuffer[ib]=ifile;
940  break;
941  case(crule::mode):
942  switch(theResample){
943  case(BILINEAR):
944  lowerCol=readCol-0.5;
945  lowerCol=static_cast<int>(lowerCol);
946  upperCol=readCol+0.5;
947  upperCol=static_cast<int>(upperCol);
948  if(lowerCol<0)
949  lowerCol=0;
950  if(upperCol>=imgReader.nrOfCol())
951  upperCol=imgReader.nrOfCol()-1;
952  for(iband=0;iband<nband;++iband){
953  val_new=(readCol-0.5-lowerCol)*readBuffer[iband][upperCol-startCol]+(1-readCol+0.5+lowerCol)*readBuffer[iband][lowerCol-startCol];
954  maxBuffer[ib][val_new]=maxBuffer[ib][val_new]+weight_opt[ifile];
955  // ++(maxBuffer[ib][val_new]);
956  }
957  break;
958  default:
959  readCol=static_cast<int>(readCol);
960  for(iband=0;iband<nband;++iband){
961  val_new=readBuffer[iband][readCol-startCol];
962  maxBuffer[ib][val_new]=maxBuffer[ib][val_new]+weight_opt[ifile];
963  }
964  // ++(maxBuffer[ib][val_new]);
965  break;
966  }
967  break;
968  default:
969  switch(theResample){
970  case(BILINEAR):
971  lowerCol=readCol-0.5;
972  lowerCol=static_cast<int>(lowerCol);
973  upperCol=readCol+0.5;
974  upperCol=static_cast<int>(upperCol);
975  if(lowerCol<0)
976  lowerCol=0;
977  if(upperCol>=imgReader.nrOfCol())
978  upperCol=imgReader.nrOfCol()-1;
979  for(iband=0;iband<nband;++iband){
980  val_new=(readCol-0.5-lowerCol)*readBuffer[iband][upperCol-startCol]+(1-readCol+0.5+lowerCol)*readBuffer[iband][lowerCol-startCol];
981  val_new*=weight_opt[ifile];
982  writeBuffer[iband][ib]=val_new;
983  }
984  break;
985  default:
986  readCol=static_cast<int>(readCol);
987  for(iband=0;iband<nband;++iband){
988  val_new=readBuffer[iband][readCol-startCol];
989  val_new*=weight_opt[ifile];
990  writeBuffer[iband][ib]=val_new;
991  }
992  break;
993  }
994  if(file_opt[0]>1)
995  fileBuffer[ib]=ifile;
996  break;
997  }
998  }
999  }
1000  }
1001  imgReader.close();
1002  }
1003  if(cruleMap[crule_opt[0]]==crule::mode){
1004  vector<short> classBuffer(imgWriter.nrOfCol());
1005  if(class_opt.size()>1){
1006  for(int iclass=0;iclass<class_opt.size();++iclass){
1007  for(int icol=0;icol<imgWriter.nrOfCol();++icol)
1008  classBuffer[icol]=maxBuffer[icol][class_opt[iclass]];
1009  try{
1010  imgWriter.writeData(classBuffer,GDT_Int16,irow,iclass);
1011  }
1012  catch(string error){
1013  cerr << "error writing image file " << output_opt[0] << ": " << error << endl;
1014  throw;
1015  }
1016  }
1017  }
1018  else{
1019  for(int icol=0;icol<imgWriter.nrOfCol();++icol){
1020  vector<short>::iterator maxit=maxBuffer[icol].begin();
1021  maxit=stat.mymax(maxBuffer[icol],maxBuffer[icol].begin(),maxBuffer[icol].end());
1022  writeBuffer[0][icol]=distance(maxBuffer[icol].begin(),maxit);
1023  if(file_opt[0]>1)
1024  fileBuffer[icol]=*(maxit);
1025  }
1026  try{
1027  imgWriter.writeData(writeBuffer[0],GDT_Float64,irow,0);
1028  if(file_opt[0])
1029  imgWriter.writeData(fileBuffer,GDT_Int16,irow,1);
1030  }
1031  catch(string error){
1032  cerr << "error writing image file " << output_opt[0] << ": " << error << endl;
1033  throw;
1034  }
1035  }
1036  }
1037  else{
1038  for(int iband=0;iband<bands.size();++iband){
1039  // assert(writeBuffer[bands[iband]].size()==imgWriter.nrOfCol());
1040  assert(writeBuffer[iband].size()==imgWriter.nrOfCol());
1041  for(int icol=0;icol<imgWriter.nrOfCol();++icol){
1042  try{
1043  switch(cruleMap[crule_opt[0]]){
1044  case(crule::mean):
1045  // writeBuffer[iband][icol]=stat.mean(storeBuffer[bands[iband]][icol]);
1046  writeBuffer[iband][icol]=stat.mean(storeBuffer[iband][icol]);
1047  break;
1048  case(crule::median):
1049  // writeBuffer[iband][icol]=stat.median(storeBuffer[bands[iband]][icol]);
1050  writeBuffer[iband][icol]=stat.median(storeBuffer[iband][icol]);
1051  break;
1052  case(crule::sum):
1053  // writeBuffer[iband][icol]=stat.sum(storeBuffer[bands[iband]][icol]);
1054  writeBuffer[iband][icol]=stat.sum(storeBuffer[iband][icol]);
1055  break;
1056  case(crule::minallbands):
1057  // writeBuffer[iband][icol]=stat.mymin(storeBuffer[bands[iband]][icol]);
1058  writeBuffer[iband][icol]=stat.mymin(storeBuffer[iband][icol]);
1059  break;
1060  case(crule::maxallbands):
1061  // writeBuffer[iband][icol]=stat.mymax(storeBuffer[bands[iband]][icol]);
1062  writeBuffer[iband][icol]=stat.mymax(storeBuffer[iband][icol]);
1063  break;
1064  case(crule::stdev):
1065  // writeBuffer[iband][icol]=sqrt(stat.var(storeBuffer[bands[iband]][icol]));
1066  writeBuffer[iband][icol]=sqrt(stat.var(storeBuffer[iband][icol]));
1067  break;
1068  default:
1069  break;
1070  }
1071  }
1072  catch(string error){
1073  if(verbose_opt[0])
1074  cerr << error << endl;
1075  writeBuffer[iband][icol]=dstnodata_opt[0];
1076  continue;
1077  }
1078  }
1079  try{
1080  imgWriter.writeData(writeBuffer[iband],GDT_Float64,irow,iband);
1081  }
1082  catch(string error){
1083  cerr << error << " in " << output_opt[0] << endl;
1084  throw;
1085  }
1086  }
1087  if(file_opt[0]){
1088  try{
1089  imgWriter.writeData(fileBuffer,GDT_Int16,irow,bands.size());
1090  }
1091  catch(string error){
1092  cerr << error << " in " << output_opt[0] << endl;
1093  throw;
1094  }
1095  }
1096  }
1097  progress=static_cast<float>(irow+1.0)/imgWriter.nrOfRow();
1098  pfnProgress(progress,pszMessage,pProgressArg);
1099  }
1100  imgWriter.close();
1101 }
1102