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