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