pktools  2.6.5
Processing Kernel for geospatial data
pkfilter_old.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, 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, heterogeneous (central pixel must be different than all other pixels within window), order (rank pixels in order), stdev, mrf, dwt, dwti, dwt_cut, dwt_cut_from, scramble, shift, savgolay, percentile)", "median");
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 (band or spectral 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<double> percentile_opt("perc","perc","Percentile value used for percentile",95);
70  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","");
71  Optionpk<string> oformat_opt("of", "oformat", "Output image format (see also gdal_translate). Empty string: inherit from input image");
72  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");
73  Optionpk<string> option_opt("co", "co", "Creation option for output file. Multiple options can be specified.");
74  Optionpk<short> down_opt("d", "down", "down sampling factor. Use value 1 for no downsampling). Use value n>1 for downsampling (aggregation)", 1);
75  Optionpk<string> beta_opt("beta", "beta", "ASCII file with beta for each class transition in Markov Random Field");
76  // Optionpk<double> eps_opt("eps","eps", "error marging for linear feature",0);
77  // Optionpk<bool> l1_opt("l1","l1", "obtain longest object length for linear feature",false);
78  // Optionpk<bool> l2_opt("l2","l2", "obtain shortest object length for linear feature",false,2);
79  // Optionpk<bool> a1_opt("a1","a1", "obtain angle found for longest object length for linear feature",false);
80  // Optionpk<bool> a2_opt("a2","a2", "obtain angle found for shortest object length for linear feature",false);
81  Optionpk<short> verbose_opt("v", "verbose", "verbose mode if > 0", 0,2);
82 
83  resample_opt.setHide(1);
84  option_opt.setHide(1);
85  wavelet_type_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  percentile_opt.retrieveOption(argc,argv);
120  dimX_opt.retrieveOption(argc,argv);
121  dimY_opt.retrieveOption(argc,argv);
122  dimZ_opt.retrieveOption(argc,argv);
123  nodata_opt.retrieveOption(argc,argv);
124  resample_opt.retrieveOption(argc,argv);
125  option_opt.retrieveOption(argc,argv);
126  wavelet_type_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  if(method_opt.empty()){
178  cerr << "Error: no filter selected, use option -f" << endl;
179  exit(1);
180  }
181  input.open(input_opt[0]);
182  GDALDataType theType=GDT_Unknown;
183  if(verbose_opt[0])
184  cout << "possible output data types: ";
185  for(int iType = 0; iType < GDT_TypeCount; ++iType){
186  if(verbose_opt[0])
187  cout << " " << GDALGetDataTypeName((GDALDataType)iType);
188  if( GDALGetDataTypeName((GDALDataType)iType) != NULL
189  && EQUAL(GDALGetDataTypeName((GDALDataType)iType),
190  otype_opt[0].c_str()))
191  theType=(GDALDataType) iType;
192  }
193  if(theType==GDT_Unknown)
194  theType=input.getDataType();
195 
196  if(verbose_opt[0])
197  std::cout << std::endl << "Output pixel type: " << GDALGetDataTypeName(theType) << endl;
198 
199  string imageType=input.getImageType();
200  if(oformat_opt.size())
201  imageType=oformat_opt[0];
202 
203  if(option_opt.findSubstring("INTERLEAVE=")==option_opt.end()){
204  string theInterleave="INTERLEAVE=";
205  theInterleave+=input.getInterleave();
206  option_opt.push_back(theInterleave);
207  }
208  try{
209  int nband=1;
210  if(fwhm_opt.size())
211  nband=fwhm_opt.size();
212  else if(srf_opt.size())
213  nband=srf_opt.size();
214  else if(dimZ_opt.size()){
215 
216  else if(percentile_opt.size())
217  nband=percentile_opt.size();
218  else{
219  switch(filter2d::Filter2d::getFilterType(method_opt[0])){
220  case(filter2d::mrf):
221  assert(class_opt.size()>1);
222  if(verbose_opt[0])
223  std::cout << "opening output image " << output_opt[0] << std::endl;
224  nband=class_opt.size()
225  break;
226  default:
227  break;
228  }
229  }
230  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);
231 
232  }
233  else{
234  int nband=input.nrOfBand();
235  if(dimZ_opt.size()){
236  if(filter2d::Filter2d::getFilterType(method_opt[0])==filter2d::smoothnodata)
237  dimZ_opt[0]=nband;
238  if(dimZ_opt[0]==1){
239  nband=1;
240  if(verbose_opt[0])
241  std::cout << "opening single band output image " << output_opt[0] << std::endl;
242  }
243  else if(verbose_opt[0])
244  std::cout << "opening multi-band output image " << output_opt[0] << std::endl;
245  }
246  else
247  std::cout << "opening output image " << output_opt[0] << std::endl;
248  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);
249  }
250  }
251  catch(string errorstring){
252  cout << errorstring << endl;
253  exit(4);
254  }
255  output.setProjection(input.getProjection());
256  double gt[6];
257  input.getGeoTransform(gt);
258  gt[1]*=down_opt[0];//dx
259  gt[5]*=down_opt[0];//dy
260  output.setGeoTransform(gt);
261 
262  if(colorTable_opt.size()){
263  if(colorTable_opt[0]!="none"){
264  if(verbose_opt[0])
265  cout << "set colortable " << colorTable_opt[0] << endl;
266  assert(output.getDataType()==GDT_Byte);
267  output.setColorTable(colorTable_opt[0]);
268  }
269  }
270  else if(input.getColorTable()!=NULL)
271  output.setColorTable(input.getColorTable());
272 
273  if(nodata_opt.size()){
274  for(int iband=0;iband<output.nrOfBand();++iband)
275  output.GDALSetNoDataValue(nodata_opt[0],iband);
276  }
277 
279  filter::Filter filter1d;
280  if(verbose_opt[0])
281  cout << "Set padding to " << padding_opt[0] << endl;
282  filter1d.setPadding(padding_opt[0]);
283  if(class_opt.size()){
284  if(verbose_opt[0])
285  std::cout<< "class values: ";
286  for(int iclass=0;iclass<class_opt.size();++iclass){
287  if(!dimZ_opt.size())
288  filter2d.pushClass(class_opt[iclass]);
289  else
290  filter1d.pushClass(class_opt[iclass]);
291  if(verbose_opt[0])
292  std::cout<< class_opt[iclass] << " ";
293  }
294  if(verbose_opt[0])
295  std::cout<< std::endl;
296  }
297 
298  if(nodata_opt.size()){
299  if(verbose_opt[0])
300  std::cout<< "mask values: ";
301  for(int imask=0;imask<nodata_opt.size();++imask){
302  if(verbose_opt[0])
303  std::cout<< nodata_opt[imask] << " ";
304  filter1d.pushNoDataValue(nodata_opt[imask]);
305  filter2d.pushNoDataValue(nodata_opt[imask]);
306  }
307  if(verbose_opt[0])
308  std::cout<< std::endl;
309  }
310  if(tap_opt.size()){
311  ifstream tapfile(tap_opt[0].c_str());
312  assert(tapfile);
313  Vector2d<double> taps(dimY_opt[0],dimX_opt[0]);
314 
315  for(int j=0;j<dimY_opt[0];++j){
316  for(int i=0;i<dimX_opt[0];++i){
317  tapfile >> taps[j][i];
318  }
319  }
320  if(verbose_opt[0]){
321  std::cout << "taps: ";
322  for(int j=0;j<dimY_opt[0];++j){
323  for(int i=0;i<dimX_opt[0];++i){
324  std::cout<< taps[j][i] << " ";
325  }
326  std::cout<< std::endl;
327  }
328  }
329  filter2d.setTaps(taps);
330  filter2d.filter(input,output);
331  tapfile.close();
332  }
333  else if(tapz_opt.size()){
334  if(verbose_opt[0]){
335  std::cout << "taps: ";
336  for(int itap=0;itap<tapz_opt.size();++itap)
337  std::cout<< tapz_opt[itap] << " ";
338  std::cout<< std::endl;
339  }
340  filter1d.setTaps(tapz_opt);
341  filter1d.filter(input,output);
342  }
343  else if(fwhm_opt.size()){
344  if(verbose_opt[0])
345  std::cout << "spectral filtering to " << fwhm_opt.size() << " bands with provided fwhm " << std::endl;
346  assert(wavelengthOut_opt.size()==fwhm_opt.size());
347  assert(wavelengthIn_opt.size());
348 
349  Vector2d<double> lineInput(input.nrOfBand(),input.nrOfCol());
350  Vector2d<double> lineOutput(wavelengthOut_opt.size(),input.nrOfCol());
351  const char* pszMessage;
352  void* pProgressArg=NULL;
353  GDALProgressFunc pfnProgress=GDALTermProgress;
354  double progress=0;
355  pfnProgress(progress,pszMessage,pProgressArg);
356  for(int y=0;y<input.nrOfRow();++y){
357  if((y+1+down_opt[0]/2)%down_opt[0])
358  continue;
359  for(int iband=0;iband<input.nrOfBand();++iband)
360  input.readData(lineInput[iband],GDT_Float64,y,iband);
361  filter1d.applyFwhm<double>(wavelengthIn_opt,lineInput,wavelengthOut_opt,fwhm_opt, interpolationType_opt[0], lineOutput, down_opt[0], verbose_opt[0]);
362  for(int iband=0;iband<output.nrOfBand();++iband){
363  try{
364  output.writeData(lineOutput[iband],GDT_Float64,y/down_opt[0],iband);
365  }
366  catch(string errorstring){
367  cerr << errorstring << "in band " << iband << ", line " << y << endl;
368  }
369  }
370  progress=(1.0+y)/output.nrOfRow();
371  pfnProgress(progress,pszMessage,pProgressArg);
372  }
373  }
374  else if(srf_opt.size()){
375  if(verbose_opt[0])
376  std::cout << "spectral filtering to " << srf_opt.size() << " bands with provided SRF " << std::endl;
377  assert(wavelengthIn_opt.size());
378  vector< Vector2d<double> > srf(srf_opt.size());//[0] srf_nr, [1]: wavelength, [2]: response
379  ifstream srfFile;
380  for(int isrf=0;isrf<srf_opt.size();++isrf){
381  srf[isrf].resize(2);
382  srfFile.open(srf_opt[isrf].c_str());
383  double v;
384  //add 0 to make sure srf is 0 at boundaries after interpolation step
385  srf[isrf][0].push_back(0);
386  srf[isrf][1].push_back(0);
387  srf[isrf][0].push_back(1);
388  srf[isrf][1].push_back(0);
389  while(srfFile >> v){
390  srf[isrf][0].push_back(v);
391  srfFile >> v;
392  srf[isrf][1].push_back(v);
393  }
394  srfFile.close();
395  //add 0 to make sure srf[isrf] is 0 at boundaries after interpolation step
396  srf[isrf][0].push_back(srf[isrf][0].back()+1);
397  srf[isrf][1].push_back(0);
398  srf[isrf][0].push_back(srf[isrf][0].back()+1);
399  srf[isrf][1].push_back(0);
400  if(verbose_opt[0])
401  cout << "srf file details: " << srf[isrf][0].size() << " wavelengths defined" << endl;
402  }
403  assert(output.nrOfBand()==srf.size());
404  double centreWavelength=0;
405  Vector2d<double> lineInput(input.nrOfBand(),input.nrOfCol());
406  const char* pszMessage;
407  void* pProgressArg=NULL;
408  GDALProgressFunc pfnProgress=GDALTermProgress;
409  double progress=0;
410  pfnProgress(progress,pszMessage,pProgressArg);
411  for(int y=0;y<input.nrOfRow();++y){
412  if((y+1+down_opt[0]/2)%down_opt[0])
413  continue;
414  for(int iband=0;iband<input.nrOfBand();++iband)
415  input.readData(lineInput[iband],GDT_Float64,y,iband);
416  for(int isrf=0;isrf<srf.size();++isrf){
417  vector<double> lineOutput(output.nrOfCol());
418  double delta=1.0;
419  bool normalize=true;
420  centreWavelength=filter1d.applySrf<double>(wavelengthIn_opt,lineInput,srf[isrf], interpolationType_opt[0], lineOutput, delta, normalize);
421  if(verbose_opt[0])
422  std::cout << "centre wavelength srf " << isrf << ": " << centreWavelength << std::endl;
423  try{
424  output.writeData(lineOutput,GDT_Float64,y/down_opt[0],isrf);
425  }
426  catch(string errorstring){
427  cerr << errorstring << "in srf " << srf_opt[isrf] << ", line " << y << endl;
428  }
429 
430  }
431  progress=(1.0+y)/output.nrOfRow();
432  pfnProgress(progress,pszMessage,pProgressArg);
433  }
434 
435  }
436  else{
437  switch(filter2d::Filter2d::getFilterType(method_opt[0])){
438  case(filter2d::dilate):
439  if(down_opt[0]!=1){
440  std::cerr << "Error: down option not supported for morphological operator" << std::endl;
441  exit(1);
442  }
443  if(dimZ_opt.size()){
444  if(verbose_opt[0])
445  std::cout<< "1-D filtering: dilate" << std::endl;
446  filter1d.morphology(input,output,"dilate",dimZ_opt[0],verbose_opt[0]);
447  }
448  else{
449  filter2d.morphology(input,output,"dilate",dimX_opt[0],dimY_opt[0],angle_opt,disc_opt[0]);
450  }
451  break;
452  case(filter2d::erode):
453  if(down_opt[0]!=1){
454  std::cerr << "Error: down option not supported for morphological operator" << std::endl;
455  exit(1);
456  }
457  if(dimZ_opt.size()>0){
458  if(verbose_opt[0])
459  std::cout<< "1-D filtering: dilate" << std::endl;
460  filter1d.morphology(input,output,"erode",dimZ_opt[0]);
461  }
462  else{
463  filter2d.morphology(input,output,"erode",dimX_opt[0],dimY_opt[0],angle_opt,disc_opt[0]);
464  }
465  break;
466  case(filter2d::close):{//closing
467  if(down_opt[0]!=1){
468  std::cerr << "Error: down option not supported for morphological operator" << std::endl;
469  exit(1);
470  }
471 
472  ImgWriterGdal tmpout;
473  tmpout.open("/vsimem/dilation",input);
474  try{
475  if(dimZ_opt.size()){
476  filter1d.morphology(input,tmpout,"dilate",dimZ_opt[0]);
477  }
478  else{
479  filter2d.morphology(input,tmpout,"dilate",dimX_opt[0],dimY_opt[0],angle_opt,disc_opt[0]);
480  }
481  }
482  catch(std::string errorString){
483  std::cout<< errorString;
484  exit(1);
485  }
486  ImgReaderGdal tmpin;
487  tmpin.open("/vsimem/dilation");
488  if(dimZ_opt.size()){
489  filter1d.morphology(tmpin,output,"erode",dimZ_opt[0]);
490  }
491  else{
492  filter2d.morphology(tmpin,output,"erode",dimX_opt[0],dimY_opt[0],angle_opt,disc_opt[0]);
493  }
494  tmpin.close();
495  tmpout.close();
496  break;
497  }
498  case(filter2d::open):{//opening
499  if(down_opt[0]!=1){
500  std::cerr << "Error: down option not supported for morphological operator" << std::endl;
501  exit(1);
502  }
503  ImgWriterGdal tmpout;
504  tmpout.open("/vsimem/erosion",input);
505  try{
506  if(dimZ_opt.size()){
507  filter1d.morphology(input,tmpout,"erode",dimZ_opt[0]);
508  }
509  else{
510  filter2d.morphology(input,tmpout,"erode",dimX_opt[0],dimY_opt[0],angle_opt,disc_opt[0]);
511  }
512  }
513  catch(std::string errorString){
514  std::cout<< errorString;
515  exit(1);
516  }
517  ImgReaderGdal tmpin;
518  tmpin.open("/vsimem/erosion");
519  if(dimZ_opt.size()){
520  filter1d.morphology(tmpin,output,"dilate",dimZ_opt[0]);
521  }
522  else{
523  filter2d.morphology(tmpin,output,"dilate",dimX_opt[0],dimY_opt[0],angle_opt,disc_opt[0]);
524  }
525  tmpin.close();
526  tmpout.close();
527  break;
528  }
529  case(filter2d::homog):{//spatially homogeneous
530  filter2d.doit(input,output,"homog",dimX_opt[0],dimY_opt[0],down_opt[0],disc_opt[0]);
531  break;
532  }
533  case(filter2d::heterog):{//spatially heterogeneous
534  filter2d.doit(input,output,"heterog",dimX_opt[0],dimY_opt[0],down_opt[0],disc_opt[0]);
535  break;
536  }
537  case(filter2d::shift):{//shift
538  if(down_opt[0]!=1){
539  std::cerr << "Error: down option not supported for shift operator" << std::endl;
540  exit(1);
541  }
542  assert(input.nrOfBand());
543  assert(input.nrOfCol());
544  assert(input.nrOfRow());
545  try{
546  filter2d.shift(input,output,dimX_opt[0],dimY_opt[0],threshold_opt[0],filter2d::Filter2d::getResampleType(resample_opt[0]));
547  }
548  catch(string errorstring){
549  cerr << errorstring << endl;
550  }
551  break;
552  }
553  // case(filter2d::linearfeature):{
554  // if(down_opt[0]!=1){
555  // std::cerr << "Error: down option not supported for linear feature" << std::endl;
556  // exit(1);
557  // }
558  // assert(input.nrOfBand());
559  // assert(input.nrOfCol());
560  // assert(input.nrOfRow());
561  // float theAngle=361;
562  // if(angle_opt.size())
563  // theAngle=angle_opt[0];
564  // if(verbose_opt[0])
565  // std::cout << "using angle " << theAngle << std::endl;
566  // try{
567  // //using an angle step of 5 degrees and no maximum distance
568  // 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]);
569  // }
570  // catch(string errorstring){
571  // cerr << errorstring << endl;
572  // }
573  // break;
574  // }
575  case(filter2d::mrf):{//Markov Random Field
576  if(verbose_opt[0])
577  std::cout << "Markov Random Field filtering" << std::endl;
578  if(beta_opt.size()){
579  //in file: classFrom classTo
580  //in variable: beta[classTo][classFrom]
581  FileReaderAscii betaReader(beta_opt[0]);
582  Vector2d<double> beta(class_opt.size(),class_opt.size());
583  vector<int> cols(class_opt.size());
584  for(int iclass=0;iclass<class_opt.size();++iclass)
585  cols[iclass]=iclass;
586  betaReader.readData(beta,cols);
587  if(verbose_opt[0]){
588  std::cout << "using values for beta:" << std::endl;
589  for(int iclass1=0;iclass1<class_opt.size();++iclass1)
590  std::cout << " " << iclass1 << " (" << class_opt[iclass1] << ")";
591  std::cout << std::endl;
592  for(int iclass1=0;iclass1<class_opt.size();++iclass1){
593  std::cout << iclass1 << " (" << class_opt[iclass1] << ")";
594  for(int iclass2=0;iclass2<class_opt.size();++iclass2)
595  std::cout << " " << beta[iclass2][iclass1] << " (" << class_opt[iclass2] << ")";
596  std::cout << std::endl;
597  }
598  }
599  filter2d.mrf(input, output, dimX_opt[0], dimY_opt[0], beta, true, down_opt[0], verbose_opt[0]);
600  }
601  else
602  filter2d.mrf(input, output, dimX_opt[0], dimY_opt[0], 1, true, down_opt[0], verbose_opt[0]);
603  break;
604  }
605  case(filter2d::sobelx):{//Sobel edge detection in X
606  if(down_opt[0]!=1){
607  std::cerr << "Error: down option not supported for sobel edge detection" << std::endl;
608  exit(1);
609  }
610  Vector2d<double> theTaps(3,3);
611  theTaps[0][0]=-1.0;
612  theTaps[0][1]=0.0;
613  theTaps[0][2]=1.0;
614  theTaps[1][0]=-2.0;
615  theTaps[1][1]=0.0;
616  theTaps[1][2]=2.0;
617  theTaps[2][0]=-1.0;
618  theTaps[2][1]=0.0;
619  theTaps[2][2]=1.0;
620  filter2d.setTaps(theTaps);
621  filter2d.filter(input,output,true,true);//absolute and normalize
622  break;
623  }
624  case(filter2d::sobely):{//Sobel edge detection in Y
625  if(down_opt[0]!=1){
626  std::cerr << "Error: down option not supported for sobel edge detection" << std::endl;
627  exit(1);
628  }
629  Vector2d<double> theTaps(3,3);
630  theTaps[0][0]=1.0;
631  theTaps[0][1]=2.0;
632  theTaps[0][2]=1.0;
633  theTaps[1][0]=0.0;
634  theTaps[1][1]=0.0;
635  theTaps[1][2]=0.0;
636  theTaps[2][0]=-1.0;
637  theTaps[2][1]=-2.0;
638  theTaps[2][2]=-1.0;
639  filter2d.setTaps(theTaps);
640  filter2d.filter(input,output,true,true);//absolute and normalize
641  break;
642  }
643  case(filter2d::sobelxy):{//Sobel edge detection in XY
644  if(down_opt[0]!=1){
645  std::cerr << "Error: down option not supported for sobel edge detection" << std::endl;
646  exit(1);
647  }
648  Vector2d<double> theTaps(3,3);
649  theTaps[0][0]=0.0;
650  theTaps[0][1]=1.0;
651  theTaps[0][2]=2.0;
652  theTaps[1][0]=-1.0;
653  theTaps[1][1]=0.0;
654  theTaps[1][2]=1.0;
655  theTaps[2][0]=-2.0;
656  theTaps[2][1]=-1.0;
657  theTaps[2][2]=0.0;
658  filter2d.setTaps(theTaps);
659  filter2d.filter(input,output,true,true);//absolute and normalize
660  break;
661  }
662  case(filter2d::sobelyx):{//Sobel edge detection in XY
663  if(down_opt[0]!=1){
664  std::cerr << "Error: down option not supported for sobel edge detection" << std::endl;
665  exit(1);
666  }
667  Vector2d<double> theTaps(3,3);
668  theTaps[0][0]=2.0;
669  theTaps[0][1]=1.0;
670  theTaps[0][2]=0.0;
671  theTaps[1][0]=1.0;
672  theTaps[1][1]=0.0;
673  theTaps[1][2]=-1.0;
674  theTaps[2][0]=0.0;
675  theTaps[2][1]=-1.0;
676  theTaps[2][2]=-2.0;
677  filter2d.setTaps(theTaps);
678  filter2d.filter(input,output,true,true);//absolute and normalize
679  break;
680  }
681  case(filter2d::smooth):{//Smoothing filter
682  if(down_opt[0]!=1){
683  std::cerr << "Error: down option not supported for this filter" << std::endl;
684  exit(1);
685  }
686  if(dimZ_opt.size()){
687  if(verbose_opt[0])
688  std::cout<< "1-D filtering: smooth" << std::endl;
689  filter1d.smooth(input,output,dimZ_opt[0]);
690  }
691  else{
692  filter2d.smooth(input,output,dimX_opt[0],dimY_opt[0]);
693  }
694  break;
695  }
696  case(filter2d::smoothnodata):{//Smoothing filter
697  if(down_opt[0]!=1){
698  std::cerr << "Error: down option not supported for this filter" << std::endl;
699  exit(1);
700  }
701  if(dimZ_opt.size()){
702  if(verbose_opt[0])
703  std::cout<< "1-D filtering: smooth" << std::endl;
704  filter1d.smoothNoData(input,interpolationType_opt[0],output);
705  }
706  else
707  filter2d.smoothNoData(input,output,dimX_opt[0],dimY_opt[0]);
708  break;
709  }
710  case(filter2d::dwt):
711  if(down_opt[0]!=1){
712  std::cerr << "Error: down option not supported for this filter" << std::endl;
713  exit(1);
714  }
715  if(dimZ_opt.size()){
716  if(verbose_opt[0])
717  std::cout<< "DWT in spectral domain" << std::endl;
718  filter1d.dwtForward(input, output, wavelet_type_opt[0], family_opt[0]);
719  }
720  else
721  filter2d.dwtForward(input, output, wavelet_type_opt[0], family_opt[0]);
722  break;
723  case(filter2d::dwti):
724  if(down_opt[0]!=1){
725  std::cerr << "Error: down option not supported for this filter" << std::endl;
726  exit(1);
727  }
728  if(dimZ_opt.size()){
729  if(verbose_opt[0])
730  std::cout<< "inverse DWT in spectral domain" << std::endl;
731  filter1d.dwtInverse(input, output, wavelet_type_opt[0], family_opt[0]);
732  }
733  else
734  filter2d.dwtInverse(input, output, wavelet_type_opt[0], family_opt[0]);
735  break;
736  case(filter2d::dwt_cut):
737  if(down_opt[0]!=1){
738  std::cerr << "Error: down option not supported for this filter" << std::endl;
739  exit(1);
740  }
741  if(dimZ_opt.size()){
742  if(verbose_opt[0])
743  std::cout<< "DWT approximation in spectral domain" << std::endl;
744  filter1d.dwtCut(input, output, wavelet_type_opt[0], family_opt[0], threshold_opt[0]);
745  }
746  else
747  filter2d.dwtCut(input, output, wavelet_type_opt[0], family_opt[0], threshold_opt[0]);
748  break;
749  case(filter2d::dwt_cut_from):
750  if(down_opt[0]!=1){
751  std::cerr << "Error: down option not supported for this filter" << std::endl;
752  exit(1);
753  }
754  if(dimZ_opt.size()){
755  if(verbose_opt[0])
756  std::cout<< "DWT approximation in spectral domain" << std::endl;
757  filter1d.dwtCutFrom(input, output, wavelet_type_opt[0], family_opt[0], static_cast<int>(threshold_opt[0]));
758  }
759  else{
760  std::cerr << "Error: this filter is not supported in 2D" << std::endl;
761  exit(1);
762  }
763  break;
764  case(filter2d::savgolay):{
765  assert(savgolay_nl_opt.size());
766  assert(savgolay_nr_opt.size());
767  assert(savgolay_ld_opt.size());
768  assert(savgolay_m_opt.size());
769  if(verbose_opt[0])
770  std::cout << "Calculating Savitzky-Golay coefficients: " << endl;
771  filter1d.getSavGolayCoefficients(tapz_opt, input.nrOfBand(), savgolay_nl_opt[0], savgolay_nr_opt[0], savgolay_ld_opt[0], savgolay_m_opt[0]);
772  if(verbose_opt[0]){
773  std::cout << "taps (size is " << tapz_opt.size() << "): ";
774  for(int itap=0;itap<tapz_opt.size();++itap)
775  std::cout<< tapz_opt[itap] << " ";
776  std::cout<< std::endl;
777  }
778  filter1d.setTaps(tapz_opt);
779  filter1d.filter(input,output);
780  break;
781  }
782  case(filter2d::threshold):
783  filter2d.setThresholds(threshold_opt);//deliberate fall through
784  case(filter2d::density):
785  filter2d.setClasses(class_opt);//deliberate fall through
786  if(verbose_opt[0])
787  std::cout << "classes set" << std::endl;
788  default:
789  if(dimZ_opt.size()){
790  if(dimZ_opt[0]==1)
791  filter1d.stat(input,output,method_opt[0]);
792  else{
793  assert(down_opt[0]==1);//not implemented yet...
794  filter1d.filter(input,output,method_opt[0],dimZ_opt[0]);
795  }
796  }
797  else
798  filter2d.doit(input,output,method_opt[0],dimX_opt[0],dimY_opt[0],down_opt[0],disc_opt[0]);
799  break;
800  }
801  }
802  input.close();
803  output.close();
804  return 0;
805 }
STL namespace.