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