pktools  2.6.3
Processing Kernel for geospatial data
pkfilter.cc
1 /**********************************************************************
2 pkfilter.cc: program to filter raster images: median, min/max, morphological, filtering
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 <iostream>
22 #include <string>
23 #include <fstream>
24 #include <math.h>
25 #include <sys/types.h>
26 #include <stdio.h>
27 #include "base/Optionpk.h"
28 #include "base/Vector2d.h"
29 #include "algorithms/Filter2d.h"
30 #include "algorithms/Filter.h"
31 #include "fileclasses/FileReaderAscii.h"
32 #include "imageclasses/ImgReaderGdal.h"
33 #include "imageclasses/ImgWriterGdal.h"
34 //test
35 #include "algorithms/StatFactory.h"
36 
37 using namespace std;
38 /*------------------
39  Main procedure
40  ----------------*/
41 int main(int argc,char **argv) {
42  Optionpk<std::string> input_opt("i","input","input image file");
43  Optionpk<std::string> output_opt("o", "output", "Output image file");
44  // Optionpk<std::string> tmpdir_opt("tmp", "tmp", "Temporary directory","/tmp",2);
45  Optionpk<bool> disc_opt("circ", "circular", "circular disc kernel for dilation and erosion", false);
46  // Optionpk<double> angle_opt("a", "angle", "angle used for directional filtering in dilation (North=0, East=90, South=180, West=270).");
47  Optionpk<std::string> method_opt("f", "filter", "filter function (median, var, min, max, sum, mean, dilate, erode, close, open, homog (central pixel must be identical to all other pixels within window), heterog (central pixel must be different than all other pixels within window), sobelx (horizontal edge detection), sobely (vertical edge detection), sobelxy (diagonal edge detection NE-SW),sobelyx (diagonal edge detection NW-SE), smooth, density, countid, mode (majority voting, only for classes), smoothnodata (smooth nodata values only) values, threshold local filtering, ismin, ismax, order (rank pixels in order), stdev, mrf, dwt, dwti, dwt_cut, dwt_cut_from, scramble, shift, savgolay, percentile)");
48  Optionpk<std::string> resample_opt("r", "resampling-method", "Resampling method for shifting operation (near: nearest neighbour, bilinear: bi-linear interpolation).", "near");
49  Optionpk<double> dimX_opt("dx", "dx", "filter kernel size in x, better use odd value to avoid image shift", 3);
50  Optionpk<double> dimY_opt("dy", "dy", "filter kernel size in y, better use odd value to avoid image shift", 3);
51  Optionpk<int> dimZ_opt("dz", "dz", "filter kernel size in z (spectral/temporal dimension), must be odd (example: 3).. Set dz>0 if 1-D filter must be used in band domain");
52  Optionpk<std::string> wavelet_type_opt("wt", "wavelet", "wavelet type: daubechies,daubechies_centered, haar, haar_centered, bspline, bspline_centered", "daubechies");
53  Optionpk<int> family_opt("wf", "family", "wavelet family (vanishing moment, see also http://www.gnu.org/software/gsl/manual/html_node/DWT-Initialization.html)", 4);
54  Optionpk<int> savgolay_nl_opt("nl", "nl", "Number of leftward (past) data points used in Savitzky-Golay filter)", 2);
55  Optionpk<int> savgolay_nr_opt("nr", "nr", "Number of rightward (future) data points used in Savitzky-Golay filter)", 2);
56  Optionpk<int> savgolay_ld_opt("ld", "ld", "order of the derivative desired in Savitzky-Golay filter (e.g., ld=0 for smoothed function)", 0);
57  Optionpk<int> savgolay_m_opt("m", "m", "order of the smoothing polynomial in Savitzky-Golay filter, also equal to the highest conserved moment; usual values are m = 2 or m = 4)", 2);
58  Optionpk<short> class_opt("class", "class", "class value(s) to use for density, erosion, dilation, openening and closing, thresholding");
59  Optionpk<double> threshold_opt("t", "threshold", "threshold value(s) to use for threshold filter (one for each class), or threshold to cut for dwt_cut (use 0 to keep all) or dwt_cut_from, or sigma for shift", 0);
60  Optionpk<double> nodata_opt("nodata", "nodata", "nodata value(s) (used for smoothnodata filter)");
61  Optionpk<std::string> tap_opt("tap", "tap", "text file containing taps used for spatial filtering (from ul to lr). Use dimX and dimY to specify tap dimensions in x and y. Leave empty for not using taps");
62  Optionpk<double> tapz_opt("tapz", "tapz", "taps used for spectral filtering");
63  Optionpk<string> padding_opt("pad","pad", "Padding method for filtering (how to handle edge effects). Choose between: symmetric, replicate, circular, zero (pad with 0).", "symmetric");
64  Optionpk<double> fwhm_opt("fwhm", "fwhm", "list of full width half to apply spectral filtering (-fwhm band1 -fwhm band2 ...)");
65  Optionpk<std::string> srf_opt("srf", "srf", "list of ASCII files containing spectral response functions (two columns: wavelength response)");
66  Optionpk<double> wavelengthIn_opt("win", "wavelengthIn", "list of wavelengths in input spectrum (-win band1 -win band2 ...)");
67  Optionpk<double> wavelengthOut_opt("wout", "wavelengthOut", "list of wavelengths in output spectrum (-wout band1 -wout band2 ...)");
68  Optionpk<std::string> interpolationType_opt("interp", "interp", "type of interpolation for spectral filtering (see http://www.gnu.org/software/gsl/manual/html_node/Interpolation-Types.html)","akima");
69  Optionpk<std::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","");
70  Optionpk<string> oformat_opt("of", "oformat", "Output image format (see also gdal_translate). Empty string: inherit from input image");
71  Optionpk<string> colorTable_opt("ct", "ct", "color table (file with 5 columns: id R G B ALFA (0: transparent, 255: solid). Use none to ommit color table");
72  Optionpk<string> option_opt("co", "co", "Creation option for output file. Multiple options can be specified.");
73  Optionpk<short> down_opt("d", "down", "down sampling factor. Use value 1 for no downsampling). Use value n>1 for downsampling (aggregation)", 1);
74  Optionpk<string> beta_opt("beta", "beta", "ASCII file with beta for each class transition in Markov Random Field");
75  // Optionpk<double> eps_opt("eps","eps", "error marging for linear feature",0);
76  // Optionpk<bool> l1_opt("l1","l1", "obtain longest object length for linear feature",false);
77  // Optionpk<bool> l2_opt("l2","l2", "obtain shortest object length for linear feature",false,2);
78  // Optionpk<bool> a1_opt("a1","a1", "obtain angle found for longest object length for linear feature",false);
79  // Optionpk<bool> a2_opt("a2","a2", "obtain angle found for shortest object length for linear feature",false);
80  Optionpk<short> verbose_opt("v", "verbose", "verbose mode if > 0", 0,2);
81 
82  resample_opt.setHide(1);
83  option_opt.setHide(1);
84  wavelet_type_opt.setHide(1);
85  family_opt.setHide(1);
86  savgolay_nl_opt.setHide(1);
87  savgolay_nr_opt.setHide(1);
88  savgolay_ld_opt.setHide(1);
89  savgolay_m_opt.setHide(1);
90  class_opt.setHide(1);
91  threshold_opt.setHide(1);
92  tap_opt.setHide(1);
93  tapz_opt.setHide(1);
94  padding_opt.setHide(1);
95  wavelengthIn_opt.setHide(1);
96  wavelengthOut_opt.setHide(1);
97  down_opt.setHide(1);
98  beta_opt.setHide(1);
99  // eps_opt.setHide(1);
100  // l1_opt.setHide(1);
101  // l2_opt.setHide(1);
102  // a1_opt.setHide(1);
103  // a2_opt.setHide(1);
104  interpolationType_opt.setHide(1);
105  otype_opt.setHide(1);
106  oformat_opt.setHide(1);
107  colorTable_opt.setHide(1);
108  disc_opt.setHide(1);
109 
110  bool doProcess;//stop process when program was invoked with help option (-h --help)
111  try{
112  doProcess=input_opt.retrieveOption(argc,argv);
113  output_opt.retrieveOption(argc,argv);
114  // tmpdir_opt.retrieveOption(argc,argv);
115  // angle_opt.retrieveOption(argc,argv);
116  method_opt.retrieveOption(argc,argv);
117  srf_opt.retrieveOption(argc,argv);
118  fwhm_opt.retrieveOption(argc,argv);
119  dimX_opt.retrieveOption(argc,argv);
120  dimY_opt.retrieveOption(argc,argv);
121  dimZ_opt.retrieveOption(argc,argv);
122  nodata_opt.retrieveOption(argc,argv);
123  resample_opt.retrieveOption(argc,argv);
124  option_opt.retrieveOption(argc,argv);
125  wavelet_type_opt.retrieveOption(argc,argv);
126  family_opt.retrieveOption(argc,argv);
127  savgolay_nl_opt.retrieveOption(argc,argv);
128  savgolay_nr_opt.retrieveOption(argc,argv);
129  savgolay_ld_opt.retrieveOption(argc,argv);
130  savgolay_m_opt.retrieveOption(argc,argv);
131  class_opt.retrieveOption(argc,argv);
132  threshold_opt.retrieveOption(argc,argv);
133  tap_opt.retrieveOption(argc,argv);
134  tapz_opt.retrieveOption(argc,argv);
135  padding_opt.retrieveOption(argc,argv);
136  wavelengthIn_opt.retrieveOption(argc,argv);
137  wavelengthOut_opt.retrieveOption(argc,argv);
138  down_opt.retrieveOption(argc,argv);
139  beta_opt.retrieveOption(argc,argv);
140  // eps_opt.retrieveOption(argc,argv);
141  // l1_opt.retrieveOption(argc,argv);
142  // l2_opt.retrieveOption(argc,argv);
143  // a1_opt.retrieveOption(argc,argv);
144  // a2_opt.retrieveOption(argc,argv);
145  interpolationType_opt.retrieveOption(argc,argv);
146  otype_opt.retrieveOption(argc,argv);
147  oformat_opt.retrieveOption(argc,argv);
148  colorTable_opt.retrieveOption(argc,argv);
149  disc_opt.retrieveOption(argc,argv);
150  verbose_opt.retrieveOption(argc,argv);
151  }
152  catch(string predefinedString){
153  std::cout << predefinedString << std::endl;
154  exit(0);
155  }
156  if(!doProcess){
157  cout << endl;
158  cout << "Usage: pkfilter -i input -o ouptut [-f filter | -perc value | -srf file [-srf file]* -win wavelength [-win wavelength]* | -wout wavelength -fwhm value [-wout wavelength -fwhm value]* -win wavelength [-win wavelength]*]" << endl;
159  cout << endl;
160  std::cout << "short option -h shows basic options only, use long option --help to show all options" << std::endl;
161  exit(0);//help was invoked, stop processing
162  }
163 
164  //not implemented yet, must debug first...
165  vector<double> angle_opt;
166 
167  ImgReaderGdal input;
168  ImgWriterGdal output;
169  if(input_opt.empty()){
170  cerr << "Error: no input file selected, use option -i" << endl;
171  exit(1);
172  }
173  if(output_opt.empty()){
174  cerr << "Error: no output file selected, use option -o" << endl;
175  exit(1);
176  }
177  input.open(input_opt[0]);
178  GDALDataType theType=GDT_Unknown;
179  if(verbose_opt[0])
180  cout << "possible output data types: ";
181  for(int iType = 0; iType < GDT_TypeCount; ++iType){
182  if(verbose_opt[0])
183  cout << " " << GDALGetDataTypeName((GDALDataType)iType);
184  if( GDALGetDataTypeName((GDALDataType)iType) != NULL
185  && EQUAL(GDALGetDataTypeName((GDALDataType)iType),
186  otype_opt[0].c_str()))
187  theType=(GDALDataType) iType;
188  }
189  if(theType==GDT_Unknown)
190  theType=input.getDataType();
191 
192  if(verbose_opt[0])
193  std::cout << std::endl << "Output pixel type: " << GDALGetDataTypeName(theType) << endl;
194 
195  string imageType=input.getImageType();
196  if(oformat_opt.size())
197  imageType=oformat_opt[0];
198 
199  if(option_opt.findSubstring("INTERLEAVE=")==option_opt.end()){
200  string theInterleave="INTERLEAVE=";
201  theInterleave+=input.getInterleave();
202  option_opt.push_back(theInterleave);
203  }
204  try{
205  int nband=input.nrOfBand();
206 
207  if(fwhm_opt.size())
208  nband=fwhm_opt.size();
209  else if(srf_opt.size())
210  nband=srf_opt.size();
211  else if(tap_opt.size()||tapz_opt.size())
212  nband=input.nrOfBand();
213  else{
214  if(method_opt.empty()){
215  cerr << "Error: no filter selected, use option -f" << endl;
216  exit(1);
217  }
218  switch(filter2d::Filter2d::getFilterType(method_opt[0])){
219  case(filter2d::dilate):
220  case(filter2d::erode):
221  case(filter2d::close):
222  case(filter2d::open):
223  case(filter2d::smooth):
224  //implemented in spectral/temporal domain (dimZ>1) and spatial domain
225  if(dimZ_opt.size())
226  assert(dimZ_opt[0]>1);
227  nband=input.nrOfBand();
228  break;
229  case(filter2d::dwt):
230  case(filter2d::dwti):
231  case(filter2d::dwt_cut):
232  case(filter2d::smoothnodata):
233  //implemented in spectral/temporal/spatial domain and nband always input.nrOfBand()
234  nband=input.nrOfBand();
235  break;
236  case(filter2d::savgolay):
237  nband=input.nrOfBand();
238  if(dimZ_opt.empty())
239  dimZ_opt.push_back(1);
240  case(filter2d::dwt_cut_from):
241  //only implemented in spectral/temporal domain
242  if(dimZ_opt.size()){
243  nband=input.nrOfBand();
244  assert(threshold_opt.size());
245  }
246  else{
247  cerr << "filter not implemented in spectral/temporal domain" << endl;
248  exit(1);
249  }
250  break;
251  case(filter2d::mrf)://deliberate fall through
252  assert(class_opt.size()>1);
253  if(verbose_opt[0])
254  std::cout << "opening output image " << output_opt[0] << std::endl;
255  nband=class_opt.size();
256  case(filter2d::ismin):
257  case(filter2d::ismax):
258  case(filter2d::shift):
259  case(filter2d::scramble):
260  case(filter2d::mode):
261  case(filter2d::sobelx):
262  case(filter2d::sobely):
263  case(filter2d::sobelxy):
264  case(filter2d::countid):
265  case(filter2d::order):
266  case(filter2d::density):
267  case(filter2d::homog):
268  case(filter2d::heterog):
269  //only implemented in spatial domain
270  if(dimZ_opt.size()){
271  cerr << "filter not implemented in spectral/temporal domain" << endl;
272  exit(1);
273  }
274  break;
275  // case(filter2d::percentile):
276  // //implemented in spectral/temporal/spatial domain and nband 1 if dimZ>0
277  // if(dimZ_opt.size()){
278  // dimZ_opt[0]=1;
279  // nband=1;
280  // }
281  // else
282  // nband=input.nrOfBand();
283  // break;
284  case(filter2d::sum):
285  case(filter2d::mean):
286  case(filter2d::min):
287  case(filter2d::max):
288  case(filter2d::var):
289  case(filter2d::stdev):
290  case(filter2d::median):
291  case(filter2d::percentile):
292  //implemented in spectral/temporal/spatial domain and nband 1 if dimZ==1
293  if(dimZ_opt.size()==1)
294  if(dimZ_opt[0]==1)
295  nband=1;
296  else
297  nband=input.nrOfBand();
298  break;
299  default:
300  cerr << "filter not implemented" << endl;
301  exit(1);
302  // if(dimZ_opt.size())
303  // nband=dimZ_opt[0];
304  // else
305  // nband=input.nrOfBand();
306  break;
307  }
308  }
309  std::cout << "opening output image " << output_opt[0] << " with " << nband << " bands" << std::endl;
310  output.open(output_opt[0],(input.nrOfCol()+down_opt[0]-1)/down_opt[0],(input.nrOfRow()+down_opt[0]-1)/down_opt[0],nband,theType,imageType,option_opt);
311  }
312  catch(string errorstring){
313  cout << errorstring << endl;
314  exit(4);
315  }
316  output.setProjection(input.getProjection());
317  double gt[6];
318  input.getGeoTransform(gt);
319  gt[1]*=down_opt[0];//dx
320  gt[5]*=down_opt[0];//dy
321  output.setGeoTransform(gt);
322 
323  if(colorTable_opt.size()){
324  if(colorTable_opt[0]!="none"){
325  if(verbose_opt[0])
326  cout << "set colortable " << colorTable_opt[0] << endl;
327  assert(output.getDataType()==GDT_Byte);
328  output.setColorTable(colorTable_opt[0]);
329  }
330  }
331  else if(input.getColorTable()!=NULL)
332  output.setColorTable(input.getColorTable());
333 
334  if(nodata_opt.size()){
335  for(int iband=0;iband<output.nrOfBand();++iband)
336  output.GDALSetNoDataValue(nodata_opt[0],iband);
337  }
338 
339  filter2d::Filter2d filter2d;
340  filter::Filter filter1d;
341  if(verbose_opt[0])
342  cout << "Set padding to " << padding_opt[0] << endl;
343  filter1d.setPadding(padding_opt[0]);
344  if(class_opt.size()){
345  if(verbose_opt[0])
346  std::cout<< "class values: ";
347  for(int iclass=0;iclass<class_opt.size();++iclass){
348  if(!dimZ_opt.size())
349  filter2d.pushClass(class_opt[iclass]);
350  else
351  filter1d.pushClass(class_opt[iclass]);
352  if(verbose_opt[0])
353  std::cout<< class_opt[iclass] << " ";
354  }
355  if(verbose_opt[0])
356  std::cout<< std::endl;
357  }
358 
359  if(nodata_opt.size()){
360  if(verbose_opt[0])
361  std::cout<< "mask values: ";
362  for(int imask=0;imask<nodata_opt.size();++imask){
363  if(verbose_opt[0])
364  std::cout<< nodata_opt[imask] << " ";
365  filter1d.pushNoDataValue(nodata_opt[imask]);
366  filter2d.pushNoDataValue(nodata_opt[imask]);
367  }
368  if(verbose_opt[0])
369  std::cout<< std::endl;
370  }
371  if(tap_opt.size()){
372  ifstream tapfile(tap_opt[0].c_str());
373  assert(tapfile);
374  Vector2d<double> taps(dimY_opt[0],dimX_opt[0]);
375 
376  for(int j=0;j<dimY_opt[0];++j){
377  for(int i=0;i<dimX_opt[0];++i){
378  tapfile >> taps[j][i];
379  }
380  }
381  if(verbose_opt[0]){
382  std::cout << "taps: ";
383  for(int j=0;j<dimY_opt[0];++j){
384  for(int i=0;i<dimX_opt[0];++i){
385  std::cout<< taps[j][i] << " ";
386  }
387  std::cout<< std::endl;
388  }
389  }
390  filter2d.setTaps(taps);
391  try{
392  filter2d.filter(input,output);
393  }
394  catch(string errorstring){
395  cerr << errorstring << endl;
396  }
397  tapfile.close();
398  }
399  else if(tapz_opt.size()){
400  if(verbose_opt[0]){
401  std::cout << "taps: ";
402  for(int itap=0;itap<tapz_opt.size();++itap)
403  std::cout<< tapz_opt[itap] << " ";
404  std::cout<< std::endl;
405  }
406  filter1d.setTaps(tapz_opt);
407  filter1d.filter(input,output);
408  }
409  else if(fwhm_opt.size()){
410  if(verbose_opt[0])
411  std::cout << "spectral filtering to " << fwhm_opt.size() << " bands with provided fwhm " << std::endl;
412  assert(wavelengthOut_opt.size()==fwhm_opt.size());
413  assert(wavelengthIn_opt.size());
414 
415  Vector2d<double> lineInput(input.nrOfBand(),input.nrOfCol());
416  Vector2d<double> lineOutput(wavelengthOut_opt.size(),input.nrOfCol());
417  const char* pszMessage;
418  void* pProgressArg=NULL;
419  GDALProgressFunc pfnProgress=GDALTermProgress;
420  double progress=0;
421  pfnProgress(progress,pszMessage,pProgressArg);
422  for(int y=0;y<input.nrOfRow();++y){
423  if((y+1+down_opt[0]/2)%down_opt[0])
424  continue;
425  for(int iband=0;iband<input.nrOfBand();++iband)
426  input.readData(lineInput[iband],GDT_Float64,y,iband);
427  filter1d.applyFwhm<double>(wavelengthIn_opt,lineInput,wavelengthOut_opt,fwhm_opt, interpolationType_opt[0], lineOutput, down_opt[0], verbose_opt[0]);
428  for(int iband=0;iband<output.nrOfBand();++iband){
429  try{
430  output.writeData(lineOutput[iband],GDT_Float64,y/down_opt[0],iband);
431  }
432  catch(string errorstring){
433  cerr << errorstring << "in band " << iband << ", line " << y << endl;
434  }
435  }
436  progress=(1.0+y)/output.nrOfRow();
437  pfnProgress(progress,pszMessage,pProgressArg);
438  }
439  }
440  else if(srf_opt.size()){
441  if(verbose_opt[0])
442  std::cout << "spectral filtering to " << srf_opt.size() << " bands with provided SRF " << std::endl;
443  assert(wavelengthIn_opt.size());
444  vector< Vector2d<double> > srf(srf_opt.size());//[0] srf_nr, [1]: wavelength, [2]: response
445  ifstream srfFile;
446  for(int isrf=0;isrf<srf_opt.size();++isrf){
447  srf[isrf].resize(2);
448  srfFile.open(srf_opt[isrf].c_str());
449  double v;
450  //add 0 to make sure srf is 0 at boundaries after interpolation step
451  srf[isrf][0].push_back(0);
452  srf[isrf][1].push_back(0);
453  srf[isrf][0].push_back(1);
454  srf[isrf][1].push_back(0);
455  while(srfFile >> v){
456  srf[isrf][0].push_back(v);
457  srfFile >> v;
458  srf[isrf][1].push_back(v);
459  }
460  srfFile.close();
461  //add 0 to make sure srf[isrf] is 0 at boundaries after interpolation step
462  srf[isrf][0].push_back(srf[isrf][0].back()+1);
463  srf[isrf][1].push_back(0);
464  srf[isrf][0].push_back(srf[isrf][0].back()+1);
465  srf[isrf][1].push_back(0);
466  if(verbose_opt[0])
467  cout << "srf file details: " << srf[isrf][0].size() << " wavelengths defined" << endl;
468  }
469  assert(output.nrOfBand()==srf.size());
470  double centreWavelength=0;
471  Vector2d<double> lineInput(input.nrOfBand(),input.nrOfCol());
472  const char* pszMessage;
473  void* pProgressArg=NULL;
474  GDALProgressFunc pfnProgress=GDALTermProgress;
475  double progress=0;
476  pfnProgress(progress,pszMessage,pProgressArg);
477  for(int y=0;y<input.nrOfRow();++y){
478  if((y+1+down_opt[0]/2)%down_opt[0])
479  continue;
480  for(int iband=0;iband<input.nrOfBand();++iband)
481  input.readData(lineInput[iband],GDT_Float64,y,iband);
482  for(int isrf=0;isrf<srf.size();++isrf){
483  vector<double> lineOutput(output.nrOfCol());
484  double delta=1.0;
485  bool normalize=true;
486  centreWavelength=filter1d.applySrf<double>(wavelengthIn_opt,lineInput,srf[isrf], interpolationType_opt[0], lineOutput, delta, normalize);
487  if(verbose_opt[0])
488  std::cout << "centre wavelength srf " << isrf << ": " << centreWavelength << std::endl;
489  try{
490  output.writeData(lineOutput,GDT_Float64,y/down_opt[0],isrf);
491  }
492  catch(string errorstring){
493  cerr << errorstring << "in srf " << srf_opt[isrf] << ", line " << y << endl;
494  }
495 
496  }
497  progress=(1.0+y)/output.nrOfRow();
498  pfnProgress(progress,pszMessage,pProgressArg);
499  }
500 
501  }
502  else{
503  switch(filter2d::Filter2d::getFilterType(method_opt[0])){
504  case(filter2d::dilate):
505  if(down_opt[0]!=1){
506  std::cerr << "Error: down option not supported for morphological operator" << std::endl;
507  exit(1);
508  }
509  try{
510  if(dimZ_opt.size()){
511  if(verbose_opt[0])
512  std::cout<< "1-D filtering: dilate" << std::endl;
513  filter1d.morphology(input,output,"dilate",dimZ_opt[0],verbose_opt[0]);
514  }
515  else
516  filter2d.morphology(input,output,"dilate",dimX_opt[0],dimY_opt[0],angle_opt,disc_opt[0]);
517  }
518  catch(string errorstring){
519  cerr << errorstring << endl;
520  }
521  break;
522  case(filter2d::erode):
523  if(down_opt[0]!=1){
524  std::cerr << "Error: down option not supported for morphological operator" << std::endl;
525  exit(1);
526  }
527  try{
528  if(dimZ_opt.size()>0){
529  if(verbose_opt[0])
530  std::cout<< "1-D filtering: dilate" << std::endl;
531  filter1d.morphology(input,output,"erode",dimZ_opt[0]);
532  }
533  else{
534  filter2d.morphology(input,output,"erode",dimX_opt[0],dimY_opt[0],angle_opt,disc_opt[0]);
535  }
536  }
537  catch(string errorstring){
538  cerr << errorstring << endl;
539  }
540  break;
541  case(filter2d::close):{//closing
542  if(down_opt[0]!=1){
543  std::cerr << "Error: down option not supported for morphological operator" << std::endl;
544  exit(1);
545  }
546 
547  ImgWriterGdal tmpout;
548  tmpout.open("/vsimem/dilation.tif",input);
549  try{
550  if(dimZ_opt.size()){
551  filter1d.morphology(input,tmpout,"dilate",dimZ_opt[0]);
552  }
553  else{
554  filter2d.morphology(input,tmpout,"dilate",dimX_opt[0],dimY_opt[0],angle_opt,disc_opt[0]);
555  }
556  }
557  catch(std::string errorString){
558  std::cout<< errorString;
559  exit(1);
560  }
561  ImgReaderGdal tmpin;
562  tmpin.open("/vsimem/dilation.tif");
563  try{
564  if(dimZ_opt.size()){
565  filter1d.morphology(tmpin,output,"erode",dimZ_opt[0]);
566  }
567  else{
568  filter2d.morphology(tmpin,output,"erode",dimX_opt[0],dimY_opt[0],angle_opt,disc_opt[0]);
569  }
570  }
571  catch(string errorstring){
572  cerr << errorstring << endl;
573  }
574  tmpin.close();
575  tmpout.close();
576  break;
577  }
578  case(filter2d::open):{//opening
579  if(down_opt[0]!=1){
580  std::cerr << "Error: down option not supported for morphological operator" << std::endl;
581  exit(1);
582  }
583  ImgWriterGdal tmpout;
584  tmpout.open("/vsimem/erosion.tif",input);
585  try{
586  if(dimZ_opt.size()){
587  filter1d.morphology(input,tmpout,"erode",dimZ_opt[0]);
588  }
589  else{
590  filter2d.morphology(input,tmpout,"erode",dimX_opt[0],dimY_opt[0],angle_opt,disc_opt[0]);
591  }
592  }
593  catch(std::string errorString){
594  std::cout<< errorString;
595  exit(1);
596  }
597  ImgReaderGdal tmpin;
598  try{
599  tmpin.open("/vsimem/erosion.tif");
600  if(dimZ_opt.size()){
601  filter1d.morphology(tmpin,output,"dilate",dimZ_opt[0]);
602  }
603  else{
604  filter2d.morphology(tmpin,output,"dilate",dimX_opt[0],dimY_opt[0],angle_opt,disc_opt[0]);
605  }
606  tmpin.close();
607  tmpout.close();
608  }
609  catch(string errorstring){
610  cerr << errorstring << endl;
611  }
612  break;
613  }
614  case(filter2d::homog):{//spatially homogeneous
615  try{
616  filter2d.doit(input,output,"homog",dimX_opt[0],dimY_opt[0],down_opt[0],disc_opt[0]);
617  }
618  catch(string errorstring){
619  cerr << errorstring << endl;
620  }
621  break;
622  }
623  case(filter2d::heterog):{//spatially heterogeneous
624  try{
625  filter2d.doit(input,output,"heterog",dimX_opt[0],dimY_opt[0],down_opt[0],disc_opt[0]);
626  }
627  catch(string errorstring){
628  cerr << errorstring << endl;
629  }
630  break;
631  }
632  case(filter2d::shift):{//shift
633  if(down_opt[0]!=1){
634  std::cerr << "Error: down option not supported for shift operator" << std::endl;
635  exit(1);
636  }
637  assert(input.nrOfBand());
638  assert(input.nrOfCol());
639  assert(input.nrOfRow());
640  try{
641  filter2d.shift(input,output,dimX_opt[0],dimY_opt[0],threshold_opt[0],filter2d::Filter2d::getResampleType(resample_opt[0]));
642  }
643  catch(string errorstring){
644  cerr << errorstring << endl;
645  }
646  break;
647  }
648  // case(filter2d::linearfeature):{
649  // if(down_opt[0]!=1){
650  // std::cerr << "Error: down option not supported for linear feature" << std::endl;
651  // exit(1);
652  // }
653  // assert(input.nrOfBand());
654  // assert(input.nrOfCol());
655  // assert(input.nrOfRow());
656  // float theAngle=361;
657  // if(angle_opt.size())
658  // theAngle=angle_opt[0];
659  // if(verbose_opt[0])
660  // std::cout << "using angle " << theAngle << std::endl;
661  // try{
662  // //using an angle step of 5 degrees and no maximum distance
663  // filter2d.linearFeature(input,output,theAngle,5,0,eps_opt[0],l1_opt[0],a1_opt[0],l2_opt[0],a2_opt[0],0,verbose_opt[0]);
664  // }
665  // catch(string errorstring){
666  // cerr << errorstring << endl;
667  // }
668  // break;
669  // }
670  case(filter2d::mrf):{//Markov Random Field
671  if(verbose_opt[0])
672  std::cout << "Markov Random Field filtering" << std::endl;
673  try{
674  if(beta_opt.size()){
675  //in file: classFrom classTo
676  //in variable: beta[classTo][classFrom]
677  FileReaderAscii betaReader(beta_opt[0]);
678  Vector2d<double> beta(class_opt.size(),class_opt.size());
679  vector<int> cols(class_opt.size());
680  for(int iclass=0;iclass<class_opt.size();++iclass)
681  cols[iclass]=iclass;
682  betaReader.readData(beta,cols);
683  if(verbose_opt[0]){
684  std::cout << "using values for beta:" << std::endl;
685  for(int iclass1=0;iclass1<class_opt.size();++iclass1)
686  std::cout << " " << iclass1 << " (" << class_opt[iclass1] << ")";
687  std::cout << std::endl;
688  for(int iclass1=0;iclass1<class_opt.size();++iclass1){
689  std::cout << iclass1 << " (" << class_opt[iclass1] << ")";
690  for(int iclass2=0;iclass2<class_opt.size();++iclass2)
691  std::cout << " " << beta[iclass2][iclass1] << " (" << class_opt[iclass2] << ")";
692  std::cout << std::endl;
693  }
694  }
695  filter2d.mrf(input, output, dimX_opt[0], dimY_opt[0], beta, true, down_opt[0], verbose_opt[0]);
696  }
697  else
698  filter2d.mrf(input, output, dimX_opt[0], dimY_opt[0], 1, true, down_opt[0], verbose_opt[0]);
699  }
700  catch(string errorstring){
701  cerr << errorstring << endl;
702  }
703  break;
704  }
705  case(filter2d::sobelx):{//Sobel edge detection in X
706  if(down_opt[0]!=1){
707  std::cerr << "Error: down option not supported for sobel edge detection" << std::endl;
708  exit(1);
709  }
710  Vector2d<double> theTaps(3,3);
711  theTaps[0][0]=-1.0;
712  theTaps[0][1]=0.0;
713  theTaps[0][2]=1.0;
714  theTaps[1][0]=-2.0;
715  theTaps[1][1]=0.0;
716  theTaps[1][2]=2.0;
717  theTaps[2][0]=-1.0;
718  theTaps[2][1]=0.0;
719  theTaps[2][2]=1.0;
720  filter2d.setTaps(theTaps);
721  try{
722  filter2d.filter(input,output,true,true);//absolute and normalize
723  }
724  catch(string errorstring){
725  cerr << errorstring << endl;
726  }
727  break;
728  }
729  case(filter2d::sobely):{//Sobel edge detection in Y
730  if(down_opt[0]!=1){
731  std::cerr << "Error: down option not supported for sobel edge detection" << std::endl;
732  exit(1);
733  }
734  Vector2d<double> theTaps(3,3);
735  theTaps[0][0]=1.0;
736  theTaps[0][1]=2.0;
737  theTaps[0][2]=1.0;
738  theTaps[1][0]=0.0;
739  theTaps[1][1]=0.0;
740  theTaps[1][2]=0.0;
741  theTaps[2][0]=-1.0;
742  theTaps[2][1]=-2.0;
743  theTaps[2][2]=-1.0;
744  filter2d.setTaps(theTaps);
745  try{
746  filter2d.filter(input,output,true,true);//absolute and normalize
747  }
748  catch(string errorstring){
749  cerr << errorstring << endl;
750  }
751  break;
752  }
753  case(filter2d::sobelxy):{//Sobel edge detection in XY
754  if(down_opt[0]!=1){
755  std::cerr << "Error: down option not supported for sobel edge detection" << std::endl;
756  exit(1);
757  }
758  Vector2d<double> theTaps(3,3);
759  theTaps[0][0]=0.0;
760  theTaps[0][1]=1.0;
761  theTaps[0][2]=2.0;
762  theTaps[1][0]=-1.0;
763  theTaps[1][1]=0.0;
764  theTaps[1][2]=1.0;
765  theTaps[2][0]=-2.0;
766  theTaps[2][1]=-1.0;
767  theTaps[2][2]=0.0;
768  filter2d.setTaps(theTaps);
769  try{
770  filter2d.filter(input,output,true,true);//absolute and normalize
771  }
772  catch(string errorstring){
773  cerr << errorstring << endl;
774  }
775  break;
776  }
777  case(filter2d::sobelyx):{//Sobel edge detection in XY
778  if(down_opt[0]!=1){
779  std::cerr << "Error: down option not supported for sobel edge detection" << std::endl;
780  exit(1);
781  }
782  Vector2d<double> theTaps(3,3);
783  theTaps[0][0]=2.0;
784  theTaps[0][1]=1.0;
785  theTaps[0][2]=0.0;
786  theTaps[1][0]=1.0;
787  theTaps[1][1]=0.0;
788  theTaps[1][2]=-1.0;
789  theTaps[2][0]=0.0;
790  theTaps[2][1]=-1.0;
791  theTaps[2][2]=-2.0;
792  filter2d.setTaps(theTaps);
793  try{
794  filter2d.filter(input,output,true,true);//absolute and normalize
795  }
796  catch(string errorstring){
797  cerr << errorstring << endl;
798  }
799  break;
800  }
801  case(filter2d::smooth):{//Smoothing filter
802  if(down_opt[0]!=1){
803  std::cerr << "Error: down option not supported for this filter" << std::endl;
804  exit(1);
805  }
806  try{
807  if(dimZ_opt.size()){
808  if(verbose_opt[0])
809  std::cout<< "1-D filtering: smooth" << std::endl;
810  filter1d.smooth(input,output,dimZ_opt[0]);
811  }
812  else{
813  filter2d.smooth(input,output,dimX_opt[0],dimY_opt[0]);
814  }
815  }
816  catch(string errorstring){
817  cerr << errorstring << endl;
818  }
819  break;
820  }
821  case(filter2d::smoothnodata):{//Smoothing filter
822  if(down_opt[0]!=1){
823  std::cerr << "Error: down option not supported for this filter" << std::endl;
824  exit(1);
825  }
826  try{
827  if(dimZ_opt.size()){
828  if(verbose_opt[0])
829  std::cout<< "1-D filtering: smooth" << std::endl;
830  filter1d.smoothNoData(input,interpolationType_opt[0],output);
831  }
832  else{
833  if(verbose_opt[0])
834  std::cout<< "2-D filtering: smooth" << std::endl;
835  filter2d.smoothNoData(input,output,dimX_opt[0],dimY_opt[0]);
836  }
837  }
838  catch(string errorstring){
839  cerr << errorstring << endl;
840  }
841  break;
842  }
843  case(filter2d::dwt):
844  if(down_opt[0]!=1){
845  std::cerr << "Error: down option not supported for this filter" << std::endl;
846  exit(1);
847  }
848  try{
849  if(dimZ_opt.size()){
850  if(verbose_opt[0])
851  std::cout<< "DWT in spectral domain" << std::endl;
852  filter1d.dwtForward(input, output, wavelet_type_opt[0], family_opt[0]);
853  }
854  else
855  filter2d.dwtForward(input, output, wavelet_type_opt[0], family_opt[0]);
856  }
857  catch(string errorstring){
858  cerr << errorstring << endl;
859  }
860  break;
861  case(filter2d::dwti):
862  if(down_opt[0]!=1){
863  std::cerr << "Error: down option not supported for this filter" << std::endl;
864  exit(1);
865  }
866  try{
867  if(dimZ_opt.size()){
868  if(verbose_opt[0])
869  std::cout<< "inverse DWT in spectral domain" << std::endl;
870  filter1d.dwtInverse(input, output, wavelet_type_opt[0], family_opt[0]);
871  }
872  else
873  filter2d.dwtInverse(input, output, wavelet_type_opt[0], family_opt[0]);
874  }
875  catch(string errorstring){
876  cerr << errorstring << endl;
877  }
878  break;
879  case(filter2d::dwt_cut):
880  if(down_opt[0]!=1){
881  std::cerr << "Error: down option not supported for this filter" << std::endl;
882  exit(1);
883  }
884  if(dimZ_opt.size()){
885  if(verbose_opt[0])
886  std::cout<< "DWT approximation in spectral domain" << std::endl;
887  filter1d.dwtCut(input, output, wavelet_type_opt[0], family_opt[0], threshold_opt[0]);
888  }
889  else
890  filter2d.dwtCut(input, output, wavelet_type_opt[0], family_opt[0], threshold_opt[0]);
891  break;
892  case(filter2d::dwt_cut_from):
893  if(down_opt[0]!=1){
894  std::cerr << "Error: down option not supported for this filter" << std::endl;
895  exit(1);
896  }
897  try{
898  if(dimZ_opt.size()){
899  if(verbose_opt[0])
900  std::cout<< "DWT approximation in spectral domain" << std::endl;
901  filter1d.dwtCutFrom(input, output, wavelet_type_opt[0], family_opt[0], static_cast<int>(threshold_opt[0]));
902  }
903  else{
904  string errorString="Error: this filter is not supported in 2D";
905  throw(errorString);
906  }
907  }
908  catch(string errorstring){
909  cerr << errorstring << endl;
910  }
911  break;
912  case(filter2d::savgolay):{
913  assert(savgolay_nl_opt.size());
914  assert(savgolay_nr_opt.size());
915  assert(savgolay_ld_opt.size());
916  assert(savgolay_m_opt.size());
917  if(verbose_opt[0])
918  std::cout << "Calculating Savitzky-Golay coefficients: " << endl;
919  filter1d.getSavGolayCoefficients(tapz_opt, input.nrOfBand(), savgolay_nl_opt[0], savgolay_nr_opt[0], savgolay_ld_opt[0], savgolay_m_opt[0]);
920  if(verbose_opt[0]){
921  std::cout << "taps (size is " << tapz_opt.size() << "): ";
922  for(int itap=0;itap<tapz_opt.size();++itap)
923  std::cout<< tapz_opt[itap] << " ";
924  std::cout<< std::endl;
925  }
926  filter1d.setTaps(tapz_opt);
927  filter1d.filter(input,output);
928  break;
929  }
930  case(filter2d::percentile)://deliberate fall through
931  case(filter2d::threshold)://deliberate fall through
932  assert(threshold_opt.size());
933  if(dimZ_opt.size())
934  filter1d.setThresholds(threshold_opt);
935  else
936  filter2d.setThresholds(threshold_opt);
937  case(filter2d::density)://deliberate fall through
938  filter2d.setClasses(class_opt);
939  if(verbose_opt[0])
940  std::cout << "classes set" << std::endl;
941  default:
942  try{
943  if(dimZ_opt.size()){
944  if(dimZ_opt[0]==1)
945  filter1d.stat(input,output,method_opt[0]);
946  else{
947  assert(down_opt[0]==1);//not implemented yet...
948  filter1d.filter(input,output,method_opt[0],dimZ_opt[0]);
949  }
950  }
951  else
952  filter2d.doit(input,output,method_opt[0],dimX_opt[0],dimY_opt[0],down_opt[0],disc_opt[0]);
953  }
954  catch(string errorstring){
955  cerr << errorstring << endl;
956  }
957  break;
958  }
959  }
960  input.close();
961  output.close();
962  return 0;
963 }