pktools  2.6.5
Processing Kernel for geospatial data
pksvm.cc
1 /**********************************************************************
2 pksvm.cc: classify raster image using Support Vector Machine
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 <stdlib.h>
21 #include <vector>
22 #include <map>
23 #include <algorithm>
24 #include "imageclasses/ImgReaderGdal.h"
25 #include "imageclasses/ImgWriterGdal.h"
26 #include "imageclasses/ImgReaderOgr.h"
27 #include "imageclasses/ImgWriterOgr.h"
28 #include "base/Optionpk.h"
29 #include "base/PosValue.h"
30 #include "algorithms/ConfusionMatrix.h"
31 #include "algorithms/svm.h"
32 
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
36 /******************************************************************************/
118 namespace svm{
119  enum SVM_TYPE {C_SVC=0, nu_SVC=1,one_class=2, epsilon_SVR=3, nu_SVR=4};
120  enum KERNEL_TYPE {linear=0,polynomial=1,radial=2,sigmoid=3};
121 }
122 
123 #define Malloc(type,n) (type *)malloc((n)*sizeof(type))
124 
125 using namespace std;
126 
127 int main(int argc, char *argv[])
128 {
129  vector<double> priors;
130 
131  //--------------------------- command line options ------------------------------------
132  Optionpk<string> input_opt("i", "input", "input image");
133  Optionpk<string> training_opt("t", "training", "Training vector file. A single vector file contains all training features (must be set as: b0, b1, b2,...) for all classes (class numbers identified by label option). Use multiple training files for bootstrap aggregation (alternative to the bag and bsize options, where a random subset is taken from a single training file)");
134  Optionpk<string> tlayer_opt("tln", "tln", "Training layer name(s)");
135  Optionpk<string> label_opt("label", "label", "Attribute name for class label in training vector file.","label");
136  Optionpk<unsigned int> balance_opt("bal", "balance", "Balance the input data to this number of samples for each class", 0);
137  Optionpk<bool> random_opt("random", "random", "Randomize training data for balancing and bagging", true, 2);
138  Optionpk<int> minSize_opt("min", "min", "If number of training pixels is less then min, do not take this class into account (0: consider all classes)", 0);
139  Optionpk<unsigned short> band_opt("b", "band", "Band index (starting from 0, either use band option or use start to end)");
140  Optionpk<unsigned short> bstart_opt("sband", "startband", "Start band sequence number");
141  Optionpk<unsigned short> bend_opt("eband", "endband", "End band sequence number");
142  Optionpk<double> offset_opt("offset", "offset", "Offset value for each spectral band input features: refl[band]=(DN[band]-offset[band])/scale[band]", 0.0);
143  Optionpk<double> scale_opt("scale", "scale", "Scale value for each spectral band input features: refl=(DN[band]-offset[band])/scale[band] (use 0 if scale min and max in each band to -1.0 and 1.0)", 0.0);
144  Optionpk<double> priors_opt("prior", "prior", "Prior probabilities for each class (e.g., -p 0.3 -p 0.3 -p 0.2 ). Used for input only (ignored for cross validation)", 0.0);
145  Optionpk<string> priorimg_opt("pim", "priorimg", "Prior probability image (multi-band img with band for each class","",2);
146  Optionpk<unsigned short> cv_opt("cv", "cv", "N-fold cross validation mode",0);
147  Optionpk<string> cmformat_opt("cmf","cmf","Format for confusion matrix (ascii or latex)","ascii");
148  Optionpk<std::string> svm_type_opt("svmt", "svmtype", "Type of SVM (C_SVC, nu_SVC,one_class, epsilon_SVR, nu_SVR)","C_SVC");
149  Optionpk<std::string> kernel_type_opt("kt", "kerneltype", "Type of kernel function (linear,polynomial,radial,sigmoid) ","radial");
150  Optionpk<unsigned short> kernel_degree_opt("kd", "kd", "Degree in kernel function",3);
151  Optionpk<float> gamma_opt("g", "gamma", "Gamma in kernel function",1.0);
152  Optionpk<float> coef0_opt("c0", "coef0", "Coef0 in kernel function",0);
153  Optionpk<float> ccost_opt("cc", "ccost", "The parameter C of C_SVC, epsilon_SVR, and nu_SVR",1000);
154  Optionpk<float> nu_opt("nu", "nu", "The parameter nu of nu_SVC, one_class SVM, and nu_SVR",0.5);
155  Optionpk<float> epsilon_loss_opt("eloss", "eloss", "The epsilon in loss function of epsilon_SVR",0.1);
156  Optionpk<int> cache_opt("cache", "cache", "Cache memory size in MB",100);
157  Optionpk<float> epsilon_tol_opt("etol", "etol", "The tolerance of termination criterion",0.001);
158  Optionpk<bool> shrinking_opt("shrink", "shrink", "Whether to use the shrinking heuristics",false);
159  Optionpk<bool> prob_est_opt("pe", "probest", "Whether to train a SVC or SVR model for probability estimates",true,2);
160  // Optionpk<bool> weight_opt("wi", "wi", "Set the parameter C of class i to weight*C, for C_SVC",true);
161  Optionpk<unsigned short> comb_opt("comb", "comb", "How to combine bootstrap aggregation classifiers (0: sum rule, 1: product rule, 2: max rule). Also used to aggregate classes with rc option.",0);
162  Optionpk<unsigned short> bag_opt("bag", "bag", "Number of bootstrap aggregations", 1);
163  Optionpk<int> bagSize_opt("bagsize", "bagsize", "Percentage of features used from available training features for each bootstrap aggregation (one size for all classes, or a different size for each class respectively", 100);
164  Optionpk<string> classBag_opt("cb", "classbag", "Output for each individual bootstrap aggregation");
165  Optionpk<string> mask_opt("m", "mask", "Only classify within specified mask (vector or raster). For raster mask, set nodata values with the option msknodata.");
166  Optionpk<short> msknodata_opt("msknodata", "msknodata", "Mask value(s) not to consider for classification (use negative values if only these values should be taken into account). Values will be taken over in classification image.", 0);
167  Optionpk<unsigned short> nodata_opt("nodata", "nodata", "Nodata value to put where image is masked as nodata", 0);
168  Optionpk<string> output_opt("o", "output", "Output classification image");
169  Optionpk<string> oformat_opt("of", "oformat", "Output image format (see also gdal_translate).","GTiff");
170  Optionpk<string> option_opt("co", "co", "Creation option for output file. Multiple options can be specified.");
171  Optionpk<string> colorTable_opt("ct", "ct", "Color table in ASCII format having 5 columns: id R G B ALFA (0: transparent, 255: solid)");
172  Optionpk<string> prob_opt("prob", "prob", "Probability image.");
173  Optionpk<string> entropy_opt("entropy", "entropy", "Entropy image (measure for uncertainty of classifier output","",2);
174  Optionpk<string> active_opt("active", "active", "Ogr output for active training sample.","",2);
175  Optionpk<string> ogrformat_opt("f", "f", "Output ogr format for active training sample","SQLite");
176  Optionpk<unsigned int> nactive_opt("na", "nactive", "Number of active training points",1);
177  Optionpk<string> classname_opt("c", "class", "List of class names.");
178  Optionpk<short> classvalue_opt("r", "reclass", "List of class values (use same order as in class opt).");
179  Optionpk<short> verbose_opt("v", "verbose", "Verbose level",0,2);
180 
181  oformat_opt.setHide(1);
182  option_opt.setHide(1);
183  band_opt.setHide(1);
184  bstart_opt.setHide(1);
185  bend_opt.setHide(1);
186  balance_opt.setHide(1);
187  minSize_opt.setHide(1);
188  bag_opt.setHide(1);
189  bagSize_opt.setHide(1);
190  comb_opt.setHide(1);
191  classBag_opt.setHide(1);
192  prob_opt.setHide(1);
193  priorimg_opt.setHide(1);
194  offset_opt.setHide(1);
195  scale_opt.setHide(1);
196  svm_type_opt.setHide(1);
197  kernel_type_opt.setHide(1);
198  kernel_degree_opt.setHide(1);
199  coef0_opt.setHide(1);
200  nu_opt.setHide(1);
201  epsilon_loss_opt.setHide(1);
202  cache_opt.setHide(1);
203  epsilon_tol_opt.setHide(1);
204  shrinking_opt.setHide(1);
205  prob_est_opt.setHide(1);
206  entropy_opt.setHide(1);
207  active_opt.setHide(1);
208  nactive_opt.setHide(1);
209  random_opt.setHide(1);
210 
211  verbose_opt.setHide(2);
212 
213  bool doProcess;//stop process when program was invoked with help option (-h --help)
214  try{
215  doProcess=training_opt.retrieveOption(argc,argv);
216  input_opt.retrieveOption(argc,argv);
217  output_opt.retrieveOption(argc,argv);
218  cv_opt.retrieveOption(argc,argv);
219  cmformat_opt.retrieveOption(argc,argv);
220  tlayer_opt.retrieveOption(argc,argv);
221  classname_opt.retrieveOption(argc,argv);
222  classvalue_opt.retrieveOption(argc,argv);
223  oformat_opt.retrieveOption(argc,argv);
224  ogrformat_opt.retrieveOption(argc,argv);
225  option_opt.retrieveOption(argc,argv);
226  colorTable_opt.retrieveOption(argc,argv);
227  label_opt.retrieveOption(argc,argv);
228  priors_opt.retrieveOption(argc,argv);
229  gamma_opt.retrieveOption(argc,argv);
230  ccost_opt.retrieveOption(argc,argv);
231  mask_opt.retrieveOption(argc,argv);
232  msknodata_opt.retrieveOption(argc,argv);
233  nodata_opt.retrieveOption(argc,argv);
234  // Advanced options
235  band_opt.retrieveOption(argc,argv);
236  bstart_opt.retrieveOption(argc,argv);
237  bend_opt.retrieveOption(argc,argv);
238  balance_opt.retrieveOption(argc,argv);
239  minSize_opt.retrieveOption(argc,argv);
240  bag_opt.retrieveOption(argc,argv);
241  bagSize_opt.retrieveOption(argc,argv);
242  comb_opt.retrieveOption(argc,argv);
243  classBag_opt.retrieveOption(argc,argv);
244  prob_opt.retrieveOption(argc,argv);
245  priorimg_opt.retrieveOption(argc,argv);
246  offset_opt.retrieveOption(argc,argv);
247  scale_opt.retrieveOption(argc,argv);
248  svm_type_opt.retrieveOption(argc,argv);
249  kernel_type_opt.retrieveOption(argc,argv);
250  kernel_degree_opt.retrieveOption(argc,argv);
251  coef0_opt.retrieveOption(argc,argv);
252  nu_opt.retrieveOption(argc,argv);
253  epsilon_loss_opt.retrieveOption(argc,argv);
254  cache_opt.retrieveOption(argc,argv);
255  epsilon_tol_opt.retrieveOption(argc,argv);
256  shrinking_opt.retrieveOption(argc,argv);
257  prob_est_opt.retrieveOption(argc,argv);
258  entropy_opt.retrieveOption(argc,argv);
259  active_opt.retrieveOption(argc,argv);
260  nactive_opt.retrieveOption(argc,argv);
261  verbose_opt.retrieveOption(argc,argv);
262  random_opt.retrieveOption(argc,argv);
263  }
264  catch(string predefinedString){
265  std::cout << predefinedString << std::endl;
266  exit(0);
267  }
268  if(!doProcess){
269  cout << endl;
270  cout << "Usage: pksvm -t training [-i input -o output] [-cv value]" << endl;
271  cout << endl;
272  std::cout << "short option -h shows basic options only, use long option --help to show all options" << std::endl;
273  exit(0);//help was invoked, stop processing
274  }
275 
276  if(entropy_opt[0]=="")
277  entropy_opt.clear();
278  if(active_opt[0]=="")
279  active_opt.clear();
280  if(priorimg_opt[0]=="")
281  priorimg_opt.clear();
282 
283 
284  std::map<std::string, svm::SVM_TYPE> svmMap;
285 
286  svmMap["C_SVC"]=svm::C_SVC;
287  svmMap["nu_SVC"]=svm::nu_SVC;
288  svmMap["one_class"]=svm::one_class;
289  svmMap["epsilon_SVR"]=svm::epsilon_SVR;
290  svmMap["nu_SVR"]=svm::nu_SVR;
291 
292  std::map<std::string, svm::KERNEL_TYPE> kernelMap;
293 
294  kernelMap["linear"]=svm::linear;
295  kernelMap["polynomial"]=svm::polynomial;
296  kernelMap["radial"]=svm::radial;
297  kernelMap["sigmoid;"]=svm::sigmoid;
298 
299  assert(training_opt.size());
300 
301  if(verbose_opt[0]>=1){
302  if(input_opt.size())
303  std::cout << "input filename: " << input_opt[0] << std::endl;
304  if(mask_opt.size())
305  std::cout << "mask filename: " << mask_opt[0] << std::endl;
306  std::cout << "training vector file: " << std::endl;
307  for(int ifile=0;ifile<training_opt.size();++ifile)
308  std::cout << training_opt[ifile] << std::endl;
309  std::cout << "verbose: " << verbose_opt[0] << std::endl;
310  }
311  unsigned short nbag=(training_opt.size()>1)?training_opt.size():bag_opt[0];
312  if(verbose_opt[0]>=1)
313  std::cout << "number of bootstrap aggregations: " << nbag << std::endl;
314 
315  ImgReaderOgr extentReader;
316  OGRLayer *readLayer;
317 
318  double ulx=0;
319  double uly=0;
320  double lrx=0;
321  double lry=0;
322 
323  bool maskIsVector=false;
324  if(mask_opt.size()){
325  try{
326  extentReader.open(mask_opt[0]);
327  maskIsVector=true;
328  readLayer = extentReader.getDataSource()->GetLayer(0);
329  if(!(extentReader.getExtent(ulx,uly,lrx,lry))){
330  cerr << "Error: could not get extent from " << mask_opt[0] << endl;
331  exit(1);
332  }
333  }
334  catch(string errorString){
335  maskIsVector=false;
336  }
337  }
338 
339  ImgWriterOgr activeWriter;
340  if(active_opt.size()){
341  prob_est_opt[0]=true;
342  ImgReaderOgr trainingReader(training_opt[0]);
343  activeWriter.open(active_opt[0],ogrformat_opt[0]);
344  activeWriter.createLayer(active_opt[0],trainingReader.getProjection(),wkbPoint,NULL);
345  activeWriter.copyFields(trainingReader);
346  }
347  vector<PosValue> activePoints(nactive_opt[0]);
348  for(int iactive=0;iactive<activePoints.size();++iactive){
349  activePoints[iactive].value=1.0;
350  activePoints[iactive].posx=0.0;
351  activePoints[iactive].posy=0.0;
352  }
353 
354  unsigned int totalSamples=0;
355  unsigned int nactive=0;
356  vector<struct svm_model*> svm(nbag);
357  vector<struct svm_parameter> param(nbag);
358 
359  short nclass=0;
360  int nband=0;
361  int startBand=2;//first two bands represent X and Y pos
362 
363  //normalize priors from command line
364  if(priors_opt.size()>1){//priors from argument list
365  priors.resize(priors_opt.size());
366  double normPrior=0;
367  for(short iclass=0;iclass<priors_opt.size();++iclass){
368  priors[iclass]=priors_opt[iclass];
369  normPrior+=priors[iclass];
370  }
371  //normalize
372  for(short iclass=0;iclass<priors_opt.size();++iclass)
373  priors[iclass]/=normPrior;
374  }
375 
376  //convert start and end band options to vector of band indexes
377  try{
378  if(bstart_opt.size()){
379  if(bend_opt.size()!=bstart_opt.size()){
380  string errorstring="Error: options for start and end band indexes must be provided as pairs, missing end band";
381  throw(errorstring);
382  }
383  band_opt.clear();
384  for(int ipair=0;ipair<bstart_opt.size();++ipair){
385  if(bend_opt[ipair]<=bstart_opt[ipair]){
386  string errorstring="Error: index for end band must be smaller then start band";
387  throw(errorstring);
388  }
389  for(int iband=bstart_opt[ipair];iband<=bend_opt[ipair];++iband)
390  band_opt.push_back(iband);
391  }
392  }
393  }
394  catch(string error){
395  cerr << error << std::endl;
396  exit(1);
397  }
398  //sort bands
399  if(band_opt.size())
400  std::sort(band_opt.begin(),band_opt.end());
401 
402  map<string,short> classValueMap;
403  vector<std::string> nameVector;
404  if(classname_opt.size()){
405  assert(classname_opt.size()==classvalue_opt.size());
406  for(int iclass=0;iclass<classname_opt.size();++iclass)
407  classValueMap[classname_opt[iclass]]=classvalue_opt[iclass];
408  }
409 
410  //----------------------------------- Training -------------------------------
412  vector< vector<double> > offset(nbag);
413  vector< vector<double> > scale(nbag);
414  map<string,Vector2d<float> > trainingMap;
415  vector< Vector2d<float> > trainingPixels;//[class][sample][band]
416  vector<string> fields;
417 
418  vector<struct svm_problem> prob(nbag);
419  vector<struct svm_node *> x_space(nbag);
420 
421  for(int ibag=0;ibag<nbag;++ibag){
422  //organize training data
423  if(ibag<training_opt.size()){//if bag contains new training pixels
424  trainingMap.clear();
425  trainingPixels.clear();
426  if(verbose_opt[0]>=1)
427  std::cout << "reading imageVector file " << training_opt[0] << std::endl;
428  try{
429  ImgReaderOgr trainingReaderBag(training_opt[ibag]);
430  if(band_opt.size())
431  totalSamples=trainingReaderBag.readDataImageOgr(trainingMap,fields,band_opt,label_opt[0],tlayer_opt,verbose_opt[0]);
432  else
433  totalSamples=trainingReaderBag.readDataImageOgr(trainingMap,fields,0,0,label_opt[0],tlayer_opt,verbose_opt[0]);
434  if(trainingMap.size()<2){
435  string errorstring="Error: could not read at least two classes from training file, did you provide class labels in training sample (see option label)?";
436  throw(errorstring);
437  }
438  trainingReaderBag.close();
439  }
440  catch(string error){
441  cerr << error << std::endl;
442  exit(1);
443  }
444  catch(std::exception& e){
445  std::cerr << "Error: ";
446  std::cerr << e.what() << std::endl;
447  std::cerr << CPLGetLastErrorMsg() << std::endl;
448  exit(1);
449  }
450  catch(...){
451  cerr << "error catched" << std::endl;
452  exit(1);
453  }
454 
455  //convert map to vector
456  // short iclass=0;
457  if(verbose_opt[0]>1)
458  std::cout << "training pixels: " << std::endl;
459  map<string,Vector2d<float> >::iterator mapit=trainingMap.begin();
460  while(mapit!=trainingMap.end()){
461  //delete small classes
462  if((mapit->second).size()<minSize_opt[0]){
463  trainingMap.erase(mapit);
464  continue;
465  }
466  trainingPixels.push_back(mapit->second);
467  if(verbose_opt[0]>1)
468  std::cout << mapit->first << ": " << (mapit->second).size() << " samples" << std::endl;
469  ++mapit;
470  }
471  if(!ibag){
472  nclass=trainingPixels.size();
473  if(classname_opt.size())
474  assert(nclass==classname_opt.size());
475  nband=trainingPixels[0][0].size()-2;//X and Y//trainingPixels[0][0].size();
476  }
477  else{
478  assert(nclass==trainingPixels.size());
479  assert(nband==trainingPixels[0][0].size()-2);
480  }
481 
482  //do not remove outliers here: could easily be obtained through ogr2ogr -where 'B2<110' output.shp input.shp
483  //balance training data
484  if(balance_opt[0]>0){
485  while(balance_opt.size()<nclass)
486  balance_opt.push_back(balance_opt.back());
487  if(random_opt[0])
488  srand(time(NULL));
489  totalSamples=0;
490  for(short iclass=0;iclass<nclass;++iclass){
491  if(trainingPixels[iclass].size()>balance_opt[iclass]){
492  while(trainingPixels[iclass].size()>balance_opt[iclass]){
493  int index=rand()%trainingPixels[iclass].size();
494  trainingPixels[iclass].erase(trainingPixels[iclass].begin()+index);
495  }
496  }
497  else{
498  int oldsize=trainingPixels[iclass].size();
499  for(int isample=trainingPixels[iclass].size();isample<balance_opt[iclass];++isample){
500  int index = rand()%oldsize;
501  trainingPixels[iclass].push_back(trainingPixels[iclass][index]);
502  }
503  }
504  totalSamples+=trainingPixels[iclass].size();
505  }
506  }
507 
508  //set scale and offset
509  offset[ibag].resize(nband);
510  scale[ibag].resize(nband);
511  if(offset_opt.size()>1)
512  assert(offset_opt.size()==nband);
513  if(scale_opt.size()>1)
514  assert(scale_opt.size()==nband);
515  for(int iband=0;iband<nband;++iband){
516  if(verbose_opt[0]>=1)
517  std::cout << "scaling for band" << iband << std::endl;
518  offset[ibag][iband]=(offset_opt.size()==1)?offset_opt[0]:offset_opt[iband];
519  scale[ibag][iband]=(scale_opt.size()==1)?scale_opt[0]:scale_opt[iband];
520  //search for min and maximum
521  if(scale[ibag][iband]<=0){
522  float theMin=trainingPixels[0][0][iband+startBand];
523  float theMax=trainingPixels[0][0][iband+startBand];
524  for(short iclass=0;iclass<nclass;++iclass){
525  for(int isample=0;isample<trainingPixels[iclass].size();++isample){
526  if(theMin>trainingPixels[iclass][isample][iband+startBand])
527  theMin=trainingPixels[iclass][isample][iband+startBand];
528  if(theMax<trainingPixels[iclass][isample][iband+startBand])
529  theMax=trainingPixels[iclass][isample][iband+startBand];
530  }
531  }
532  offset[ibag][iband]=theMin+(theMax-theMin)/2.0;
533  scale[ibag][iband]=(theMax-theMin)/2.0;
534  if(verbose_opt[0]>=1){
535  std::cout << "Extreme image values for band " << iband << ": [" << theMin << "," << theMax << "]" << std::endl;
536  std::cout << "Using offset, scale: " << offset[ibag][iband] << ", " << scale[ibag][iband] << std::endl;
537  std::cout << "scaled values for band " << iband << ": [" << (theMin-offset[ibag][iband])/scale[ibag][iband] << "," << (theMax-offset[ibag][iband])/scale[ibag][iband] << "]" << std::endl;
538  }
539  }
540  }
541  }
542  else{//use same offset and scale
543  offset[ibag].resize(nband);
544  scale[ibag].resize(nband);
545  for(int iband=0;iband<nband;++iband){
546  offset[ibag][iband]=offset[0][iband];
547  scale[ibag][iband]=scale[0][iband];
548  }
549  }
550 
551  if(!ibag){
552  if(priors_opt.size()==1){//default: equal priors for each class
553  priors.resize(nclass);
554  for(short iclass=0;iclass<nclass;++iclass)
555  priors[iclass]=1.0/nclass;
556  }
557  assert(priors_opt.size()==1||priors_opt.size()==nclass);
558 
559  //set bagsize for each class if not done already via command line
560  while(bagSize_opt.size()<nclass)
561  bagSize_opt.push_back(bagSize_opt.back());
562 
563  if(verbose_opt[0]>=1){
564  std::cout << "number of bands: " << nband << std::endl;
565  std::cout << "number of classes: " << nclass << std::endl;
566  if(priorimg_opt.empty()){
567  std::cout << "priors:";
568  for(short iclass=0;iclass<nclass;++iclass)
569  std::cout << " " << priors[iclass];
570  std::cout << std::endl;
571  }
572  }
573  map<string,Vector2d<float> >::iterator mapit=trainingMap.begin();
574  bool doSort=true;
575  try{
576  while(mapit!=trainingMap.end()){
577  nameVector.push_back(mapit->first);
578  if(classValueMap.size()){
579  //check if name in training is covered by classname_opt (values can not be 0)
580  if(classValueMap[mapit->first]>0){
581  if(cm.getClassIndex(type2string<short>(classValueMap[mapit->first]))<0){
582  cm.pushBackClassName(type2string<short>(classValueMap[mapit->first]),doSort);
583  }
584  }
585  else{
586  std::cerr << "Error: names in classname option are not complete, please check names in training vector and make sure classvalue is > 0" << std::endl;
587  exit(1);
588  }
589  }
590  else
591  cm.pushBackClassName(mapit->first,doSort);
592  ++mapit;
593  }
594  }
595  catch(BadConversion conversionString){
596  std::cerr << "Error: did you provide class pairs names (-c) and integer values (-r) for each class in training vector?" << std::endl;
597  exit(1);
598  }
599  if(classname_opt.empty()){
600  //std::cerr << "Warning: no class name and value pair provided for all " << nclass << " classes, using string2type<int> instead!" << std::endl;
601  for(int iclass=0;iclass<nclass;++iclass){
602  if(verbose_opt[0])
603  std::cout << iclass << " " << cm.getClass(iclass) << " -> " << string2type<short>(cm.getClass(iclass)) << std::endl;
604  classValueMap[cm.getClass(iclass)]=string2type<short>(cm.getClass(iclass));
605  }
606  }
607 
608  // if(priors_opt.size()==nameVector.size()){
609  // std::cerr << "Warning: please check if priors are provided in correct order!!!" << std::endl;
610  // for(int iclass=0;iclass<nameVector.size();++iclass)
611  // std::cerr << nameVector[iclass] << " " << priors_opt[iclass] << std::endl;
612  // }
613  }//if(!ibag)
614 
615  //Calculate features of training set
616  vector< Vector2d<float> > trainingFeatures(nclass);
617  for(short iclass=0;iclass<nclass;++iclass){
618  int nctraining=0;
619  if(verbose_opt[0]>=1)
620  std::cout << "calculating features for class " << iclass << std::endl;
621  if(random_opt[0])
622  srand(time(NULL));
623  nctraining=(bagSize_opt[iclass]<100)? trainingPixels[iclass].size()/100.0*bagSize_opt[iclass] : trainingPixels[iclass].size();//bagSize_opt[iclass] given in % of training size
624  if(nctraining<=0)
625  nctraining=1;
626  assert(nctraining<=trainingPixels[iclass].size());
627  int index=0;
628  if(bagSize_opt[iclass]<100)
629  random_shuffle(trainingPixels[iclass].begin(),trainingPixels[iclass].end());
630  if(verbose_opt[0]>1)
631  std::cout << "nctraining (class " << iclass << "): " << nctraining << std::endl;
632  trainingFeatures[iclass].resize(nctraining);
633  for(int isample=0;isample<nctraining;++isample){
634  //scale pixel values according to scale and offset!!!
635  for(int iband=0;iband<nband;++iband){
636  float value=trainingPixels[iclass][isample][iband+startBand];
637  trainingFeatures[iclass][isample].push_back((value-offset[ibag][iband])/scale[ibag][iband]);
638  }
639  }
640  assert(trainingFeatures[iclass].size()==nctraining);
641  }
642 
643  unsigned int nFeatures=trainingFeatures[0][0].size();
644  if(verbose_opt[0]>=1)
645  std::cout << "number of features: " << nFeatures << std::endl;
646  unsigned int ntraining=0;
647  for(short iclass=0;iclass<nclass;++iclass)
648  ntraining+=trainingFeatures[iclass].size();
649  if(verbose_opt[0]>=1)
650  std::cout << "training size over all classes: " << ntraining << std::endl;
651 
652  prob[ibag].l=ntraining;
653  prob[ibag].y = Malloc(double,prob[ibag].l);
654  prob[ibag].x = Malloc(struct svm_node *,prob[ibag].l);
655  x_space[ibag] = Malloc(struct svm_node,(nFeatures+1)*ntraining);
656  unsigned long int spaceIndex=0;
657  int lIndex=0;
658  for(short iclass=0;iclass<nclass;++iclass){
659  for(int isample=0;isample<trainingFeatures[iclass].size();++isample){
660  prob[ibag].x[lIndex]=&(x_space[ibag][spaceIndex]);
661  for(int ifeature=0;ifeature<nFeatures;++ifeature){
662  x_space[ibag][spaceIndex].index=ifeature+1;
663  x_space[ibag][spaceIndex].value=trainingFeatures[iclass][isample][ifeature];
664  ++spaceIndex;
665  }
666  x_space[ibag][spaceIndex++].index=-1;
667  prob[ibag].y[lIndex]=iclass;
668  ++lIndex;
669  }
670  }
671  assert(lIndex==prob[ibag].l);
672 
673  //set SVM parameters through command line options
674  param[ibag].svm_type = svmMap[svm_type_opt[0]];
675  param[ibag].kernel_type = kernelMap[kernel_type_opt[0]];
676  param[ibag].degree = kernel_degree_opt[0];
677  param[ibag].gamma = (gamma_opt[0]>0)? gamma_opt[0] : 1.0/nFeatures;
678  param[ibag].coef0 = coef0_opt[0];
679  param[ibag].nu = nu_opt[0];
680  param[ibag].cache_size = cache_opt[0];
681  param[ibag].C = ccost_opt[0];
682  param[ibag].eps = epsilon_tol_opt[0];
683  param[ibag].p = epsilon_loss_opt[0];
684  param[ibag].shrinking = (shrinking_opt[0])? 1 : 0;
685  param[ibag].probability = (prob_est_opt[0])? 1 : 0;
686  param[ibag].nr_weight = 0;//not used: I use priors and balancing
687  param[ibag].weight_label = NULL;
688  param[ibag].weight = NULL;
689  param[ibag].verbose=(verbose_opt[0]>1)? true:false;
690 
691  if(verbose_opt[0]>1)
692  std::cout << "checking parameters" << std::endl;
693  svm_check_parameter(&prob[ibag],&param[ibag]);
694  if(verbose_opt[0])
695  std::cout << "parameters ok, training" << std::endl;
696  svm[ibag]=svm_train(&prob[ibag],&param[ibag]);
697  if(verbose_opt[0]>1)
698  std::cout << "SVM is now trained" << std::endl;
699  if(cv_opt[0]>1){
700  if(verbose_opt[0]>1)
701  std::cout << "Cross validating" << std::endl;
702  double *target = Malloc(double,prob[ibag].l);
703  svm_cross_validation(&prob[ibag],&param[ibag],cv_opt[0],target);
704  assert(param[ibag].svm_type != EPSILON_SVR&&param[ibag].svm_type != NU_SVR);//only for regression
705 
706  for(int i=0;i<prob[ibag].l;i++){
707  string refClassName=nameVector[prob[ibag].y[i]];
708  string className=nameVector[target[i]];
709  if(classValueMap.size())
710  cm.incrementResult(type2string<short>(classValueMap[refClassName]),type2string<short>(classValueMap[className]),1.0/nbag);
711  else
712  cm.incrementResult(cm.getClass(prob[ibag].y[i]),cm.getClass(target[i]),1.0/nbag);
713  }
714  free(target);
715  }
716  // *NOTE* Because svm_model contains pointers to svm_problem, you can
717  // not free the memory used by svm_problem if you are still using the
718  // svm_model produced by svm_train().
719  }//for ibag
720  if(cv_opt[0]>1){
721  assert(cm.nReference());
722  cm.setFormat(cmformat_opt[0]);
723  cm.reportSE95(false);
724  std::cout << cm << std::endl;
725  // cout << "class #samples userAcc prodAcc" << endl;
726  // double se95_ua=0;
727  // double se95_pa=0;
728  // double se95_oa=0;
729  // double dua=0;
730  // double dpa=0;
731  // double doa=0;
732  // for(short iclass=0;iclass<cm.nClasses();++iclass){
733  // dua=cm.ua(cm.getClass(iclass),&se95_ua);
734  // dpa=cm.pa(cm.getClass(iclass),&se95_pa);
735  // cout << cm.getClass(iclass) << " " << cm.nReference(cm.getClass(iclass)) << " " << dua << " (" << se95_ua << ")" << " " << dpa << " (" << se95_pa << ")" << endl;
736  // }
737  // std::cout << "Kappa: " << cm.kappa() << std::endl;
738  // doa=cm.oa(&se95_oa);
739  // std::cout << "Overall Accuracy: " << 100*doa << " (" << 100*se95_oa << ")" << std::endl;
740  }
741 
742  //--------------------------------- end of training -----------------------------------
743  if(input_opt.empty())
744  exit(0);
745 
746  const char* pszMessage;
747  void* pProgressArg=NULL;
748  GDALProgressFunc pfnProgress=GDALTermProgress;
749  float progress=0;
750  if(!verbose_opt[0])
751  pfnProgress(progress,pszMessage,pProgressArg);
752  //-------------------------------- open image file ------------------------------------
753  bool inputIsRaster=false;
754  ImgReaderOgr imgReaderOgr;
755  try{
756  imgReaderOgr.open(input_opt[0]);
757  imgReaderOgr.close();
758  }
759  catch(string errorString){
760  inputIsRaster=true;
761  }
762  if(inputIsRaster){
763  ImgReaderGdal testImage;
764  try{
765  if(verbose_opt[0]>=1)
766  std::cout << "opening image " << input_opt[0] << std::endl;
767  testImage.open(input_opt[0]);
768  }
769  catch(string error){
770  cerr << error << std::endl;
771  exit(2);
772  }
773  ImgReaderGdal priorReader;
774  if(priorimg_opt.size()){
775  try{
776  if(verbose_opt[0]>=1)
777  std::cout << "opening prior image " << priorimg_opt[0] << std::endl;
778  priorReader.open(priorimg_opt[0]);
779  assert(priorReader.nrOfCol()==testImage.nrOfCol());
780  assert(priorReader.nrOfRow()==testImage.nrOfRow());
781  }
782  catch(string error){
783  cerr << error << std::endl;
784  exit(2);
785  }
786  catch(...){
787  cerr << "error catched" << std::endl;
788  exit(1);
789  }
790  }
791 
792  int nrow=testImage.nrOfRow();
793  int ncol=testImage.nrOfCol();
794  if(option_opt.findSubstring("INTERLEAVE=")==option_opt.end()){
795  string theInterleave="INTERLEAVE=";
796  theInterleave+=testImage.getInterleave();
797  option_opt.push_back(theInterleave);
798  }
799  vector<char> classOut(ncol);//classified line for writing to image file
800 
801  // assert(nband==testImage.nrOfBand());
802  ImgWriterGdal classImageBag;
803  ImgWriterGdal classImageOut;
804  ImgWriterGdal probImage;
805  ImgWriterGdal entropyImage;
806 
807  string imageType=testImage.getImageType();
808  if(oformat_opt.size())//default
809  imageType=oformat_opt[0];
810  try{
811  assert(output_opt.size());
812  if(verbose_opt[0]>=1)
813  std::cout << "opening class image for writing output " << output_opt[0] << std::endl;
814  if(classBag_opt.size()){
815  classImageBag.open(classBag_opt[0],ncol,nrow,nbag,GDT_Byte,imageType,option_opt);
816  classImageBag.GDALSetNoDataValue(nodata_opt[0]);
817  classImageBag.copyGeoTransform(testImage);
818  classImageBag.setProjection(testImage.getProjection());
819  }
820  classImageOut.open(output_opt[0],ncol,nrow,1,GDT_Byte,imageType,option_opt);
821  classImageOut.GDALSetNoDataValue(nodata_opt[0]);
822  classImageOut.copyGeoTransform(testImage);
823  classImageOut.setProjection(testImage.getProjection());
824  if(colorTable_opt.size())
825  classImageOut.setColorTable(colorTable_opt[0],0);
826  if(prob_opt.size()){
827  probImage.open(prob_opt[0],ncol,nrow,nclass,GDT_Byte,imageType,option_opt);
828  probImage.GDALSetNoDataValue(nodata_opt[0]);
829  probImage.copyGeoTransform(testImage);
830  probImage.setProjection(testImage.getProjection());
831  }
832  if(entropy_opt.size()){
833  entropyImage.open(entropy_opt[0],ncol,nrow,1,GDT_Byte,imageType,option_opt);
834  entropyImage.GDALSetNoDataValue(nodata_opt[0]);
835  entropyImage.copyGeoTransform(testImage);
836  entropyImage.setProjection(testImage.getProjection());
837  }
838  }
839  catch(string error){
840  cerr << error << std::endl;
841  }
842 
843  ImgWriterGdal maskWriter;
844 
845  if(maskIsVector){
846  try{
847  maskWriter.open("/vsimem/mask.tif",ncol,nrow,1,GDT_Float32,imageType,option_opt);
848  maskWriter.GDALSetNoDataValue(nodata_opt[0]);
849  maskWriter.copyGeoTransform(testImage);
850  maskWriter.setProjection(testImage.getProjection());
851  vector<double> burnValues(1,1);//burn value is 1 (single band)
852  maskWriter.rasterizeOgr(extentReader,burnValues);
853  extentReader.close();
854  maskWriter.close();
855  }
856  catch(string error){
857  cerr << error << std::endl;
858  exit(2);
859  }
860  catch(...){
861  cerr << "error catched" << std::endl;
862  exit(1);
863  }
864  mask_opt.clear();
865  mask_opt.push_back("/vsimem/mask.tif");
866  }
867  ImgReaderGdal maskReader;
868  if(mask_opt.size()){
869  try{
870  if(verbose_opt[0]>=1)
871  std::cout << "opening mask image file " << mask_opt[0] << std::endl;
872  maskReader.open(mask_opt[0]);
873  }
874  catch(string error){
875  cerr << error << std::endl;
876  exit(2);
877  }
878  catch(...){
879  cerr << "error catched" << std::endl;
880  exit(1);
881  }
882  }
883 
884  for(int iline=0;iline<nrow;++iline){
885  vector<float> buffer(ncol);
886  vector<short> lineMask;
887  Vector2d<float> linePrior;
888  if(priorimg_opt.size())
889  linePrior.resize(nclass,ncol);//prior prob for each class
890  Vector2d<float> hpixel(ncol);
891  Vector2d<float> probOut(nclass,ncol);//posterior prob for each (internal) class
892  vector<float> entropy(ncol);
893  Vector2d<char> classBag;//classified line for writing to image file
894  if(classBag_opt.size())
895  classBag.resize(nbag,ncol);
896  try{
897  if(band_opt.size()){
898  for(int iband=0;iband<band_opt.size();++iband){
899  if(verbose_opt[0]==2)
900  std::cout << "reading band " << band_opt[iband] << std::endl;
901  assert(band_opt[iband]>=0);
902  assert(band_opt[iband]<testImage.nrOfBand());
903  testImage.readData(buffer,GDT_Float32,iline,band_opt[iband]);
904  for(int icol=0;icol<ncol;++icol)
905  hpixel[icol].push_back(buffer[icol]);
906  }
907  }
908  else{
909  for(int iband=0;iband<nband;++iband){
910  if(verbose_opt[0]==2)
911  std::cout << "reading band " << iband << std::endl;
912  assert(iband>=0);
913  assert(iband<testImage.nrOfBand());
914  testImage.readData(buffer,GDT_Float32,iline,iband);
915  for(int icol=0;icol<ncol;++icol)
916  hpixel[icol].push_back(buffer[icol]);
917  }
918  }
919  }
920  catch(string theError){
921  cerr << "Error reading " << input_opt[0] << ": " << theError << std::endl;
922  exit(3);
923  }
924  catch(...){
925  cerr << "error catched" << std::endl;
926  exit(3);
927  }
928  assert(nband==hpixel[0].size());
929  if(verbose_opt[0]>1)
930  std::cout << "used bands: " << nband << std::endl;
931  //read prior
932  if(priorimg_opt.size()){
933  try{
934  for(short iclass=0;iclass<nclass;++iclass){
935  if(verbose_opt.size()>1)
936  std::cout << "Reading " << priorimg_opt[0] << " band " << iclass << " line " << iline << std::endl;
937  priorReader.readData(linePrior[iclass],GDT_Float32,iline,iclass);
938  }
939  }
940  catch(string theError){
941  std::cerr << "Error reading " << priorimg_opt[0] << ": " << theError << std::endl;
942  exit(3);
943  }
944  catch(...){
945  cerr << "error catched" << std::endl;
946  exit(3);
947  }
948  }
949  double oldRowMask=-1;//keep track of row mask to optimize number of line readings
950  //process per pixel
951  for(int icol=0;icol<ncol;++icol){
952  assert(hpixel[icol].size()==nband);
953  bool doClassify=true;
954  bool masked=false;
955  double geox=0;
956  double geoy=0;
957  if(maskIsVector){
958  doClassify=false;
959  testImage.image2geo(icol,iline,geox,geoy);
960  //check enveloppe first
961  if(uly>=geoy&&lry<=geoy&&ulx<=geox&&lrx>=geox){
962  doClassify=true;
963  }
964  }
965  if(mask_opt.size()){
966  //read mask
967  double colMask=0;
968  double rowMask=0;
969 
970  testImage.image2geo(icol,iline,geox,geoy);
971  maskReader.geo2image(geox,geoy,colMask,rowMask);
972  colMask=static_cast<int>(colMask);
973  rowMask=static_cast<int>(rowMask);
974  if(rowMask>=0&&rowMask<maskReader.nrOfRow()&&colMask>=0&&colMask<maskReader.nrOfCol()){
975  if(static_cast<int>(rowMask)!=static_cast<int>(oldRowMask)){
976  assert(rowMask>=0&&rowMask<maskReader.nrOfRow());
977  try{
978  // maskReader.readData(lineMask[imask],GDT_Int32,static_cast<int>(rowMask));
979  maskReader.readData(lineMask,GDT_Int16,static_cast<int>(rowMask));
980  }
981  catch(string errorstring){
982  cerr << errorstring << endl;
983  exit(1);
984  }
985  catch(...){
986  cerr << "error catched" << std::endl;
987  exit(3);
988  }
989  oldRowMask=rowMask;
990  }
991  short theMask=0;
992  for(short ivalue=0;ivalue<msknodata_opt.size();++ivalue){
993  if(msknodata_opt[ivalue]>=0){//values set in msknodata_opt are invalid
994  if(lineMask[colMask]==msknodata_opt[ivalue]){
995  theMask=lineMask[colMask];
996  masked=true;
997  break;
998  }
999  }
1000  else{//only values set in msknodata_opt are valid
1001  if(lineMask[colMask]!=-msknodata_opt[ivalue]){
1002  theMask=lineMask[colMask];
1003  masked=true;
1004  }
1005  else{
1006  masked=false;
1007  break;
1008  }
1009  }
1010  }
1011  if(masked){
1012  if(classBag_opt.size())
1013  for(int ibag=0;ibag<nbag;++ibag)
1014  classBag[ibag][icol]=theMask;
1015  classOut[icol]=theMask;
1016  continue;
1017  }
1018  }
1019  bool valid=false;
1020  for(int iband=0;iband<hpixel[icol].size();++iband){
1021  if(hpixel[icol][iband]){
1022  valid=true;
1023  break;
1024  }
1025  }
1026  if(!valid)
1027  doClassify=false;
1028  }
1029  for(short iclass=0;iclass<nclass;++iclass)
1030  probOut[iclass][icol]=0;
1031  if(!doClassify){
1032  if(classBag_opt.size())
1033  for(int ibag=0;ibag<nbag;++ibag)
1034  classBag[ibag][icol]=nodata_opt[0];
1035  classOut[icol]=nodata_opt[0];
1036  continue;//next column
1037  }
1038  if(verbose_opt[0]>1)
1039  std::cout << "begin classification " << std::endl;
1040  //----------------------------------- classification -------------------
1041  for(int ibag=0;ibag<nbag;++ibag){
1042  vector<double> result(nclass);
1043  struct svm_node *x;
1044  x = (struct svm_node *) malloc((nband+1)*sizeof(struct svm_node));
1045  for(int iband=0;iband<nband;++iband){
1046  x[iband].index=iband+1;
1047  x[iband].value=(hpixel[icol][iband]-offset[ibag][iband])/scale[ibag][iband];
1048  }
1049  x[nband].index=-1;//to end svm feature vector
1050  double predict_label=0;
1051  vector<float> prValues(nclass);
1052  float maxP=0;
1053  if(!prob_est_opt[0]){
1054  predict_label = svm_predict(svm[ibag],x);
1055  for(short iclass=0;iclass<nclass;++iclass){
1056  if(iclass==static_cast<short>(predict_label))
1057  result[iclass]=1;
1058  else
1059  result[iclass]=0;
1060  }
1061  }
1062  else{
1063  assert(svm_check_probability_model(svm[ibag]));
1064  predict_label = svm_predict_probability(svm[ibag],x,&(result[0]));
1065  }
1066  //calculate posterior prob of bag
1067  if(classBag_opt.size()){
1068  //search for max prob within bag
1069  maxP=0;
1070  classBag[ibag][icol]=0;
1071  }
1072  double normPrior=0;
1073  if(priorimg_opt.size()){
1074  for(short iclass=0;iclass<nclass;++iclass)
1075  normPrior+=linePrior[iclass][icol];
1076  }
1077  for(short iclass=0;iclass<nclass;++iclass){
1078  if(priorimg_opt.size())
1079  priors[iclass]=linePrior[iclass][icol]/normPrior;//todo: check if correct for all cases... (automatic classValueMap and manual input for names and values)
1080  switch(comb_opt[0]){
1081  default:
1082  case(0)://sum rule
1083  probOut[iclass][icol]+=result[iclass]*priors[iclass];//add probabilities for each bag
1084  break;
1085  case(1)://product rule
1086  probOut[iclass][icol]*=pow(static_cast<float>(priors[iclass]),static_cast<float>(1.0-nbag)/nbag)*result[iclass];//multiply probabilities for each bag
1087  break;
1088  case(2)://max rule
1089  if(priors[iclass]*result[iclass]>probOut[iclass][icol])
1090  probOut[iclass][icol]=priors[iclass]*result[iclass];
1091  break;
1092  }
1093  if(classBag_opt.size()){
1094  //search for max prob within bag
1095  // if(prValues[iclass]>maxP){
1096  // maxP=prValues[iclass];
1097  // classBag[ibag][icol]=iclass;
1098  // }
1099  if(result[iclass]>maxP){
1100  maxP=result[iclass];
1101  classBag[ibag][icol]=iclass;
1102  }
1103  }
1104  }
1105  free(x);
1106  }//ibag
1107 
1108  //search for max class prob
1109  float maxBag1=0;//max probability
1110  float maxBag2=0;//second max probability
1111  float normBag=0;
1112  for(short iclass=0;iclass<nclass;++iclass){
1113  if(probOut[iclass][icol]>maxBag1){
1114  maxBag1=probOut[iclass][icol];
1115  classOut[icol]=classValueMap[nameVector[iclass]];
1116  }
1117  else if(probOut[iclass][icol]>maxBag2)
1118  maxBag2=probOut[iclass][icol];
1119  normBag+=probOut[iclass][icol];
1120  }
1121  //normalize probOut and convert to percentage
1122  entropy[icol]=0;
1123  for(short iclass=0;iclass<nclass;++iclass){
1124  float prv=probOut[iclass][icol];
1125  prv/=normBag;
1126  entropy[icol]-=prv*log(prv)/log(2.0);
1127  prv*=100.0;
1128 
1129  probOut[iclass][icol]=static_cast<short>(prv+0.5);
1130  // assert(classValueMap[nameVector[iclass]]<probOut.size());
1131  // assert(classValueMap[nameVector[iclass]]>=0);
1132  // probOut[classValueMap[nameVector[iclass]]][icol]=static_cast<short>(prv+0.5);
1133  }
1134  entropy[icol]/=log(static_cast<double>(nclass))/log(2.0);
1135  entropy[icol]=static_cast<short>(100*entropy[icol]+0.5);
1136  if(active_opt.size()){
1137  if(entropy[icol]>activePoints.back().value){
1138  activePoints.back().value=entropy[icol];//replace largest value (last)
1139  activePoints.back().posx=icol;
1140  activePoints.back().posy=iline;
1141  std::sort(activePoints.begin(),activePoints.end(),Decrease_PosValue());//sort in descending order (largest first, smallest last)
1142  if(verbose_opt[0])
1143  std::cout << activePoints.back().posx << " " << activePoints.back().posy << " " << activePoints.back().value << std::endl;
1144  }
1145  }
1146  }//icol
1147  //----------------------------------- write output ------------------------------------------
1148  if(classBag_opt.size())
1149  for(int ibag=0;ibag<nbag;++ibag)
1150  classImageBag.writeData(classBag[ibag],GDT_Byte,iline,ibag);
1151  if(prob_opt.size()){
1152  for(short iclass=0;iclass<nclass;++iclass)
1153  probImage.writeData(probOut[iclass],GDT_Float32,iline,iclass);
1154  }
1155  if(entropy_opt.size()){
1156  entropyImage.writeData(entropy,GDT_Float32,iline);
1157  }
1158  classImageOut.writeData(classOut,GDT_Byte,iline);
1159  if(!verbose_opt[0]){
1160  progress=static_cast<float>(iline+1.0)/classImageOut.nrOfRow();
1161  pfnProgress(progress,pszMessage,pProgressArg);
1162  }
1163  }
1164  //write active learning points
1165  if(active_opt.size()){
1166  for(int iactive=0;iactive<activePoints.size();++iactive){
1167  std::map<string,double> pointMap;
1168  for(int iband=0;iband<testImage.nrOfBand();++iband){
1169  double value;
1170  testImage.readData(value,GDT_Float64,static_cast<int>(activePoints[iactive].posx),static_cast<int>(activePoints[iactive].posy),iband);
1171  ostringstream fs;
1172  fs << "B" << iband;
1173  pointMap[fs.str()]=value;
1174  }
1175  pointMap[label_opt[0]]=0;
1176  double x, y;
1177  testImage.image2geo(activePoints[iactive].posx,activePoints[iactive].posy,x,y);
1178  std::string fieldname="id";//number of the point
1179  activeWriter.addPoint(x,y,pointMap,fieldname,++nactive);
1180  }
1181  }
1182 
1183  testImage.close();
1184  if(mask_opt.size())
1185  maskReader.close();
1186  if(priorimg_opt.size())
1187  priorReader.close();
1188  if(prob_opt.size())
1189  probImage.close();
1190  if(entropy_opt.size())
1191  entropyImage.close();
1192  if(classBag_opt.size())
1193  classImageBag.close();
1194  classImageOut.close();
1195  }
1196  else{//classify vector file
1197  cm.clearResults();
1198  //notice that fields have already been set by readDataImageOgr (taking into account appropriate bands)
1199  for(int ivalidation=0;ivalidation<input_opt.size();++ivalidation){
1200  if(output_opt.size())
1201  assert(output_opt.size()==input_opt.size());
1202  if(verbose_opt[0])
1203  std::cout << "opening img reader " << input_opt[ivalidation] << std::endl;
1204  imgReaderOgr.open(input_opt[ivalidation]);
1205  ImgWriterOgr imgWriterOgr;
1206 
1207  if(output_opt.size()){
1208  if(verbose_opt[0])
1209  std::cout << "opening img writer and copying fields from img reader" << output_opt[ivalidation] << std::endl;
1210  imgWriterOgr.open(output_opt[ivalidation],imgReaderOgr);
1211  }
1212  if(verbose_opt[0])
1213  cout << "number of layers in input ogr file: " << imgReaderOgr.getLayerCount() << endl;
1214  for(int ilayer=0;ilayer<imgReaderOgr.getLayerCount();++ilayer){
1215  if(verbose_opt[0])
1216  cout << "processing input layer " << ilayer << endl;
1217  if(output_opt.size()){
1218  if(verbose_opt[0])
1219  std::cout << "creating field class" << std::endl;
1220  if(classValueMap.size())
1221  imgWriterOgr.createField("class",OFTInteger,ilayer);
1222  else
1223  imgWriterOgr.createField("class",OFTString,ilayer);
1224  }
1225  unsigned int nFeatures=imgReaderOgr.getFeatureCount(ilayer);
1226  unsigned int ifeature=0;
1227  progress=0;
1228  pfnProgress(progress,pszMessage,pProgressArg);
1229  OGRFeature *poFeature;
1230  while( (poFeature = imgReaderOgr.getLayer(ilayer)->GetNextFeature()) != NULL ){
1231  if(verbose_opt[0]>1)
1232  std::cout << "feature " << ifeature << std::endl;
1233  if( poFeature == NULL ){
1234  cout << "Warning: could not read feature " << ifeature << " in layer " << imgReaderOgr.getLayerName(ilayer) << endl;
1235  continue;
1236  }
1237  OGRFeature *poDstFeature = NULL;
1238  if(output_opt.size()){
1239  poDstFeature=imgWriterOgr.createFeature(ilayer);
1240  if( poDstFeature->SetFrom( poFeature, TRUE ) != OGRERR_NONE ){
1241  CPLError( CE_Failure, CPLE_AppDefined,
1242  "Unable to translate feature %d from layer %s.\n",
1243  poFeature->GetFID(), imgWriterOgr.getLayerName(ilayer).c_str() );
1244  OGRFeature::DestroyFeature( poFeature );
1245  OGRFeature::DestroyFeature( poDstFeature );
1246  }
1247  }
1248  vector<float> validationPixel;
1249  vector<float> validationFeature;
1250 
1251  imgReaderOgr.readData(validationPixel,OFTReal,fields,poFeature,ilayer);
1252  assert(validationPixel.size()==nband);
1253  vector<float> probOut(nclass);//posterior prob for each class
1254  for(short iclass=0;iclass<nclass;++iclass)
1255  probOut[iclass]=0;
1256  for(int ibag=0;ibag<nbag;++ibag){
1257  for(int iband=0;iband<nband;++iband){
1258  validationFeature.push_back((validationPixel[iband]-offset[ibag][iband])/scale[ibag][iband]);
1259  if(verbose_opt[0]==2)
1260  std::cout << " " << validationFeature.back();
1261  }
1262  if(verbose_opt[0]==2)
1263  std::cout << std::endl;
1264  vector<double> result(nclass);
1265  struct svm_node *x;
1266  x = (struct svm_node *) malloc((validationFeature.size()+1)*sizeof(struct svm_node));
1267  for(int i=0;i<validationFeature.size();++i){
1268  x[i].index=i+1;
1269  x[i].value=validationFeature[i];
1270  }
1271 
1272  x[validationFeature.size()].index=-1;//to end svm feature vector
1273  double predict_label=0;
1274  if(!prob_est_opt[0]){
1275  predict_label = svm_predict(svm[ibag],x);
1276  for(short iclass=0;iclass<nclass;++iclass){
1277  if(iclass==static_cast<short>(predict_label))
1278  result[iclass]=1;
1279  else
1280  result[iclass]=0;
1281  }
1282  }
1283  else{
1284  assert(svm_check_probability_model(svm[ibag]));
1285  predict_label = svm_predict_probability(svm[ibag],x,&(result[0]));
1286  }
1287  if(verbose_opt[0]>1){
1288  std::cout << "predict_label: " << predict_label << std::endl;
1289  for(int iclass=0;iclass<result.size();++iclass)
1290  std::cout << result[iclass] << " ";
1291  std::cout << std::endl;
1292  }
1293 
1294  //calculate posterior prob of bag
1295  for(short iclass=0;iclass<nclass;++iclass){
1296  switch(comb_opt[0]){
1297  default:
1298  case(0)://sum rule
1299  probOut[iclass]+=result[iclass]*priors[iclass];//add probabilities for each bag
1300  break;
1301  case(1)://product rule
1302  probOut[iclass]*=pow(static_cast<float>(priors[iclass]),static_cast<float>(1.0-nbag)/nbag)*result[iclass];//multiply probabilities for each bag
1303  break;
1304  case(2)://max rule
1305  if(priors[iclass]*result[iclass]>probOut[iclass])
1306  probOut[iclass]=priors[iclass]*result[iclass];
1307  break;
1308  }
1309  }
1310  free(x);
1311  }//for ibag
1312 
1313  //search for max class prob
1314  float maxBag=0;
1315  float normBag=0;
1316  string classOut="Unclassified";
1317  for(short iclass=0;iclass<nclass;++iclass){
1318  if(verbose_opt[0]>1)
1319  std::cout << probOut[iclass] << " ";
1320  if(probOut[iclass]>maxBag){
1321  maxBag=probOut[iclass];
1322  classOut=nameVector[iclass];
1323  }
1324  }
1325  //look for class name
1326  if(verbose_opt[0]>1){
1327  if(classValueMap.size())
1328  std::cout << "->" << classValueMap[classOut] << std::endl;
1329  else
1330  std::cout << "->" << classOut << std::endl;
1331  }
1332  if(output_opt.size()){
1333  if(classValueMap.size())
1334  poDstFeature->SetField("class",classValueMap[classOut]);
1335  else
1336  poDstFeature->SetField("class",classOut.c_str());
1337  poDstFeature->SetFID( poFeature->GetFID() );
1338  }
1339  int labelIndex=poFeature->GetFieldIndex(label_opt[0].c_str());
1340  if(labelIndex>=0){
1341  string classRef=poFeature->GetFieldAsString(labelIndex);
1342  if(classRef!="0"){
1343  if(classValueMap.size())
1344  cm.incrementResult(type2string<short>(classValueMap[classRef]),type2string<short>(classValueMap[classOut]),1);
1345  else
1346  cm.incrementResult(classRef,classOut,1);
1347  }
1348  }
1349  CPLErrorReset();
1350  if(output_opt.size()){
1351  if(imgWriterOgr.createFeature(poDstFeature,ilayer) != OGRERR_NONE){
1352  CPLError( CE_Failure, CPLE_AppDefined,
1353  "Unable to translate feature %d from layer %s.\n",
1354  poFeature->GetFID(), imgWriterOgr.getLayerName(ilayer).c_str() );
1355  OGRFeature::DestroyFeature( poDstFeature );
1356  OGRFeature::DestroyFeature( poDstFeature );
1357  }
1358  }
1359  ++ifeature;
1360  if(!verbose_opt[0]){
1361  progress=static_cast<float>(ifeature+1.0)/nFeatures;
1362  pfnProgress(progress,pszMessage,pProgressArg);
1363  }
1364  OGRFeature::DestroyFeature( poFeature );
1365  OGRFeature::DestroyFeature( poDstFeature );
1366  }//get next feature
1367  }//next layer
1368  imgReaderOgr.close();
1369  if(output_opt.size())
1370  imgWriterOgr.close();
1371  }
1372  if(cm.nReference()){
1373  std::cout << cm << std::endl;
1374  cout << "class #samples userAcc prodAcc" << endl;
1375  double se95_ua=0;
1376  double se95_pa=0;
1377  double se95_oa=0;
1378  double dua=0;
1379  double dpa=0;
1380  double doa=0;
1381  for(short iclass=0;iclass<cm.nClasses();++iclass){
1382  dua=cm.ua_pct(cm.getClass(iclass),&se95_ua);
1383  dpa=cm.pa_pct(cm.getClass(iclass),&se95_pa);
1384  cout << cm.getClass(iclass) << " " << cm.nReference(cm.getClass(iclass)) << " " << dua << " (" << se95_ua << ")" << " " << dpa << " (" << se95_pa << ")" << endl;
1385  }
1386  std::cout << "Kappa: " << cm.kappa() << std::endl;
1387  doa=cm.oa(&se95_oa);
1388  std::cout << "Overall Accuracy: " << 100*doa << " (" << 100*se95_oa << ")" << std::endl;
1389  }
1390  }
1391  try{
1392  if(active_opt.size())
1393  activeWriter.close();
1394  }
1395  catch(string errorString){
1396  std::cerr << "Error: errorString" << std::endl;
1397  }
1398 
1399  for(int ibag=0;ibag<nbag;++ibag){
1400  // svm_destroy_param[ibag](&param[ibag]);
1401  svm_destroy_param(&param[ibag]);
1402  free(prob[ibag].y);
1403  free(prob[ibag].x);
1404  free(x_space[ibag]);
1405  svm_free_and_destroy_model(&(svm[ibag]));
1406  }
1407  return 0;
1408 }
throw this class when syntax error in command line option
Definition: Optionpk.h:45
Definition: svm.h:12