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