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