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