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