pktools  2.6.4
Processing Kernel for geospatial data
pksetmask.cc
1 /**********************************************************************
2 pksetmask.cc: program to apply mask image (set invalid values) to raster image
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 
22 #include "imageclasses/ImgReaderGdal.h"
23 #include "imageclasses/ImgWriterGdal.h"
24 #include "base/Optionpk.h"
25 /******************************************************************************/
72 using namespace std;
73 
74 int main(int argc, char *argv[])
75 {
76  //command line options
77  Optionpk<string> input_opt("i", "input", "Input image");
78  Optionpk<string> mask_opt("m", "mask", "Mask image(s)");
79  Optionpk<string> output_opt("o", "output", "Output mask file");
80  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", "");
81  Optionpk<string> oformat_opt("of", "oformat", "Output image format (see also gdal_translate). Empty string: inherit from input image");
82  Optionpk<string> option_opt("co", "co", "Creation option for output file. Multiple options can be specified.");
83  Optionpk<int> msknodata_opt("msknodata", "msknodata", "Mask value(s) where image has nodata. Use one value for each mask, or multiple values for a single mask.", 1);
84  Optionpk<short> mskband_opt("mskband", "mskband", "Mask band to read (0 indexed). Provide band for each mask.", 0);
85  Optionpk<char> operator_opt("p", "operator", "Operator: < = > !. Use operator for each msknodata option", '=');
86  Optionpk<int> nodata_opt("nodata", "nodata", "nodata value to put in image if not valid", 0);
87  Optionpk<string> colorTable_opt("ct", "ct", "color table (file with 5 columns: id R G B ALFA (0: transparent, 255: solid)");
88  Optionpk<short> verbose_opt("v", "verbose", "verbose", 0,2);
89 
90  otype_opt.setHide(1);
91  oformat_opt.setHide(1);
92  option_opt.setHide(1);
93  colorTable_opt.setHide(1);
94  mskband_opt.setHide(1);
95 
96  bool doProcess;//stop process when program was invoked with help option (-h --help)
97  try{
98  doProcess=input_opt.retrieveOption(argc,argv);
99  mask_opt.retrieveOption(argc,argv);
100  msknodata_opt.retrieveOption(argc,argv);
101  mskband_opt.retrieveOption(argc,argv);
102  output_opt.retrieveOption(argc,argv);
103  nodata_opt.retrieveOption(argc,argv);
104  operator_opt.retrieveOption(argc,argv);
105  otype_opt.retrieveOption(argc,argv);
106  oformat_opt.retrieveOption(argc,argv);
107  option_opt.retrieveOption(argc,argv);
108  colorTable_opt.retrieveOption(argc,argv);
109  verbose_opt.retrieveOption(argc,argv);
110  }
111  catch(string predefinedString){
112  std::cout << predefinedString << std::endl;
113  exit(0);
114  }
115  if(!doProcess){
116  cout << endl;
117  cout << "Usage: pksetmask -i input -m mask [-msknodata value] -o output" << endl;
118  cout << endl;
119  std::cout << "short option -h shows basic options only, use long option --help to show all options" << std::endl;
120  exit(0);//help was invoked, stop processing
121  }
122 
123  if(verbose_opt[0])
124  cout << "number of mask images: " << mask_opt.size() << endl;
125 
126  //duplicate band used for mask if not explicitly provided
127  while(mskband_opt.size()<mask_opt.size())
128  mskband_opt.push_back(mskband_opt[0]);
129 
130  vector<ImgReaderGdal> maskReader(mask_opt.size());
131  for(int imask=0;imask<mask_opt.size();++imask){
132  if(verbose_opt[0])
133  cout << "opening mask image file " << mask_opt[imask] << endl;
134  maskReader[imask].open(mask_opt[imask]);
135  }
136  assert(input_opt.size());
137  if(verbose_opt[0])
138  cout << "opening input image file " << input_opt[0] << endl;
139  ImgReaderGdal inputReader;
140  inputReader.open(input_opt[0]);
141  string imageType=inputReader.getImageType();
142  if(oformat_opt.size())//default
143  imageType=oformat_opt[0];
144  GDALDataType theType=GDT_Unknown;
145  if(verbose_opt[0]){
146  std::cout << "Image type: " << imageType << std::endl;
147  std::cout << "possible output data types: ";
148  }
149  for(int iType = 0; iType < GDT_TypeCount; ++iType){
150  if(verbose_opt[0])
151  cout << " " << GDALGetDataTypeName((GDALDataType)iType);
152  if( GDALGetDataTypeName((GDALDataType)iType) != NULL
153  && EQUAL(GDALGetDataTypeName((GDALDataType)iType),
154  otype_opt[0].c_str()))
155  theType=(GDALDataType) iType;
156  }
157  if(theType==GDT_Unknown)
158  theType=inputReader.getDataType();
159 
160  assert(output_opt.size());
161  if(verbose_opt[0]){
162  std::cout << std::endl << "Output data type: " << GDALGetDataTypeName(theType) << std::endl;
163  std::cout << "opening output image for writing: " << output_opt[0] << std::endl;
164  }
165  ImgWriterGdal outputWriter;
166  try{
167  if(option_opt.findSubstring("INTERLEAVE=")==option_opt.end()){
168  string theInterleave="INTERLEAVE=";
169  theInterleave+=inputReader.getInterleave();
170  option_opt.push_back(theInterleave);
171  }
172  outputWriter.open(output_opt[0],inputReader.nrOfCol(),inputReader.nrOfRow(),inputReader.nrOfBand(),theType,imageType,option_opt);
173  for(int iband=0;iband<inputReader.nrOfBand();++iband)
174  outputWriter.GDALSetNoDataValue(nodata_opt[0],iband);
175  outputWriter.setProjection(inputReader.getProjection());
176  outputWriter.copyGeoTransform(inputReader);
177  }
178  catch(string errorstring){
179  cout << errorstring << endl;
180  exit(1);
181  }
182  // if(verbose_opt[0])
183  // cout << "opening output image file " << output_opt[0] << endl;
184  // outputWriter.open(output_opt[0],inputReader);
185  if(colorTable_opt.size()){
186  if(colorTable_opt[0]!="none")
187  outputWriter.setColorTable(colorTable_opt[0]);
188  }
189  else if (inputReader.getColorTable()!=NULL)//copy colorTable from input image
190  outputWriter.setColorTable(inputReader.getColorTable());
191  if(inputReader.isGeoRef()){
192  for(int imask=0;imask<mask_opt.size();++imask)
193  assert(maskReader[imask].isGeoRef());
194  }
195  assert(nodata_opt.size()==msknodata_opt.size());
196  assert(operator_opt.size()==msknodata_opt.size()||operator_opt.size()==1);
197  if(verbose_opt[0]){
198  cout << " mask files selected: " << mask_opt.size() << endl;
199  for(int iv=0;iv<msknodata_opt.size();++iv){
200  char op=(operator_opt.size()==msknodata_opt.size())?operator_opt[iv]:operator_opt[0];
201  cout << op << " " << msknodata_opt[iv] << "->" << nodata_opt[iv] << endl;
202  }
203  }
204 
205  Vector2d<double> lineInput(inputReader.nrOfBand(),inputReader.nrOfCol());
206  Vector2d<double> lineOutput(outputWriter.nrOfBand(),outputWriter.nrOfCol());
207  assert(lineOutput.size()==lineInput.size());
208  assert(inputReader.nrOfCol()==outputWriter.nrOfCol());
209  // Vector2d<int> lineMask(mask_opt.size());
210  Vector2d<double> lineMask(mask_opt.size());
211  for(int imask=0;imask<mask_opt.size();++imask){
212  if(verbose_opt[0])
213  cout << "mask " << imask << " has " << maskReader[imask].nrOfCol() << " columns and " << maskReader[imask].nrOfRow() << " rows" << endl;
214  lineMask[imask].resize(maskReader[imask].nrOfCol());
215  }
216  int irow=0;
217  int icol=0;
218  const char* pszMessage;
219  void* pProgressArg=NULL;
220  GDALProgressFunc pfnProgress=GDALTermProgress;
221  float progress=0;
222  if(!verbose_opt[0])
223  pfnProgress(progress,pszMessage,pProgressArg);
224  // double oldRowMask=-1;
225  vector<double> oldRowMask(mask_opt.size());
226  for(int imask=0;imask<mask_opt.size();++imask)
227  oldRowMask[imask]=-1;
228  for(irow=0;irow<inputReader.nrOfRow();++irow){
229  //read line in lineInput buffer
230  for(int iband=0;iband<inputReader.nrOfBand();++iband){
231  try{
232  inputReader.readData(lineInput[iband],GDT_Float64,irow,iband);
233  }
234  catch(string errorstring){
235  cerr << errorstring << endl;
236  exit(1);
237  }
238  }
239  double x,y;//geo coordinates
240  double colMask,rowMask;//image coordinates in mask image
241  for(icol=0;icol<inputReader.nrOfCol();++icol){
242  if(mask_opt.size()>1){//multiple masks
243  for(int imask=0;imask<mask_opt.size();++imask){
244  inputReader.image2geo(icol,irow,x,y);
245  maskReader[imask].geo2image(x,y,colMask,rowMask);
246  colMask=static_cast<int>(colMask);
247  rowMask=static_cast<int>(rowMask);
248  bool masked=false;
249  if(rowMask>=0&&rowMask<maskReader[imask].nrOfRow()&&colMask>=0&&colMask<maskReader[imask].nrOfCol()){
250  if(static_cast<int>(rowMask)!=static_cast<int>(oldRowMask[imask])){
251  assert(rowMask>=0&&rowMask<maskReader[imask].nrOfRow());
252  try{
253  // maskReader[imask].readData(lineMask[imask],GDT_Int32,static_cast<int>(rowMask));
254  maskReader[imask].readData(lineMask[imask],GDT_Float64,static_cast<int>(rowMask),mskband_opt[imask]);
255  }
256  catch(string errorstring){
257  cerr << errorstring << endl;
258  exit(1);
259  }
260  oldRowMask[imask]=rowMask;
261  }
262  }
263  else
264  continue;//no coverage in this mask
265  int ivalue=0;
266  if(mask_opt.size()==msknodata_opt.size())//one invalid value for each mask
267  ivalue=msknodata_opt[imask];
268  else//use same invalid value for each mask
269  ivalue=msknodata_opt[0];
270  char op=(operator_opt.size()==mask_opt.size())?operator_opt[imask]:operator_opt[0];
271  switch(op){
272  case('='):
273  default:
274  if(lineMask[imask][colMask]==ivalue)
275  masked=true;
276  break;
277  case('<'):
278  if(lineMask[imask][colMask]<ivalue)
279  masked=true;
280  break;
281  case('>'):
282  if(lineMask[imask][colMask]>ivalue)
283  masked=true;
284  break;
285  case('!'):
286  if(lineMask[imask][colMask]!=ivalue)
287  masked=true;
288  break;
289  }
290  if(masked){
291  if(verbose_opt[0]>1)
292  cout << "image masked at (col=" << icol << ",row=" << irow <<") with mask " << mask_opt[imask] << " and value " << ivalue << endl;
293  for(int iband=0;iband<inputReader.nrOfBand();++iband){
294  if(mask_opt.size()==nodata_opt.size())//one flag value for each mask
295  lineInput[iband][icol]=nodata_opt[imask];
296  else
297  lineInput[iband][icol]=nodata_opt[0];
298  }
299  masked=false;
300  break;
301  }
302  }
303  }
304  else{//potentially more invalid values for single mask
305  inputReader.image2geo(icol,irow,x,y);
306  maskReader[0].geo2image(x,y,colMask,rowMask);
307  colMask=static_cast<int>(colMask);
308  rowMask=static_cast<int>(rowMask);
309  bool masked=false;
310  if(rowMask>=0&&rowMask<maskReader[0].nrOfRow()&&colMask>=0&&colMask<maskReader[0].nrOfCol()){
311  if(static_cast<int>(rowMask)!=static_cast<int>(oldRowMask[0])){
312  assert(rowMask>=0&&rowMask<maskReader[0].nrOfRow());
313  try{
314  // maskReader[0].readData(lineMask[0],GDT_Int32,static_cast<int>(rowMask));
315  maskReader[0].readData(lineMask[0],GDT_Float64,static_cast<int>(rowMask),mskband_opt[0]);
316  }
317  catch(string errorstring){
318  cerr << errorstring << endl;
319  exit(1);
320  }
321  oldRowMask[0]=rowMask;
322  }
323  for(int ivalue=0;ivalue<msknodata_opt.size();++ivalue){
324  assert(msknodata_opt.size()==nodata_opt.size());
325  char op=(operator_opt.size()==msknodata_opt.size())?operator_opt[ivalue]:operator_opt[0];
326  switch(op){
327  case('='):
328  default:
329  if(lineMask[0][colMask]==msknodata_opt[ivalue])
330  masked=true;
331  break;
332  case('<'):
333  if(lineMask[0][colMask]<msknodata_opt[ivalue])
334  masked=true;
335  break;
336  case('>'):
337  if(lineMask[0][colMask]>msknodata_opt[ivalue])
338  masked=true;
339  break;
340  case('!'):
341  if(lineMask[0][colMask]!=msknodata_opt[ivalue])
342  masked=true;
343  break;
344  }
345  if(masked){
346  for(int iband=0;iband<inputReader.nrOfBand();++iband)
347  lineInput[iband][icol]=nodata_opt[ivalue];
348  masked=false;
349  break;
350  }
351  }
352  }
353  }
354  for(int iband=0;iband<lineOutput.size();++iband)
355  lineOutput[iband][icol]=lineInput[iband][icol];
356  }
357  //write buffer lineOutput to output file
358  for(int iband=0;iband<outputWriter.nrOfBand();++iband){
359  try{
360  outputWriter.writeData(lineOutput[iband],GDT_Float64,irow,iband);
361  }
362  catch(string errorstring){
363  cerr << errorstring << endl;
364  exit(1);
365  }
366  }
367  //progress bar
368  progress=static_cast<float>(irow+1.0)/outputWriter.nrOfRow();
369  pfnProgress(progress,pszMessage,pProgressArg);
370  }
371  inputReader.close();
372  for(int imask=0;imask<mask_opt.size();++imask)
373  maskReader[imask].close();
374  outputWriter.close();
375 }