pktools  2.6.5
Processing Kernel for geospatial data
pkcrop.cc
1 /**********************************************************************
2 pkcrop.cc: perform raster data operations on image such as crop, extract and stack bands
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 <assert.h>
21 #include <cstdlib>
22 #include <string>
23 #include <list>
24 #include <iostream>
25 #include <algorithm>
26 #include "imageclasses/ImgWriterGdal.h"
27 #include "imageclasses/ImgReaderGdal.h"
28 #include "imageclasses/ImgReaderOgr.h"
29 #include "base/Optionpk.h"
30 #include "algorithms/Egcs.h"
31 
32 /******************************************************************************/
99 using namespace std;
100 
101 int main(int argc, char *argv[])
102 {
103  Optionpk<string> input_opt("i", "input", "Input image file(s). If input contains multiple images, a multi-band output is created");
104  Optionpk<string> output_opt("o", "output", "Output image file");
105  Optionpk<string> projection_opt("a_srs", "a_srs", "Override the projection for the output file (leave blank to copy from input file, use epsg:3035 to use European projection and force to European grid");
106  //todo: support layer names
107  Optionpk<string> extent_opt("e", "extent", "get boundary from extent from polygons in vector file");
108  Optionpk<bool> cut_opt("cut", "crop_to_cutline", "Crop the extent of the target dataset to the extent of the cutline.",false);
109  Optionpk<string> mask_opt("m", "mask", "Use the the specified file as a validity mask (0 is nodata).");
110  Optionpk<float> msknodata_opt("msknodata", "msknodata", "Mask value not to consider for crop.", 0);
111  Optionpk<short> mskband_opt("mskband", "mskband", "Mask band to read (0 indexed). Provide band for each mask.", 0);
112  Optionpk<double> ulx_opt("ulx", "ulx", "Upper left x value bounding box", 0.0);
113  Optionpk<double> uly_opt("uly", "uly", "Upper left y value bounding box", 0.0);
114  Optionpk<double> lrx_opt("lrx", "lrx", "Lower right x value bounding box", 0.0);
115  Optionpk<double> lry_opt("lry", "lry", "Lower right y value bounding box", 0.0);
116  Optionpk<double> dx_opt("dx", "dx", "Output resolution in x (in meter) (empty: keep original resolution)");
117  Optionpk<double> dy_opt("dy", "dy", "Output resolution in y (in meter) (empty: keep original resolution)");
118  Optionpk<double> cx_opt("x", "x", "x-coordinate of image center to crop (in meter)");
119  Optionpk<double> cy_opt("y", "y", "y-coordinate of image center to crop (in meter)");
120  Optionpk<double> nx_opt("nx", "nx", "image size in x to crop (in meter)");
121  Optionpk<double> ny_opt("ny", "ny", "image size in y to crop (in meter)");
122  Optionpk<int> ns_opt("ns", "ns", "number of samples to crop (in pixels)");
123  Optionpk<int> nl_opt("nl", "nl", "number of lines to crop (in pixels)");
124  Optionpk<unsigned short> band_opt("b", "band", "band index to crop (leave empty to retain all bands)");
125  Optionpk<unsigned short> bstart_opt("sband", "startband", "Start band sequence number");
126  Optionpk<unsigned short> bend_opt("eband", "endband", "End band sequence number");
127  Optionpk<double> autoscale_opt("as", "autoscale", "scale output to min and max, e.g., --autoscale 0 --autoscale 255");
128  Optionpk<double> scale_opt("scale", "scale", "output=scale*input+offset");
129  Optionpk<double> offset_opt("offset", "offset", "output=scale*input+offset");
130  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","");
131  Optionpk<string> oformat_opt("of", "oformat", "Output image format (see also gdal_translate). Empty string: inherit from input image");
132  Optionpk<string> option_opt("co", "co", "Creation option for output file. Multiple options can be specified.");
133  Optionpk<string> colorTable_opt("ct", "ct", "color table (file with 5 columns: id R G B ALFA (0: transparent, 255: solid)");
134  Optionpk<float> nodata_opt("nodata", "nodata", "Nodata value to put in image if out of bounds.");
135  Optionpk<string> resample_opt("r", "resampling-method", "Resampling method (near: nearest neighbor, bilinear: bi-linear interpolation).", "near");
136  Optionpk<string> description_opt("d", "description", "Set image description");
137  Optionpk<short> verbose_opt("v", "verbose", "verbose", 0,2);
138 
139  extent_opt.setHide(1);
140  cut_opt.setHide(1);
141  bstart_opt.setHide(1);
142  bend_opt.setHide(1);
143  mask_opt.setHide(1);
144  msknodata_opt.setHide(1);
145  mskband_opt.setHide(1);
146  option_opt.setHide(1);
147  cx_opt.setHide(1);
148  cy_opt.setHide(1);
149  nx_opt.setHide(1);
150  ny_opt.setHide(1);
151  ns_opt.setHide(1);
152  nl_opt.setHide(1);
153  scale_opt.setHide(1);
154  offset_opt.setHide(1);
155  nodata_opt.setHide(1);
156  description_opt.setHide(1);
157 
158  bool doProcess;//stop process when program was invoked with help option (-h --help)
159  try{
160  doProcess=input_opt.retrieveOption(argc,argv);
161  output_opt.retrieveOption(argc,argv);
162  projection_opt.retrieveOption(argc,argv);
163  ulx_opt.retrieveOption(argc,argv);
164  uly_opt.retrieveOption(argc,argv);
165  lrx_opt.retrieveOption(argc,argv);
166  lry_opt.retrieveOption(argc,argv);
167  band_opt.retrieveOption(argc,argv);
168  bstart_opt.retrieveOption(argc,argv);
169  bend_opt.retrieveOption(argc,argv);
170  autoscale_opt.retrieveOption(argc,argv);
171  otype_opt.retrieveOption(argc,argv);
172  oformat_opt.retrieveOption(argc,argv);
173  colorTable_opt.retrieveOption(argc,argv);
174  dx_opt.retrieveOption(argc,argv);
175  dy_opt.retrieveOption(argc,argv);
176  resample_opt.retrieveOption(argc,argv);
177  extent_opt.retrieveOption(argc,argv);
178  cut_opt.retrieveOption(argc,argv);
179  mask_opt.retrieveOption(argc,argv);
180  msknodata_opt.retrieveOption(argc,argv);
181  mskband_opt.retrieveOption(argc,argv);
182  option_opt.retrieveOption(argc,argv);
183  cx_opt.retrieveOption(argc,argv);
184  cy_opt.retrieveOption(argc,argv);
185  nx_opt.retrieveOption(argc,argv);
186  ny_opt.retrieveOption(argc,argv);
187  ns_opt.retrieveOption(argc,argv);
188  nl_opt.retrieveOption(argc,argv);
189  scale_opt.retrieveOption(argc,argv);
190  offset_opt.retrieveOption(argc,argv);
191  nodata_opt.retrieveOption(argc,argv);
192  description_opt.retrieveOption(argc,argv);
193  verbose_opt.retrieveOption(argc,argv);
194  }
195  catch(string predefinedString){
196  std::cout << predefinedString << std::endl;
197  exit(0);
198  }
199  if(verbose_opt[0])
200  cout << setprecision(12) << "--ulx=" << ulx_opt[0] << " --uly=" << uly_opt[0] << " --lrx=" << lrx_opt[0] << " --lry=" << lry_opt[0] << endl;
201 
202  if(!doProcess){
203  cout << endl;
204  cout << "Usage: pkcrop -i input -o output" << endl;
205  cout << endl;
206  std::cout << "short option -h shows basic options only, use long option --help to show all options" << std::endl;
207  exit(0);//help was invoked, stop processing
208  }
209  if(input_opt.empty()){
210  std::cerr << "No input file provided (use option -i). Use --help for help information" << std::endl;
211  exit(0);
212  }
213  if(output_opt.empty()){
214  std::cerr << "No output file provided (use option -o). Use --help for help information" << std::endl;
215  exit(0);
216  }
217 
218  float nodataValue=nodata_opt.size()? nodata_opt[0] : 0;
219  RESAMPLE theResample;
220  if(resample_opt[0]=="near"){
221  theResample=NEAR;
222  if(verbose_opt[0])
223  cout << "resampling: nearest neighbor" << endl;
224  }
225  else if(resample_opt[0]=="bilinear"){
226  theResample=BILINEAR;
227  if(verbose_opt[0])
228  cout << "resampling: bilinear interpolation" << endl;
229  }
230  else{
231  std::cout << "Error: resampling method " << resample_opt[0] << " not supported" << std::endl;
232  exit(1);
233  }
234 
235  const char* pszMessage;
236  void* pProgressArg=NULL;
237  GDALProgressFunc pfnProgress=GDALTermProgress;
238  double progress=0;
239  pfnProgress(progress,pszMessage,pProgressArg);
240  ImgReaderGdal imgReader;
241  ImgWriterGdal imgWriter;
242  //open input images to extract number of bands and spatial resolution
243  int ncropband=0;//total number of bands to write
244  double dx=0;
245  double dy=0;
246  if(dx_opt.size())
247  dx=dx_opt[0];
248  if(dy_opt.size())
249  dy=dy_opt[0];
250 
251  //convert start and end band options to vector of band indexes
252  try{
253  if(bstart_opt.size()){
254  if(bend_opt.size()!=bstart_opt.size()){
255  string errorstring="Error: options for start and end band indexes must be provided as pairs, missing end band";
256  throw(errorstring);
257  }
258  band_opt.clear();
259  for(int ipair=0;ipair<bstart_opt.size();++ipair){
260  if(bend_opt[ipair]<=bstart_opt[ipair]){
261  string errorstring="Error: index for end band must be smaller then start band";
262  throw(errorstring);
263  }
264  for(int iband=bstart_opt[ipair];iband<=bend_opt[ipair];++iband)
265  band_opt.push_back(iband);
266  }
267  }
268  }
269  catch(string error){
270  cerr << error << std::endl;
271  exit(1);
272  }
273 
274  bool isGeoRef=false;
275  string projectionString;
276  for(int iimg=0;iimg<input_opt.size();++iimg){
277  imgReader.open(input_opt[iimg]);
278  if(!isGeoRef)
279  isGeoRef=imgReader.isGeoRef();
280  if(imgReader.isGeoRef()&&projection_opt.empty())
281  projectionString=imgReader.getProjection();
282  if(dx_opt.empty()){
283  if(!iimg||imgReader.getDeltaX()<dx)
284  dx=imgReader.getDeltaX();
285  }
286  if(dy_opt.empty()){
287  if(!iimg||imgReader.getDeltaY()<dy)
288  dy=imgReader.getDeltaY();
289  }
290  if(band_opt.size())
291  ncropband+=band_opt.size();
292  else
293  ncropband+=imgReader.nrOfBand();
294  imgReader.close();
295  }
296 
297  GDALDataType theType=GDT_Unknown;
298  if(verbose_opt[0])
299  cout << "possible output data types: ";
300  for(int iType = 0; iType < GDT_TypeCount; ++iType){
301  if(verbose_opt[0])
302  cout << " " << GDALGetDataTypeName((GDALDataType)iType);
303  if( GDALGetDataTypeName((GDALDataType)iType) != NULL
304  && EQUAL(GDALGetDataTypeName((GDALDataType)iType),
305  otype_opt[0].c_str()))
306  theType=(GDALDataType) iType;
307  }
308  if(verbose_opt[0]){
309  cout << endl;
310  if(theType==GDT_Unknown)
311  cout << "Unknown output pixel type: " << otype_opt[0] << endl;
312  else
313  cout << "Output pixel type: " << GDALGetDataTypeName(theType) << endl;
314  }
315  //bounding box of cropped image
316  double cropulx=ulx_opt[0];
317  double cropuly=uly_opt[0];
318  double croplrx=lrx_opt[0];
319  double croplry=lry_opt[0];
320  //get bounding box from extentReader if defined
321  ImgReaderOgr extentReader;
322 
323  if(extent_opt.size()){
324  double e_ulx;
325  double e_uly;
326  double e_lrx;
327  double e_lry;
328  for(int iextent=0;iextent<extent_opt.size();++iextent){
329  extentReader.open(extent_opt[iextent]);
330  if(!(extentReader.getExtent(e_ulx,e_uly,e_lrx,e_lry))){
331  cerr << "Error: could not get extent from " << extent_opt[0] << endl;
332  exit(1);
333  }
334  if(!iextent){
335  ulx_opt[0]=e_ulx;
336  uly_opt[0]=e_uly;
337  lrx_opt[0]=e_lrx;
338  lry_opt[0]=e_lry;
339  }
340  else{
341  if(e_ulx<ulx_opt[0])
342  ulx_opt[0]=e_ulx;
343  if(e_uly>uly_opt[0])
344  uly_opt[0]=e_uly;
345  if(e_lrx>lrx_opt[0])
346  lrx_opt[0]=e_lrx;
347  if(e_lry<lry_opt[0])
348  lry_opt[0]=e_lry;
349  }
350  extentReader.close();
351  }
352  if(cut_opt.size())
353  extentReader.open(extent_opt[0]);
354  }
355  else if(cx_opt.size()&&cy_opt.size()&&nx_opt.size()&&ny_opt.size()){
356  ulx_opt[0]=cx_opt[0]-nx_opt[0]/2.0;
357  uly_opt[0]=(isGeoRef) ? cy_opt[0]+ny_opt[0]/2.0 : cy_opt[0]-ny_opt[0]/2.0;
358  lrx_opt[0]=cx_opt[0]+nx_opt[0]/2.0;
359  lry_opt[0]=(isGeoRef) ? cy_opt[0]-ny_opt[0]/2.0 : cy_opt[0]+ny_opt[0]/2.0;
360  // if(cropulx<ulx_opt[0])
361  // cropulx=ulx_opt[0];
362  // if(cropuly>uly_opt[0])
363  // cropuly=uly_opt[0];
364  // if(croplrx>lrx_opt[0])
365  // croplrx=lrx_opt[0];
366  // if(croplry<lry_opt[0])
367  // croplry=lry_opt[0];
368  }
369  else if(cx_opt.size()&&cy_opt.size()&&ns_opt.size()&&nl_opt.size()){
370  ulx_opt[0]=cx_opt[0]-ns_opt[0]*dx/2.0;
371  uly_opt[0]=(isGeoRef) ? cy_opt[0]+nl_opt[0]*dy/2.0 : cy_opt[0]-nl_opt[0]*dy/2.0;
372  lrx_opt[0]=cx_opt[0]+ns_opt[0]*dx/2.0;
373  lry_opt[0]=(isGeoRef) ? cy_opt[0]-nl_opt[0]*dy/2.0 : cy_opt[0]+nl_opt[0]*dy/2.0;
374  // if(cropulx<ulx_opt[0])
375  // cropulx=ulx_opt[0];
376  // if(cropuly>uly_opt[0])
377  // cropuly=uly_opt[0];
378  // if(croplrx>lrx_opt[0])
379  // croplrx=lrx_opt[0];
380  // if(croplry<lry_opt[0])
381  // croplry=lry_opt[0];
382  }
383 
384  if(verbose_opt[0])
385  cout << "--ulx=" << ulx_opt[0] << " --uly=" << uly_opt[0] << " --lrx=" << lrx_opt[0] << " --lry=" << lry_opt[0] << endl;
386 
387  int ncropcol=0;
388  int ncroprow=0;
389 
390  ImgWriterGdal maskWriter;
391  if(extent_opt.size()&&cut_opt[0]){
392  try{
393  ncropcol=abs(static_cast<int>(ceil((lrx_opt[0]-ulx_opt[0])/dx)));
394  ncroprow=abs(static_cast<int>(ceil((uly_opt[0]-lry_opt[0])/dy)));
395  maskWriter.open("/vsimem/mask.tif",ncropcol,ncroprow,1,GDT_Float32,"GTiff",option_opt);
396  double gt[6];
397  gt[0]=ulx_opt[0];
398  gt[1]=dx;
399  gt[2]=0;
400  gt[3]=uly_opt[0];
401  gt[4]=0;
402  gt[5]=-dy;
403  maskWriter.setGeoTransform(gt);
404  if(projection_opt.size())
405  maskWriter.setProjectionProj4(projection_opt[0]);
406  else if(projectionString.size())
407  maskWriter.setProjection(projectionString);
408 
409  //todo: handle multiple extent options
410  vector<double> burnValues(1,1);//burn value is 1 (single band)
411  maskWriter.rasterizeOgr(extentReader,burnValues);
412  maskWriter.close();
413  }
414  catch(string error){
415  cerr << error << std::endl;
416  exit(2);
417  }
418  catch(...){
419  cerr << "error catched" << std::endl;
420  exit(1);
421  }
422  //todo: support multiple masks
423  mask_opt.clear();
424  mask_opt.push_back("/vsimem/mask.tif");
425  }
426  ImgReaderGdal maskReader;
427  if(mask_opt.size()){
428  try{
429  if(verbose_opt[0]>=1)
430  std::cout << "opening mask image file " << mask_opt[0] << std::endl;
431  maskReader.open(mask_opt[0]);
432  if(mskband_opt[0]>=maskReader.nrOfBand()){
433  string errorString="Error: illegal mask band";
434  throw(errorString);
435  }
436  }
437  catch(string error){
438  cerr << error << std::endl;
439  exit(2);
440  }
441  catch(...){
442  cerr << "error catched" << std::endl;
443  exit(1);
444  }
445  }
446 
447  //determine number of output bands
448  int writeBand=0;//write band
449 
450  if(scale_opt.size()){
451  while(scale_opt.size()<band_opt.size())
452  scale_opt.push_back(scale_opt[0]);
453  }
454  if(offset_opt.size()){
455  while(offset_opt.size()<band_opt.size())
456  offset_opt.push_back(offset_opt[0]);
457  }
458  if(autoscale_opt.size()){
459  assert(autoscale_opt.size()%2==0);
460  // while(autoscale_opt.size()<band_opt.size()*2){
461  // autoscale_opt.push_back(autoscale_opt[0]);
462  // autoscale_opt.push_back(autoscale_opt[1]);
463  // }
464  }
465 
466  for(int iimg=0;iimg<input_opt.size();++iimg){
467  if(verbose_opt[0])
468  cout << "opening image " << input_opt[iimg] << endl;
469  imgReader.open(input_opt[iimg]);
470  //if output type not set, get type from input image
471  if(theType==GDT_Unknown){
472  theType=imgReader.getDataType();
473  if(verbose_opt[0])
474  cout << "Using data type from input image: " << GDALGetDataTypeName(theType) << endl;
475  }
476  if(option_opt.findSubstring("INTERLEAVE=")==option_opt.end()){
477  string theInterleave="INTERLEAVE=";
478  theInterleave+=imgReader.getInterleave();
479  option_opt.push_back(theInterleave);
480  }
481  int nrow=imgReader.nrOfRow();
482  int ncol=imgReader.nrOfCol();
483  // if(!dx||!dy){
484  // dx=imgReader.getDeltaX();
485  // dy=imgReader.getDeltaY();
486  // }
487  if(verbose_opt[0])
488  cout << "size of " << input_opt[iimg] << ": " << ncol << " cols, "<< nrow << " rows" << endl;
489  double uli,ulj,lri,lrj;//image coordinates
490  bool forceEUgrid=false;
491  if(projection_opt.size())
492  forceEUgrid=(!(projection_opt[0].compare("EPSG:3035"))||!(projection_opt[0].compare("EPSG:3035"))||projection_opt[0].find("ETRS-LAEA")!=string::npos);
493  if(ulx_opt[0]>=lrx_opt[0]){//default bounding box: no cropping
494  uli=0;
495  lri=imgReader.nrOfCol()-1;
496  ulj=0;
497  lrj=imgReader.nrOfRow()-1;
498  ncropcol=imgReader.nrOfCol();
499  ncroprow=imgReader.nrOfRow();
500  imgReader.getBoundingBox(cropulx,cropuly,croplrx,croplry);
501  double magicX=1,magicY=1;
502  // imgReader.getMagicPixel(magicX,magicY);
503  if(forceEUgrid){
504  //force to LAEA grid
505  Egcs egcs;
506  egcs.setLevel(egcs.res2level(dx));
507  egcs.force2grid(cropulx,cropuly,croplrx,croplry);
508  imgReader.geo2image(cropulx+(magicX-1.0)*imgReader.getDeltaX(),cropuly-(magicY-1.0)*imgReader.getDeltaY(),uli,ulj);
509  imgReader.geo2image(croplrx+(magicX-2.0)*imgReader.getDeltaX(),croplry-(magicY-2.0)*imgReader.getDeltaY(),lri,lrj);
510  }
511  imgReader.geo2image(cropulx+(magicX-1.0)*imgReader.getDeltaX(),cropuly-(magicY-1.0)*imgReader.getDeltaY(),uli,ulj);
512  imgReader.geo2image(croplrx+(magicX-2.0)*imgReader.getDeltaX(),croplry-(magicY-2.0)*imgReader.getDeltaY(),lri,lrj);
513  //test
514  ncropcol=abs(static_cast<int>(ceil((croplrx-cropulx)/dx)));
515  ncroprow=abs(static_cast<int>(ceil((cropuly-croplry)/dy)));
516  }
517  else{
518  double magicX=1,magicY=1;
519  // imgReader.getMagicPixel(magicX,magicY);
520  cropulx=ulx_opt[0];
521  cropuly=uly_opt[0];
522  croplrx=lrx_opt[0];
523  croplry=lry_opt[0];
524  if(forceEUgrid){
525  //force to LAEA grid
526  Egcs egcs;
527  egcs.setLevel(egcs.res2level(dx));
528  egcs.force2grid(cropulx,cropuly,croplrx,croplry);
529  imgReader.geo2image(cropulx+(magicX-1.0)*imgReader.getDeltaX(),cropuly-(magicY-1.0)*imgReader.getDeltaY(),uli,ulj);
530  imgReader.geo2image(croplrx+(magicX-2.0)*imgReader.getDeltaX(),croplry-(magicY-2.0)*imgReader.getDeltaY(),lri,lrj);
531  }
532  imgReader.geo2image(cropulx+(magicX-1.0)*imgReader.getDeltaX(),cropuly-(magicY-1.0)*imgReader.getDeltaY(),uli,ulj);
533  imgReader.geo2image(croplrx+(magicX-2.0)*imgReader.getDeltaX(),croplry-(magicY-2.0)*imgReader.getDeltaY(),lri,lrj);
534 
535  ncropcol=abs(static_cast<int>(ceil((croplrx-cropulx)/dx)));
536  ncroprow=abs(static_cast<int>(ceil((cropuly-croplry)/dy)));
537  uli=floor(uli);
538  ulj=floor(ulj);
539  lri=floor(lri);
540  lrj=floor(lrj);
541  }
542 
543  double dcropcol=0;
544  double dcroprow=0;
545  double deltaX=imgReader.getDeltaX();
546  double deltaY=imgReader.getDeltaY();
547  dcropcol=(lri-uli+1)/(dx/deltaX);
548  dcroprow=(lrj-ulj+1)/(dy/deltaY);
549  if(!imgWriter.nrOfBand()){//not opened yet
550  if(verbose_opt[0]){
551  cout << "cropulx: " << cropulx << endl;
552  cout << "cropuly: " << cropuly << endl;
553  cout << "croplrx: " << croplrx << endl;
554  cout << "croplry: " << croplry << endl;
555  cout << "ncropcol: " << ncropcol << endl;
556  cout << "ncroprow: " << ncroprow << endl;
557  cout << "cropulx+ncropcol*dx: " << cropulx+ncropcol*dx << endl;
558  cout << "cropuly-ncroprow*dy: " << cropuly-ncroprow*dy << endl;
559  cout << "upper left column of input image: " << uli << endl;
560  cout << "upper left row of input image: " << ulj << endl;
561  cout << "lower right column of input image: " << lri << endl;
562  cout << "lower right row of input image: " << lrj << endl;
563  cout << "new number of cols: " << ncropcol << endl;
564  cout << "new number of rows: " << ncroprow << endl;
565  cout << "new number of bands: " << ncropband << endl;
566  }
567  // string theCompression;
568  // if(compress_opt[0]!="")//default
569  // theCompression=compress_opt[0];
570  // else
571  // theCompression=imgReader.getCompression();
572  // string theInterleave;
573  // if(interleave_opt[0]!="")//default
574  // theInterleave=interleave_opt[0];
575  // else
576  // theInterleave=imgReader.getInterleave();
577  string imageType=imgReader.getImageType();
578  if(oformat_opt.size())//default
579  imageType=oformat_opt[0];
580  try{
581  imgWriter.open(output_opt[0],ncropcol,ncroprow,ncropband,theType,imageType,option_opt);
582  if(nodata_opt.size()){
583  for(int iband=0;iband<ncropband;++iband)
584  imgWriter.GDALSetNoDataValue(nodata_opt[0],iband);
585  }
586  }
587  catch(string errorstring){
588  cout << errorstring << endl;
589  exit(4);
590  }
591  if(description_opt.size())
592  imgWriter.setImageDescription(description_opt[0]);
593  double gt[6];
594  gt[0]=cropulx;
595  gt[1]=dx;
596  gt[2]=0;
597  gt[3]=cropuly;
598  gt[4]=0;
599  gt[5]=(imgReader.isGeoRef())? -dy : dy;
600  imgWriter.setGeoTransform(gt);
601  if(projection_opt.size()){
602  if(verbose_opt[0])
603  cout << "projection: " << projection_opt[0] << endl;
604  imgWriter.setProjectionProj4(projection_opt[0]);
605  }
606  else
607  imgWriter.setProjection(imgReader.getProjection());
608  if(imgWriter.getDataType()==GDT_Byte){
609  if(colorTable_opt.size()){
610  if(colorTable_opt[0]!="none")
611  imgWriter.setColorTable(colorTable_opt[0]);
612  }
613  else if (imgReader.getColorTable()!=NULL)//copy colorTable from input image
614  imgWriter.setColorTable(imgReader.getColorTable());
615  }
616  }
617 
618  double startCol=uli;
619  double endCol=lri;
620  if(uli<0)
621  startCol=0;
622  else if(uli>=imgReader.nrOfCol())
623  startCol=imgReader.nrOfCol()-1;
624  if(lri<0)
625  endCol=0;
626  else if(lri>=imgReader.nrOfCol())
627  endCol=imgReader.nrOfCol()-1;
628  double startRow=ulj;
629  double endRow=lrj;
630  if(ulj<0)
631  startRow=0;
632  else if(ulj>=imgReader.nrOfRow())
633  startRow=imgReader.nrOfRow()-1;
634  if(lrj<0)
635  endRow=0;
636  else if(lrj>=imgReader.nrOfRow())
637  endRow=imgReader.nrOfRow()-1;
638 
639 
640 
641  int readncol=endCol-startCol+1;
642  vector<double> readBuffer(readncol+1);
643  int nband=(band_opt.size())?band_opt.size() : imgReader.nrOfBand();
644  for(int iband=0;iband<nband;++iband){
645  int readBand=(band_opt.size()>iband)?band_opt[iband]:iband;
646  if(verbose_opt[0]){
647  cout << "extracting band " << readBand << endl;
648  pfnProgress(progress,pszMessage,pProgressArg);
649  }
650  double theMin=0;
651  double theMax=0;
652  if(autoscale_opt.size()){
653  try{
654  imgReader.getMinMax(static_cast<int>(startCol),static_cast<int>(endCol),static_cast<int>(startRow),static_cast<int>(endRow),readBand,theMin,theMax);
655  }
656  catch(string errorString){
657  cout << errorString << endl;
658  }
659  if(verbose_opt[0])
660  cout << "minmax: " << theMin << ", " << theMax << endl;
661  double theScale=(autoscale_opt[1]-autoscale_opt[0])/(theMax-theMin);
662  double theOffset=autoscale_opt[0]-theScale*theMin;
663  imgReader.setScale(theScale,readBand);
664  imgReader.setOffset(theOffset,readBand);
665  }
666  else{
667  if(scale_opt.size()){
668  if(scale_opt.size()>iband)
669  imgReader.setScale(scale_opt[iband],readBand);
670  else
671  imgReader.setScale(scale_opt[0],readBand);
672  }
673  if(offset_opt.size()){
674  if(offset_opt.size()>iband)
675  imgReader.setOffset(offset_opt[iband],readBand);
676  else
677  imgReader.setOffset(offset_opt[0],readBand);
678  }
679  }
680 
681  double readRow=0;
682  double readCol=0;
683  double lowerCol=0;
684  double upperCol=0;
685  for(int irow=0;irow<imgWriter.nrOfRow();++irow){
686  vector<float> lineMask;
687  double x=0;
688  double y=0;
689  //convert irow to geo
690  imgWriter.image2geo(0,irow,x,y);
691  //lookup corresponding row for irow in this file
692  imgReader.geo2image(x,y,readCol,readRow);
693  vector<double> writeBuffer;
694  if(readRow<0||readRow>=imgReader.nrOfRow()){
695  //if(readRow<0)
696  //readRow=0;
697  //else if(readRow>=imgReader.nrOfRow())
698  //readRow=imgReader.nrOfRow()-1;
699  for(int icol=0;icol<imgWriter.nrOfCol();++icol)
700  writeBuffer.push_back(nodataValue);
701  }
702  else{
703  if(verbose_opt[0]>1)
704  cout << "reading row: " << readRow << endl;
705  try{
706  if(endCol<imgReader.nrOfCol()-1)
707  imgReader.readData(readBuffer,GDT_Float64,startCol,endCol+1,readRow,readBand,theResample);
708  else
709  imgReader.readData(readBuffer,GDT_Float64,startCol,endCol,readRow,readBand,theResample);
710  // for(int icol=0;icol<ncropcol;++icol){
711  double oldRowMask=-1;//keep track of row mask to optimize number of line readings
712  for(int icol=0;icol<imgWriter.nrOfCol();++icol){
713  imgWriter.image2geo(icol,irow,x,y);
714  //lookup corresponding row for irow in this file
715  imgReader.geo2image(x,y,readCol,readRow);
716  if(readCol<0||readCol>=imgReader.nrOfCol()){
717  // if(readCol<0||readCol>=imgReader.nrOfCol()){
718  // if(readCol<0)
719  // readCol=0;
720  // else if(readCol>=imgReader.nrOfCol())
721  // readCol=imgReader.nrOfCol()-1;
722  writeBuffer.push_back(nodataValue);
723  }
724  else{
725  bool valid=true;
726  double geox=0;
727  double geoy=0;
728  if(mask_opt.size()){
729  //read mask
730  double colMask=0;
731  double rowMask=0;
732 
733  imgWriter.image2geo(icol,irow,geox,geoy);
734  maskReader.geo2image(geox,geoy,colMask,rowMask);
735  colMask=static_cast<int>(colMask);
736  rowMask=static_cast<int>(rowMask);
737  if(rowMask>=0&&rowMask<maskReader.nrOfRow()&&colMask>=0&&colMask<maskReader.nrOfCol()){
738  if(static_cast<int>(rowMask)!=static_cast<int>(oldRowMask)){
739 
740  assert(rowMask>=0&&rowMask<maskReader.nrOfRow());
741  try{
742  maskReader.readData(lineMask,GDT_Float32,static_cast<int>(rowMask),mskband_opt[0]);
743  }
744  catch(string errorstring){
745  cerr << errorstring << endl;
746  exit(1);
747  }
748  catch(...){
749  cerr << "error catched" << std::endl;
750  exit(3);
751  }
752  oldRowMask=rowMask;
753  }
754  if(lineMask[colMask]==msknodata_opt[0])
755  valid=false;
756  }
757  }
758 
759  if(!valid)
760  writeBuffer.push_back(nodataValue);
761  else{
762  switch(theResample){
763  case(BILINEAR):
764  lowerCol=readCol-0.5;
765  lowerCol=static_cast<int>(lowerCol);
766  upperCol=readCol+0.5;
767  upperCol=static_cast<int>(upperCol);
768  if(lowerCol<0)
769  lowerCol=0;
770  if(upperCol>=imgReader.nrOfCol())
771  upperCol=imgReader.nrOfCol()-1;
772  // writeBuffer.push_back((readCol-0.5-lowerCol)*(readBuffer[upperCol-startCol]*theScale+theOffset)+(1-readCol+0.5+lowerCol)*(readBuffer[lowerCol-startCol]*theScale+theOffset));
773  writeBuffer.push_back((readCol-0.5-lowerCol)*readBuffer[upperCol-startCol]+(1-readCol+0.5+lowerCol)*readBuffer[lowerCol-startCol]);
774  break;
775  default:
776  readCol=static_cast<int>(readCol);
777  readCol-=startCol;//we only start reading from startCol
778  // writeBuffer.push_back(readBuffer[readCol]*theScale+theOffset);
779  writeBuffer.push_back(readBuffer[readCol]);
780  break;
781  }
782  }
783  }
784  }
785  }
786  catch(string errorstring){
787  cout << errorstring << endl;
788  exit(2);
789  }
790  }
791  if(writeBuffer.size()!=imgWriter.nrOfCol())
792  cout << "writeBuffer.size()=" << writeBuffer.size() << ", imgWriter.nrOfCol()=" << imgWriter.nrOfCol() << endl;
793  assert(writeBuffer.size()==imgWriter.nrOfCol());
794  try{
795  imgWriter.writeData(writeBuffer,GDT_Float64,irow,writeBand);
796  }
797  catch(string errorstring){
798  cout << errorstring << endl;
799  exit(3);
800  }
801  if(verbose_opt[0]){
802  progress=(1.0+irow);
803  progress/=imgWriter.nrOfRow();
804  pfnProgress(progress,pszMessage,pProgressArg);
805  }
806  else{
807  progress=(1.0+irow);
808  progress+=(imgWriter.nrOfRow()*writeBand);
809  progress/=imgWriter.nrOfBand()*imgWriter.nrOfRow();
810  assert(progress>=0);
811  assert(progress<=1);
812  pfnProgress(progress,pszMessage,pProgressArg);
813  }
814  }
815  ++writeBand;
816  }
817  imgReader.close();
818  }
819  if(extent_opt.size()&&cut_opt.size()){
820  extentReader.close();
821  }
822  if(mask_opt.size())
823  maskReader.close();
824  imgWriter.close();
825 }
STL namespace.
Definition: Egcs.h:26