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"
34 int main(
int argc,
char *argv[])
36 Optionpk<string> input_opt(
"i",
"input",
"Input image file(s). If input contains multiple images, a multi-band output is created");
38 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");
39 Optionpk<string> extent_opt(
"e",
"extent",
"get boundary from extent from polygons in vector file");
40 Optionpk<bool> mask_opt(
"m",
"mask",
"mask values out of polygon in extent file to flag option (tip: for better performance, use gdal_rasterize -i -burn 0 -l extent extent.shp output (with output the result of pkcrop)",
false);
41 Optionpk<double> ulx_opt(
"ulx",
"ulx",
"Upper left x value bounding box", 0.0);
42 Optionpk<double> uly_opt(
"uly",
"uly",
"Upper left y value bounding box", 0.0);
43 Optionpk<double> lrx_opt(
"lrx",
"lrx",
"Lower right x value bounding box", 0.0);
44 Optionpk<double> lry_opt(
"lry",
"lry",
"Lower right y value bounding box", 0.0);
45 Optionpk<double> dx_opt(
"dx",
"dx",
"Output resolution in x (in meter) (empty: keep original resolution)");
46 Optionpk<double> dy_opt(
"dy",
"dy",
"Output resolution in y (in meter) (empty: keep original resolution)");
47 Optionpk<double> cx_opt(
"x",
"x",
"x-coordinate of image center to crop (in meter)");
48 Optionpk<double> cy_opt(
"y",
"y",
"y-coordinate of image center to crop (in meter)");
51 Optionpk<int> ns_opt(
"ns",
"ns",
"number of samples to crop (in pixels)");
52 Optionpk<int> nl_opt(
"nl",
"nl",
"number of lines to crop (in pixels)");
53 Optionpk<int> band_opt(
"b",
"band",
"band index to crop (leave empty to retain all bands)");
54 Optionpk<double> autoscale_opt(
"as",
"autoscale",
"scale output to min and max, e.g., --autoscale 0 --autoscale 255");
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> colorTable_opt(
"ct",
"ct",
"color table (file with 5 columns: id R G B ALFA (0: transparent, 255: solid)");
61 Optionpk<double> nodata_opt(
"nodata",
"nodata",
"Nodata value to put in image if out of bounds.");
62 Optionpk<string> resample_opt(
"r",
"resampling-method",
"Resampling method (near: nearest neighbor, bilinear: bi-linear interpolation).",
"near");
63 Optionpk<string> description_opt(
"d",
"description",
"Set image description");
66 extent_opt.setHide(1);
68 option_opt.setHide(1);
76 offset_opt.setHide(1);
77 nodata_opt.setHide(1);
78 description_opt.setHide(1);
82 doProcess=input_opt.retrieveOption(argc,argv);
83 output_opt.retrieveOption(argc,argv);
84 projection_opt.retrieveOption(argc,argv);
85 ulx_opt.retrieveOption(argc,argv);
86 uly_opt.retrieveOption(argc,argv);
87 lrx_opt.retrieveOption(argc,argv);
88 lry_opt.retrieveOption(argc,argv);
89 band_opt.retrieveOption(argc,argv);
90 autoscale_opt.retrieveOption(argc,argv);
91 otype_opt.retrieveOption(argc,argv);
92 oformat_opt.retrieveOption(argc,argv);
93 colorTable_opt.retrieveOption(argc,argv);
94 dx_opt.retrieveOption(argc,argv);
95 dy_opt.retrieveOption(argc,argv);
96 resample_opt.retrieveOption(argc,argv);
97 extent_opt.retrieveOption(argc,argv);
98 mask_opt.retrieveOption(argc,argv);
99 option_opt.retrieveOption(argc,argv);
100 cx_opt.retrieveOption(argc,argv);
101 cy_opt.retrieveOption(argc,argv);
102 nx_opt.retrieveOption(argc,argv);
103 ny_opt.retrieveOption(argc,argv);
104 ns_opt.retrieveOption(argc,argv);
105 nl_opt.retrieveOption(argc,argv);
106 scale_opt.retrieveOption(argc,argv);
107 offset_opt.retrieveOption(argc,argv);
108 nodata_opt.retrieveOption(argc,argv);
109 description_opt.retrieveOption(argc,argv);
110 verbose_opt.retrieveOption(argc,argv);
112 catch(
string predefinedString){
113 std::cout << predefinedString << std::endl;
118 cout << setprecision(12) <<
"--ulx=" << ulx_opt[0] <<
" --uly=" << uly_opt[0] <<
" --lrx=" << lrx_opt[0] <<
" --lry=" << lry_opt[0] << endl;
122 cout <<
"Usage: pkcrop -i input -o output" << endl;
124 std::cout <<
"short option -h shows basic options only, use long option --help to show all options" << std::endl;
127 if(input_opt.empty()){
128 std::cerr <<
"No input file provided (use option -i). Use --help for help information" << std::endl;
131 if(output_opt.empty()){
132 std::cerr <<
"No output file provided (use option -o). Use --help for help information" << std::endl;
136 double nodataValue=nodata_opt.size()? nodata_opt[0] : 0;
137 RESAMPLE theResample;
138 if(resample_opt[0]==
"near"){
141 cout <<
"resampling: nearest neighbor" << endl;
143 else if(resample_opt[0]==
"bilinear"){
144 theResample=BILINEAR;
146 cout <<
"resampling: bilinear interpolation" << endl;
149 std::cout <<
"Error: resampling method " << resample_opt[0] <<
" not supported" << std::endl;
153 const char* pszMessage;
154 void* pProgressArg=NULL;
155 GDALProgressFunc pfnProgress=GDALTermProgress;
157 pfnProgress(progress,pszMessage,pProgressArg);
170 for(
int iimg=0;iimg<input_opt.size();++iimg){
171 imgReader.open(input_opt[iimg]);
173 isGeoRef=imgReader.isGeoRef();
175 if(!iimg||imgReader.getDeltaX()<dx)
176 dx=imgReader.getDeltaX();
179 if(!iimg||imgReader.getDeltaY()<dy)
180 dy=imgReader.getDeltaY();
183 ncropband+=band_opt.size();
185 ncropband+=imgReader.nrOfBand();
189 GDALDataType theType=GDT_Unknown;
191 cout <<
"possible output data types: ";
192 for(
int iType = 0; iType < GDT_TypeCount; ++iType){
194 cout <<
" " << GDALGetDataTypeName((GDALDataType)iType);
195 if( GDALGetDataTypeName((GDALDataType)iType) != NULL
196 && EQUAL(GDALGetDataTypeName((GDALDataType)iType),
197 otype_opt[0].c_str()))
198 theType=(GDALDataType) iType;
202 if(theType==GDT_Unknown)
203 cout <<
"Unknown output pixel type: " << otype_opt[0] << endl;
205 cout <<
"Output pixel type: " << GDALGetDataTypeName(theType) << endl;
208 double cropulx=ulx_opt[0];
209 double cropuly=uly_opt[0];
210 double croplrx=lrx_opt[0];
211 double croplry=lry_opt[0];
216 cout <<
"--ulx=" << ulx_opt[0] <<
" --uly=" << uly_opt[0] <<
" --lrx=" << lrx_opt[0] <<
" --lry=" << lry_opt[0] << endl;
218 if(extent_opt.size()){
219 for(
int iextent=0;iextent<extent_opt.size();++iextent){
220 extentReader.open(extent_opt[iextent]);
221 if(!(extentReader.getExtent(ulx_opt[0],uly_opt[0],lrx_opt[0],lry_opt[0]))){
222 cerr <<
"Error: could not get extent from " << extent_opt[0] << endl;
225 extentReader.close();
228 extentReader.open(extent_opt[0]);
230 else if(cx_opt.size()&&cy_opt.size()&&nx_opt.size()&&ny_opt.size()){
231 ulx_opt[0]=cx_opt[0]-nx_opt[0]/2.0;
232 uly_opt[0]=(isGeoRef) ? cy_opt[0]+ny_opt[0]/2.0 : cy_opt[0]-ny_opt[0]/2.0;
233 lrx_opt[0]=cx_opt[0]+nx_opt[0]/2.0;
234 lry_opt[0]=(isGeoRef) ? cy_opt[0]-ny_opt[0]/2.0 : cy_opt[0]+ny_opt[0]/2.0;
236 else if(cx_opt.size()&&cy_opt.size()&&ns_opt.size()&&nl_opt.size()){
237 ulx_opt[0]=cx_opt[0]-ns_opt[0]*dx/2.0;
238 uly_opt[0]=(isGeoRef) ? cy_opt[0]+nl_opt[0]*dy/2.0 : cy_opt[0]-nl_opt[0]*dy/2.0;
239 lrx_opt[0]=cx_opt[0]+ns_opt[0]*dx/2.0;
240 lry_opt[0]=(isGeoRef) ? cy_opt[0]-nl_opt[0]*dy/2.0 : cy_opt[0]+nl_opt[0]*dy/2.0;
244 cout <<
"--ulx=" << ulx_opt[0] <<
" --uly=" << uly_opt[0] <<
" --lrx=" << lrx_opt[0] <<
" --lry=" << lry_opt[0] << endl;
245 if(ulx_opt[0]<cropulx)
247 if(uly_opt[0]>cropuly)
249 if(lry_opt[0]<croplry)
251 if(lrx_opt[0]>croplrx)
254 cout <<
"--ulx=" << ulx_opt[0] <<
" --uly=" << uly_opt[0] <<
" --lrx=" << lrx_opt[0] <<
" --lry=" << lry_opt[0] << endl;
258 if(scale_opt.size()){
259 while(scale_opt.size()<band_opt.size())
260 scale_opt.push_back(scale_opt[0]);
262 if(offset_opt.size()){
263 while(offset_opt.size()<band_opt.size())
264 offset_opt.push_back(offset_opt[0]);
266 if(autoscale_opt.size()){
267 assert(autoscale_opt.size()%2==0);
274 for(
int iimg=0;iimg<input_opt.size();++iimg){
276 cout <<
"opening image " << input_opt[iimg] << endl;
277 imgReader.open(input_opt[iimg]);
279 if(theType==GDT_Unknown){
280 theType=imgReader.getDataType();
282 cout <<
"Using data type from input image: " << GDALGetDataTypeName(theType) << endl;
284 if(option_opt.findSubstring(
"INTERLEAVE=")==option_opt.end()){
285 string theInterleave=
"INTERLEAVE=";
286 theInterleave+=imgReader.getInterleave();
287 option_opt.push_back(theInterleave);
289 int nrow=imgReader.nrOfRow();
290 int ncol=imgReader.nrOfCol();
298 cout <<
"size of " << input_opt[iimg] <<
": " << ncol <<
" cols, "<< nrow <<
" rows" << endl;
299 double uli,ulj,lri,lrj;
300 bool forceEUgrid=
false;
301 if(projection_opt.size())
302 forceEUgrid=(!(projection_opt[0].compare(
"EPSG:3035"))||!(projection_opt[0].compare(
"EPSG:3035"))||projection_opt[0].find(
"ETRS-LAEA")!=string::npos);
303 if(ulx_opt[0]>=lrx_opt[0]){
305 lri=imgReader.nrOfCol()-1;
307 lrj=imgReader.nrOfRow()-1;
308 ncropcol=imgReader.nrOfCol();
309 ncroprow=imgReader.nrOfRow();
310 imgReader.getBoundingBox(cropulx,cropuly,croplrx,croplry);
311 double magicX=1,magicY=1;
316 egcs.setLevel(egcs.res2level(dx));
317 egcs.force2grid(cropulx,cropuly,croplrx,croplry);
318 imgReader.geo2image(cropulx+(magicX-1.0)*imgReader.getDeltaX(),cropuly-(magicY-1.0)*imgReader.getDeltaY(),uli,ulj);
319 imgReader.geo2image(croplrx+(magicX-2.0)*imgReader.getDeltaX(),croplry-(magicY-2.0)*imgReader.getDeltaY(),lri,lrj);
321 imgReader.geo2image(cropulx+(magicX-1.0)*imgReader.getDeltaX(),cropuly-(magicY-1.0)*imgReader.getDeltaY(),uli,ulj);
322 imgReader.geo2image(croplrx+(magicX-2.0)*imgReader.getDeltaX(),croplry-(magicY-2.0)*imgReader.getDeltaY(),lri,lrj);
324 ncropcol=abs(static_cast<int>(ceil((croplrx-cropulx)/dx)));
325 ncroprow=abs(static_cast<int>(ceil((cropuly-croplry)/dy)));
328 double magicX=1,magicY=1;
337 egcs.setLevel(egcs.res2level(dx));
338 egcs.force2grid(cropulx,cropuly,croplrx,croplry);
339 imgReader.geo2image(cropulx+(magicX-1.0)*imgReader.getDeltaX(),cropuly-(magicY-1.0)*imgReader.getDeltaY(),uli,ulj);
340 imgReader.geo2image(croplrx+(magicX-2.0)*imgReader.getDeltaX(),croplry-(magicY-2.0)*imgReader.getDeltaY(),lri,lrj);
342 imgReader.geo2image(cropulx+(magicX-1.0)*imgReader.getDeltaX(),cropuly-(magicY-1.0)*imgReader.getDeltaY(),uli,ulj);
343 imgReader.geo2image(croplrx+(magicX-2.0)*imgReader.getDeltaX(),croplry-(magicY-2.0)*imgReader.getDeltaY(),lri,lrj);
345 ncropcol=abs(static_cast<int>(ceil((croplrx-cropulx)/dx)));
346 ncroprow=abs(static_cast<int>(ceil((cropuly-croplry)/dy)));
355 double deltaX=imgReader.getDeltaX();
356 double deltaY=imgReader.getDeltaY();
357 dcropcol=(lri-uli+1)/(dx/deltaX);
358 dcroprow=(lrj-ulj+1)/(dy/deltaY);
359 if(!imgWriter.nrOfBand()){
361 cout <<
"cropulx: " << cropulx << endl;
362 cout <<
"cropuly: " << cropuly << endl;
363 cout <<
"croplrx: " << croplrx << endl;
364 cout <<
"croplry: " << croplry << endl;
365 cout <<
"ncropcol: " << ncropcol << endl;
366 cout <<
"ncroprow: " << ncroprow << endl;
367 cout <<
"cropulx+ncropcol*dx: " << cropulx+ncropcol*dx << endl;
368 cout <<
"cropuly-ncroprow*dy: " << cropuly-ncroprow*dy << endl;
369 cout <<
"upper left column of input image: " << uli << endl;
370 cout <<
"upper left row of input image: " << ulj << endl;
371 cout <<
"lower right column of input image: " << lri << endl;
372 cout <<
"lower right row of input image: " << lrj << endl;
373 cout <<
"new number of cols: " << ncropcol << endl;
374 cout <<
"new number of rows: " << ncroprow << endl;
375 cout <<
"new number of bands: " << ncropband << endl;
387 string imageType=imgReader.getImageType();
388 if(oformat_opt.size())
389 imageType=oformat_opt[0];
391 imgWriter.open(output_opt[0],ncropcol,ncroprow,ncropband,theType,imageType,option_opt);
392 if(nodata_opt.size()){
393 for(
int iband=0;iband<ncropband;++iband)
394 imgWriter.GDALSetNoDataValue(nodata_opt[0],iband);
397 catch(
string errorstring){
398 cout << errorstring << endl;
401 if(description_opt.size())
402 imgWriter.setImageDescription(description_opt[0]);
409 gt[5]=(imgReader.isGeoRef())? -dy : dy;
410 imgWriter.setGeoTransform(gt);
411 if(projection_opt.size()){
413 cout <<
"projection: " << projection_opt[0] << endl;
414 imgWriter.setProjectionProj4(projection_opt[0]);
417 imgWriter.setProjection(imgReader.getProjection());
418 if(imgWriter.getDataType()==GDT_Byte){
419 if(colorTable_opt.size()){
420 if(colorTable_opt[0]!=
"none")
421 imgWriter.setColorTable(colorTable_opt[0]);
423 else if (imgReader.getColorTable()!=NULL)
424 imgWriter.setColorTable(imgReader.getColorTable());
431 else if(uli>=imgReader.nrOfCol())
432 startCol=imgReader.nrOfCol()-1;
435 else if(lri>=imgReader.nrOfCol())
436 endCol=imgReader.nrOfCol()-1;
441 else if(ulj>=imgReader.nrOfRow())
442 startRow=imgReader.nrOfRow()-1;
445 else if(lrj>=imgReader.nrOfRow())
446 endRow=imgReader.nrOfRow()-1;
448 int readncol=endCol-startCol+1;
449 vector<double> readBuffer(readncol+1);
450 int nband=(band_opt.size())?band_opt.size() : imgReader.nrOfBand();
451 for(
int iband=0;iband<nband;++iband){
452 int readBand=(band_opt.size()>iband)?band_opt[iband]:iband;
454 cout <<
"extracting band " << readBand << endl;
455 pfnProgress(progress,pszMessage,pProgressArg);
459 if(autoscale_opt.size()){
461 imgReader.getMinMax(static_cast<int>(startCol),static_cast<int>(endCol),static_cast<int>(startRow),static_cast<int>(endRow),readBand,theMin,theMax);
463 catch(
string errorString){
464 cout << errorString << endl;
467 cout <<
"minmax: " << theMin <<
", " << theMax << endl;
468 double theScale=(autoscale_opt[1]-autoscale_opt[0])/(theMax-theMin);
469 double theOffset=autoscale_opt[0]-theScale*theMin;
470 imgReader.setScale(theScale,readBand);
471 imgReader.setOffset(theOffset,readBand);
474 if(scale_opt.size()){
475 if(scale_opt.size()>iband)
476 imgReader.setScale(scale_opt[iband],readBand);
478 imgReader.setScale(scale_opt[0],readBand);
480 if(offset_opt.size()){
481 if(offset_opt.size()>iband)
482 imgReader.setOffset(offset_opt[iband],readBand);
484 imgReader.setOffset(offset_opt[0],readBand);
492 for(
int irow=0;irow<imgWriter.nrOfRow();++irow){
496 imgWriter.image2geo(0,irow,x,y);
500 imgReader.geo2image(x,y,readCol,readRow);
505 vector<double> writeBuffer;
506 if(readRow<0||readRow>=imgReader.nrOfRow()){
511 for(
int ib=0;ib<imgWriter.nrOfCol();++ib)
512 writeBuffer.push_back(nodataValue);
516 cout <<
"reading row: " << readRow << endl;
518 if(endCol<imgReader.nrOfCol()-1)
519 imgReader.readData(readBuffer,GDT_Float64,startCol,endCol+1,readRow,readBand,theResample);
521 imgReader.readData(readBuffer,GDT_Float64,startCol,endCol,readRow,readBand,theResample);
523 for(
int ib=0;ib<imgWriter.nrOfCol();++ib){
524 imgWriter.image2geo(ib,irow,x,y);
526 imgReader.geo2image(x,y,readCol,readRow);
527 if(readCol<0||readCol>=imgReader.nrOfCol()){
533 writeBuffer.push_back(nodataValue);
537 if(mask_opt[0]&&extent_opt.size()){
543 readLayer = extentReader.getDataSource()->GetLayer(0);
544 readLayer->ResetReading();
545 OGRFeature *readFeature;
546 while( (readFeature = readLayer->GetNextFeature()) != NULL ){
547 OGRGeometry *poGeometry;
548 poGeometry = readFeature->GetGeometryRef();
549 assert(poGeometry!=NULL);
551 OGRPolygon readPolygon = *((OGRPolygon *) poGeometry);
552 readPolygon.closeRings();
553 if(readPolygon.Contains(&thePoint)){
562 writeBuffer.push_back(nodataValue);
576 lowerCol=readCol-0.5;
577 lowerCol=
static_cast<int>(lowerCol);
578 upperCol=readCol+0.5;
579 upperCol=
static_cast<int>(upperCol);
582 if(upperCol>=imgReader.nrOfCol())
583 upperCol=imgReader.nrOfCol()-1;
585 writeBuffer.push_back((readCol-0.5-lowerCol)*readBuffer[upperCol-startCol]+(1-readCol+0.5+lowerCol)*readBuffer[lowerCol-startCol]);
588 readCol=
static_cast<int>(readCol);
591 writeBuffer.push_back(readBuffer[readCol]);
598 catch(
string errorstring){
599 cout << errorstring << endl;
603 if(writeBuffer.size()!=imgWriter.nrOfCol())
604 cout <<
"writeBuffer.size()=" << writeBuffer.size() <<
", imgWriter.nrOfCol()=" << imgWriter.nrOfCol() << endl;
605 assert(writeBuffer.size()==imgWriter.nrOfCol());
607 imgWriter.writeData(writeBuffer,GDT_Float64,irow,writeBand);
609 catch(
string errorstring){
610 cout << errorstring << endl;
615 progress/=imgWriter.nrOfRow();
616 pfnProgress(progress,pszMessage,pProgressArg);
620 progress+=(imgWriter.nrOfRow()*writeBand);
621 progress/=imgWriter.nrOfBand()*imgWriter.nrOfRow();
624 pfnProgress(progress,pszMessage,pProgressArg);
631 if(extent_opt.size()&&mask_opt[0]){
632 extentReader.close();