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