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