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 "floatfann.h"
32 #include "algorithms/myfann_cpp.h"
110 int main(
int argc,
char *argv[])
112 vector<double> priors;
116 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)");
118 Optionpk<string> label_opt(
"label",
"label",
"identifier for class label in training vector file.",
"label");
119 Optionpk<unsigned int> balance_opt(
"bal",
"balance",
"balance the input data to this number of samples for each class", 0);
120 Optionpk<bool> random_opt(
"random",
"random",
"in case of balance, randomize input data",
true,2);
121 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);
122 Optionpk<unsigned short> band_opt(
"b",
"band",
"band index (starting from 0, either use band option or use start to end)");
125 Optionpk<double> offset_opt(
"offset",
"offset",
"offset value for each spectral band input features: refl[band]=(DN[band]-offset[band])/scale[band]", 0.0);
126 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);
127 Optionpk<unsigned short> aggreg_opt(
"a",
"aggreg",
"how to combine aggregated classifiers, see also rc option (1: sum rule, 2: max rule).",1);
128 Optionpk<double> priors_opt(
"prior",
"prior",
"prior probabilities for each class (e.g., -p 0.3 -p 0.3 -p 0.2 )", 0.0);
129 Optionpk<string> priorimg_opt(
"pim",
"priorimg",
"prior probability image (multi-band img with band for each class",
"",2);
131 Optionpk<string> cmformat_opt(
"cmf",
"cmf",
"Format for confusion matrix (ascii or latex)",
"ascii");
132 Optionpk<unsigned int> nneuron_opt(
"nn",
"nneuron",
"number of neurons in hidden layers in neural network (multiple hidden layers are set by defining multiple number of neurons: -n 15 -n 1, default is one hidden layer with 5 neurons)", 5);
133 Optionpk<float> connection_opt(
"\0",
"connection",
"connection reate (default: 1.0 for a fully connected network)", 1.0);
134 Optionpk<float> learning_opt(
"l",
"learning",
"learning rate (default: 0.7)", 0.7);
135 Optionpk<float> weights_opt(
"w",
"weights",
"weights for neural network. Apply to fully connected network only, starting from first input neuron to last output neuron, including the bias neurons (last neuron in each but last layer)", 0.0);
136 Optionpk<unsigned int> maxit_opt(
"\0",
"maxit",
"number of maximum iterations (epoch) (default: 500)", 500);
137 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. Default is sum rule (0)",0);
139 Optionpk<int> bagSize_opt(
"bs",
"bsize",
"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);
140 Optionpk<string> classBag_opt(
"cb",
"classbag",
"output for each individual bootstrap aggregation (default is blank)");
141 Optionpk<string> mask_opt(
"m",
"mask",
"Only classify within specified mask (vector or raster). For raster mask, set nodata values with the option msknodata.");
142 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. Default is 0", 0);
145 Optionpk<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");
146 Optionpk<string> oformat_opt(
"of",
"oformat",
"Output image format (see also gdal_translate).",
"GTiff");
147 Optionpk<string> option_opt(
"co",
"co",
"Creation option for output file. Multiple options can be specified.");
148 Optionpk<string> colorTable_opt(
"ct",
"ct",
"colour table in ASCII format having 5 columns: id R G B ALFA (0: transparent, 255: solid)");
149 Optionpk<string> prob_opt(
"\0",
"prob",
"probability image. Default is no probability image");
150 Optionpk<string> entropy_opt(
"entropy",
"entropy",
"entropy image (measure for uncertainty of classifier output",
"",2);
151 Optionpk<string> active_opt(
"active",
"active",
"ogr output for active training sample.",
"",2);
152 Optionpk<string> ogrformat_opt(
"f",
"f",
"Output ogr format for active training sample",
"SQLite");
155 Optionpk<short> classvalue_opt(
"r",
"reclass",
"list of class values (use same order as in class opt).");
156 Optionpk<short> verbose_opt(
"v",
"verbose",
"set to: 0 (results only), 1 (confusion matrix), 2 (debug)",0,2);
158 option_opt.setHide(1);
159 oformat_opt.setHide(1);
161 bstart_opt.setHide(1);
163 balance_opt.setHide(1);
164 minSize_opt.setHide(1);
166 bagSize_opt.setHide(1);
168 classBag_opt.setHide(1);
169 minSize_opt.setHide(1);
171 priorimg_opt.setHide(1);
172 minSize_opt.setHide(1);
173 offset_opt.setHide(1);
174 scale_opt.setHide(1);
175 connection_opt.setHide(1);
176 weights_opt.setHide(1);
177 maxit_opt.setHide(1);
178 learning_opt.setHide(1);
180 verbose_opt.setHide(2);
184 doProcess=input_opt.retrieveOption(argc,argv);
185 training_opt.retrieveOption(argc,argv);
186 tlayer_opt.retrieveOption(argc,argv);
187 label_opt.retrieveOption(argc,argv);
188 balance_opt.retrieveOption(argc,argv);
189 random_opt.retrieveOption(argc,argv);
190 minSize_opt.retrieveOption(argc,argv);
191 band_opt.retrieveOption(argc,argv);
192 bstart_opt.retrieveOption(argc,argv);
193 bend_opt.retrieveOption(argc,argv);
194 offset_opt.retrieveOption(argc,argv);
195 scale_opt.retrieveOption(argc,argv);
196 aggreg_opt.retrieveOption(argc,argv);
197 priors_opt.retrieveOption(argc,argv);
198 priorimg_opt.retrieveOption(argc,argv);
199 cv_opt.retrieveOption(argc,argv);
200 cmformat_opt.retrieveOption(argc,argv);
201 nneuron_opt.retrieveOption(argc,argv);
202 connection_opt.retrieveOption(argc,argv);
203 weights_opt.retrieveOption(argc,argv);
204 learning_opt.retrieveOption(argc,argv);
205 maxit_opt.retrieveOption(argc,argv);
206 comb_opt.retrieveOption(argc,argv);
207 bag_opt.retrieveOption(argc,argv);
208 bagSize_opt.retrieveOption(argc,argv);
209 classBag_opt.retrieveOption(argc,argv);
210 mask_opt.retrieveOption(argc,argv);
211 msknodata_opt.retrieveOption(argc,argv);
212 nodata_opt.retrieveOption(argc,argv);
213 output_opt.retrieveOption(argc,argv);
214 otype_opt.retrieveOption(argc,argv);
215 oformat_opt.retrieveOption(argc,argv);
216 colorTable_opt.retrieveOption(argc,argv);
217 option_opt.retrieveOption(argc,argv);
218 prob_opt.retrieveOption(argc,argv);
219 entropy_opt.retrieveOption(argc,argv);
220 active_opt.retrieveOption(argc,argv);
221 ogrformat_opt.retrieveOption(argc,argv);
222 nactive_opt.retrieveOption(argc,argv);
223 classname_opt.retrieveOption(argc,argv);
224 classvalue_opt.retrieveOption(argc,argv);
225 verbose_opt.retrieveOption(argc,argv);
227 catch(
string predefinedString){
228 std::cout << predefinedString << std::endl;
233 cout <<
"Usage: pkann -t training [-i input -o output] [-cv value]" << endl;
235 cout <<
"short option -h shows basic options only, use long option --help to show all options" << endl;
239 if(entropy_opt[0]==
"")
241 if(active_opt[0]==
"")
243 if(priorimg_opt[0]==
"")
244 priorimg_opt.clear();
246 if(verbose_opt[0]>=1){
248 cout <<
"image filename: " << input_opt[0] << endl;
250 cout <<
"mask filename: " << mask_opt[0] << endl;
251 if(training_opt.size()){
252 cout <<
"training vector file: " << endl;
253 for(
int ifile=0;ifile<training_opt.size();++ifile)
254 cout << training_opt[ifile] << endl;
257 cerr <<
"no training file set!" << endl;
258 cout <<
"verbose: " << verbose_opt[0] << endl;
260 unsigned short nbag=(training_opt.size()>1)?training_opt.size():bag_opt[0];
261 if(verbose_opt[0]>=1)
262 cout <<
"number of bootstrap aggregations: " << nbag << endl;
272 bool maskIsVector=
false;
275 extentReader.open(mask_opt[0]);
277 readLayer = extentReader.getDataSource()->GetLayer(0);
278 if(!(extentReader.getExtent(ulx,uly,lrx,lry))){
279 cerr <<
"Error: could not get extent from " << mask_opt[0] << endl;
283 catch(
string errorString){
289 if(active_opt.size()){
291 activeWriter.open(active_opt[0],ogrformat_opt[0]);
292 activeWriter.createLayer(active_opt[0],trainingReader.getProjection(),wkbPoint,NULL);
293 activeWriter.copyFields(trainingReader);
295 vector<PosValue> activePoints(nactive_opt[0]);
296 for(
int iactive=0;iactive<activePoints.size();++iactive){
297 activePoints[iactive].value=1.0;
298 activePoints[iactive].posx=0.0;
299 activePoints[iactive].posy=0.0;
302 unsigned int totalSamples=0;
303 unsigned int nactive=0;
304 vector<FANN::neural_net> net(nbag);
306 unsigned int nclass=0;
310 if(priors_opt.size()>1){
311 priors.resize(priors_opt.size());
313 for(
int iclass=0;iclass<priors_opt.size();++iclass){
314 priors[iclass]=priors_opt[iclass];
315 normPrior+=priors[iclass];
318 for(
int iclass=0;iclass<priors_opt.size();++iclass)
319 priors[iclass]/=normPrior;
324 if(bstart_opt.size()){
325 if(bend_opt.size()!=bstart_opt.size()){
326 string errorstring=
"Error: options for start and end band indexes must be provided as pairs, missing end band";
330 for(
int ipair=0;ipair<bstart_opt.size();++ipair){
331 if(bend_opt[ipair]<=bstart_opt[ipair]){
332 string errorstring=
"Error: index for end band must be smaller then start band";
335 for(
int iband=bstart_opt[ipair];iband<=bend_opt[ipair];++iband)
336 band_opt.push_back(iband);
341 cerr << error << std::endl;
346 std::sort(band_opt.begin(),band_opt.end());
348 map<string,short> classValueMap;
349 vector<std::string> nameVector;
350 if(classname_opt.size()){
351 assert(classname_opt.size()==classvalue_opt.size());
352 for(
int iclass=0;iclass<classname_opt.size();++iclass)
353 classValueMap[classname_opt[iclass]]=classvalue_opt[iclass];
357 vector< vector<double> > offset(nbag);
358 vector< vector<double> > scale(nbag);
359 map<string,Vector2d<float> > trainingMap;
360 vector< Vector2d<float> > trainingPixels;
361 vector<string> fields;
362 for(
int ibag=0;ibag<nbag;++ibag){
364 if(ibag<training_opt.size()){
366 trainingPixels.clear();
367 if(verbose_opt[0]>=1)
368 cout <<
"reading imageVector file " << training_opt[0] << endl;
372 totalSamples=trainingReaderBag.readDataImageOgr(trainingMap,fields,band_opt,label_opt[0],tlayer_opt,verbose_opt[0]);
374 totalSamples=trainingReaderBag.readDataImageOgr(trainingMap,fields,0,0,label_opt[0],tlayer_opt,verbose_opt[0]);
375 if(trainingMap.size()<2){
376 string errorstring=
"Error: could not read at least two classes from training file, did you provide class labels in training sample (see option label)?";
379 trainingReaderBag.close();
382 cerr << error << std::endl;
386 cerr <<
"error catched" << std::endl;
396 std::cout <<
"training pixels: " << std::endl;
397 map<string,Vector2d<float> >::iterator mapit=trainingMap.begin();
398 while(mapit!=trainingMap.end()){
400 if((mapit->second).size()<minSize_opt[0]){
401 trainingMap.erase(mapit);
404 trainingPixels.push_back(mapit->second);
406 std::cout << mapit->first <<
": " << (mapit->second).size() <<
" samples" << std::endl;
410 nclass=trainingPixels.size();
411 if(classname_opt.size())
412 assert(nclass==classname_opt.size());
413 nband=(training_opt.size())?trainingPixels[0][0].size()-2:trainingPixels[0][0].size();
416 assert(nclass==trainingPixels.size());
417 assert(nband==(training_opt.size())?trainingPixels[0][0].size()-2:trainingPixels[0][0].size());
422 if(balance_opt[0]>0){
423 while(balance_opt.size()<nclass)
424 balance_opt.push_back(balance_opt.back());
428 for(
int iclass=0;iclass<nclass;++iclass){
429 if(trainingPixels[iclass].size()>balance_opt[iclass]){
430 while(trainingPixels[iclass].size()>balance_opt[iclass]){
431 int index=rand()%trainingPixels[iclass].size();
432 trainingPixels[iclass].erase(trainingPixels[iclass].begin()+index);
436 int oldsize=trainingPixels[iclass].size();
437 for(
int isample=trainingPixels[iclass].size();isample<balance_opt[iclass];++isample){
438 int index = rand()%oldsize;
439 trainingPixels[iclass].push_back(trainingPixels[iclass][index]);
442 totalSamples+=trainingPixels[iclass].size();
447 offset[ibag].resize(nband);
448 scale[ibag].resize(nband);
449 if(offset_opt.size()>1)
450 assert(offset_opt.size()==nband);
451 if(scale_opt.size()>1)
452 assert(scale_opt.size()==nband);
453 for(
int iband=0;iband<nband;++iband){
454 if(verbose_opt[0]>=1)
455 cout <<
"scaling for band" << iband << endl;
456 offset[ibag][iband]=(offset_opt.size()==1)?offset_opt[0]:offset_opt[iband];
457 scale[ibag][iband]=(scale_opt.size()==1)?scale_opt[0]:scale_opt[iband];
459 if(scale[ibag][iband]<=0){
460 float theMin=trainingPixels[0][0][iband+startBand];
461 float theMax=trainingPixels[0][0][iband+startBand];
462 for(
int iclass=0;iclass<nclass;++iclass){
463 for(
int isample=0;isample<trainingPixels[iclass].size();++isample){
464 if(theMin>trainingPixels[iclass][isample][iband+startBand])
465 theMin=trainingPixels[iclass][isample][iband+startBand];
466 if(theMax<trainingPixels[iclass][isample][iband+startBand])
467 theMax=trainingPixels[iclass][isample][iband+startBand];
470 offset[ibag][iband]=theMin+(theMax-theMin)/2.0;
471 scale[ibag][iband]=(theMax-theMin)/2.0;
472 if(verbose_opt[0]>=1){
473 std::cout <<
"Extreme image values for band " << iband <<
": [" << theMin <<
"," << theMax <<
"]" << std::endl;
474 std::cout <<
"Using offset, scale: " << offset[ibag][iband] <<
", " << scale[ibag][iband] << std::endl;
475 std::cout <<
"scaled values for band " << iband <<
": [" << (theMin-offset[ibag][iband])/scale[ibag][iband] <<
"," << (theMax-offset[ibag][iband])/scale[ibag][iband] <<
"]" << std::endl;
481 offset[ibag].resize(nband);
482 scale[ibag].resize(nband);
483 for(
int iband=0;iband<nband;++iband){
484 offset[ibag][iband]=offset[0][iband];
485 scale[ibag][iband]=scale[0][iband];
490 if(priors_opt.size()==1){
491 priors.resize(nclass);
492 for(
int iclass=0;iclass<nclass;++iclass)
493 priors[iclass]=1.0/nclass;
495 assert(priors_opt.size()==1||priors_opt.size()==nclass);
498 while(bagSize_opt.size()<nclass)
499 bagSize_opt.push_back(bagSize_opt.back());
501 if(verbose_opt[0]>=1){
502 std::cout <<
"number of bands: " << nband << std::endl;
503 std::cout <<
"number of classes: " << nclass << std::endl;
504 std::cout <<
"priors:";
505 if(priorimg_opt.empty()){
506 for(
int iclass=0;iclass<nclass;++iclass)
507 std::cout <<
" " << priors[iclass];
508 std::cout << std::endl;
511 map<string,Vector2d<float> >::iterator mapit=trainingMap.begin();
513 while(mapit!=trainingMap.end()){
514 nameVector.push_back(mapit->first);
515 if(classValueMap.size()){
517 if(classValueMap[mapit->first]>0){
518 if(cm.getClassIndex(type2string<short>(classValueMap[mapit->first]))<0)
519 cm.pushBackClassName(type2string<short>(classValueMap[mapit->first]),doSort);
522 std::cerr <<
"Error: names in classname option are not complete, please check names in training vector and make sure classvalue is > 0" << std::endl;
527 cm.pushBackClassName(mapit->first,doSort);
530 if(classname_opt.empty()){
532 for(
int iclass=0;iclass<nclass;++iclass){
534 std::cout << iclass <<
" " << cm.getClass(iclass) <<
" -> " << string2type<short>(cm.getClass(iclass)) << std::endl;
535 classValueMap[cm.getClass(iclass)]=string2type<short>(cm.getClass(iclass));
538 if(priors_opt.size()==nameVector.size()){
539 std::cerr <<
"Warning: please check if priors are provided in correct order!!!" << std::endl;
540 for(
int iclass=0;iclass<nameVector.size();++iclass)
541 std::cerr << nameVector[iclass] <<
" " << priors_opt[iclass] << std::endl;
546 vector< Vector2d<float> > trainingFeatures(nclass);
547 for(
int iclass=0;iclass<nclass;++iclass){
549 if(verbose_opt[0]>=1)
550 cout <<
"calculating features for class " << iclass << endl;
553 nctraining=(bagSize_opt[iclass]<100)? trainingPixels[iclass].size()/100.0*bagSize_opt[iclass] : trainingPixels[iclass].size();
556 assert(nctraining<=trainingPixels[iclass].size());
558 if(bagSize_opt[iclass]<100)
559 random_shuffle(trainingPixels[iclass].begin(),trainingPixels[iclass].end());
561 trainingFeatures[iclass].resize(nctraining);
562 for(
int isample=0;isample<nctraining;++isample){
564 for(
int iband=0;iband<nband;++iband){
565 float value=trainingPixels[iclass][isample][iband+startBand];
566 trainingFeatures[iclass][isample].push_back((value-offset[ibag][iband])/scale[ibag][iband]);
569 assert(trainingFeatures[iclass].size()==nctraining);
572 unsigned int nFeatures=trainingFeatures[0][0].size();
573 unsigned int ntraining=0;
574 for(
int iclass=0;iclass<nclass;++iclass)
575 ntraining+=trainingFeatures[iclass].size();
577 const unsigned int num_layers = nneuron_opt.size()+2;
578 const float desired_error = 0.0003;
579 const unsigned int iterations_between_reports = (verbose_opt[0])? maxit_opt[0]+1:0;
580 if(verbose_opt[0]>=1){
581 cout <<
"number of features: " << nFeatures << endl;
582 cout <<
"creating artificial neural network with " << nneuron_opt.size() <<
" hidden layer, having " << endl;
583 for(
int ilayer=0;ilayer<nneuron_opt.size();++ilayer)
584 cout << nneuron_opt[ilayer] <<
" ";
585 cout <<
"neurons" << endl;
586 cout <<
"connection_opt[0]: " << connection_opt[0] << std::endl;
587 cout <<
"num_layers: " << num_layers << std::endl;
588 cout <<
"nFeatures: " << nFeatures << std::endl;
589 cout <<
"nneuron_opt[0]: " << nneuron_opt[0] << std::endl;
590 cout <<
"number of classes (nclass): " << nclass << std::endl;
595 unsigned int layers[3];
597 layers[1]=nneuron_opt[0];
599 net[ibag].create_sparse_array(connection_opt[0],num_layers,layers);
603 unsigned int layers[4];
605 layers[1]=nneuron_opt[0];
606 layers[2]=nneuron_opt[1];
612 net[ibag].create_sparse_array(connection_opt[0],num_layers,layers);
616 cerr <<
"Only 1 or 2 hidden layers are supported!" << endl;
620 if(verbose_opt[0]>=1)
621 cout <<
"network created" << endl;
623 net[ibag].set_learning_rate(learning_opt[0]);
628 net[ibag].set_activation_function_hidden(FANN::SIGMOID_SYMMETRIC_STEPWISE);
629 net[ibag].set_activation_function_output(FANN::SIGMOID_SYMMETRIC_STEPWISE);
635 if(verbose_opt[0]>=1){
636 cout << endl <<
"Network Type : ";
637 switch (net[ibag].get_network_type())
640 cout <<
"LAYER" << endl;
643 cout <<
"SHORTCUT" << endl;
646 cout <<
"UNKNOWN" << endl;
649 net[ibag].print_parameters();
654 std::cout <<
"cross validation" << std::endl;
655 vector<unsigned short> referenceVector;
656 vector<unsigned short> outputVector;
657 float rmse=net[ibag].cross_validation(trainingFeatures,
665 map<string,Vector2d<float> >::iterator mapit=trainingMap.begin();
666 for(
int isample=0;isample<referenceVector.size();++isample){
667 string refClassName=nameVector[referenceVector[isample]];
668 string className=nameVector[outputVector[isample]];
669 if(classValueMap.size())
670 cm.incrementResult(type2string<short>(classValueMap[refClassName]),type2string<short>(classValueMap[className]),1.0/nbag);
672 cm.incrementResult(cm.getClass(referenceVector[isample]),cm.getClass(outputVector[isample]),1.0/nbag);
676 if(verbose_opt[0]>=1)
677 cout << endl <<
"Set training data" << endl;
679 if(verbose_opt[0]>=1)
680 cout << endl <<
"Training network" << endl;
682 if(verbose_opt[0]>=1){
683 cout <<
"Max Epochs " << setw(8) << maxit_opt[0] <<
". "
684 <<
"Desired Error: " << left << desired_error << right << endl;
686 if(weights_opt.size()==net[ibag].get_total_connections()){
687 vector<fann_connection> convector;
688 net[ibag].get_connection_array(convector);
689 for(
int i_connection=0;i_connection<net[ibag].get_total_connections();++i_connection)
690 convector[i_connection].weight=weights_opt[i_connection];
691 net[ibag].set_weight_array(convector);
694 bool initWeights=
true;
695 net[ibag].train_on_data(trainingFeatures,ntraining,initWeights, maxit_opt[0],
696 iterations_between_reports, desired_error);
700 if(verbose_opt[0]>=2){
701 net[ibag].print_connections();
702 vector<fann_connection> convector;
703 net[ibag].get_connection_array(convector);
704 for(
int i_connection=0;i_connection<net[ibag].get_total_connections();++i_connection)
705 cout <<
"connection " << i_connection <<
": " << convector[i_connection].weight << endl;
710 assert(cm.nReference());
711 cm.setFormat(cmformat_opt[0]);
712 cm.reportSE95(
false);
713 std::cout << cm << std::endl;
714 cout <<
"class #samples userAcc prodAcc" << endl;
721 for(
int iclass=0;iclass<cm.nClasses();++iclass){
722 dua=cm.ua_pct(cm.getClass(iclass),&se95_ua);
723 dpa=cm.pa_pct(cm.getClass(iclass),&se95_pa);
724 cout << cm.getClass(iclass) <<
" " << cm.nReference(cm.getClass(iclass)) <<
" " << dua <<
" (" << se95_ua <<
")" <<
" " << dpa <<
" (" << se95_pa <<
")" << endl;
726 std::cout <<
"Kappa: " << cm.kappa() << std::endl;
727 doa=cm.oa_pct(&se95_oa);
728 std::cout <<
"Overall Accuracy: " << doa <<
" (" << se95_oa <<
")" << std::endl;
731 if(input_opt.empty())
734 const char* pszMessage;
735 void* pProgressArg=NULL;
736 GDALProgressFunc pfnProgress=GDALTermProgress;
739 bool inputIsRaster=
false;
742 imgReaderOgr.open(input_opt[0]);
743 imgReaderOgr.close();
745 catch(
string errorString){
752 if(verbose_opt[0]>=1)
753 cout <<
"opening image " << input_opt[0] << endl;
754 testImage.open(input_opt[0]);
757 cerr << error << endl;
761 if(priorimg_opt.size()){
763 if(verbose_opt[0]>=1)
764 std::cout <<
"opening prior image " << priorimg_opt[0] << std::endl;
765 priorReader.open(priorimg_opt[0]);
766 assert(priorReader.nrOfCol()==testImage.nrOfCol());
767 assert(priorReader.nrOfRow()==testImage.nrOfRow());
770 cerr << error << std::endl;
774 cerr <<
"error catched" << std::endl;
779 int nrow=testImage.nrOfRow();
780 int ncol=testImage.nrOfCol();
781 if(option_opt.findSubstring(
"INTERLEAVE=")==option_opt.end()){
782 string theInterleave=
"INTERLEAVE=";
783 theInterleave+=testImage.getInterleave();
784 option_opt.push_back(theInterleave);
786 vector<char> classOut(ncol);
795 if(oformat_opt.size())
796 imageType=oformat_opt[0];
799 if(verbose_opt[0]>=1)
800 cout <<
"opening class image for writing output " << output_opt[0] << endl;
801 if(classBag_opt.size()){
802 classImageBag.open(classBag_opt[0],ncol,nrow,nbag,GDT_Byte,imageType,option_opt);
803 classImageBag.GDALSetNoDataValue(nodata_opt[0]);
804 classImageBag.copyGeoTransform(testImage);
805 classImageBag.setProjection(testImage.getProjection());
807 classImageOut.open(output_opt[0],ncol,nrow,1,GDT_Byte,imageType,option_opt);
808 classImageOut.GDALSetNoDataValue(nodata_opt[0]);
809 classImageOut.copyGeoTransform(testImage);
810 classImageOut.setProjection(testImage.getProjection());
811 if(colorTable_opt.size())
812 classImageOut.setColorTable(colorTable_opt[0],0);
814 probImage.open(prob_opt[0],ncol,nrow,nclass,GDT_Byte,imageType,option_opt);
815 probImage.GDALSetNoDataValue(nodata_opt[0]);
816 probImage.copyGeoTransform(testImage);
817 probImage.setProjection(testImage.getProjection());
819 if(entropy_opt.size()){
820 entropyImage.open(entropy_opt[0],ncol,nrow,1,GDT_Byte,imageType,option_opt);
821 entropyImage.GDALSetNoDataValue(nodata_opt[0]);
822 entropyImage.copyGeoTransform(testImage);
823 entropyImage.setProjection(testImage.getProjection());
827 cerr << error << endl;
834 maskWriter.open(
"/vsimem/mask.tif",ncol,nrow,1,GDT_Float32,imageType,option_opt);
835 maskWriter.GDALSetNoDataValue(nodata_opt[0]);
836 maskWriter.copyGeoTransform(testImage);
837 maskWriter.setProjection(testImage.getProjection());
838 vector<double> burnValues(1,1);
839 maskWriter.rasterizeOgr(extentReader,burnValues);
840 extentReader.close();
844 cerr << error << std::endl;
848 cerr <<
"error catched" << std::endl;
852 mask_opt.push_back(
"/vsimem/mask.tif");
857 if(verbose_opt[0]>=1)
858 std::cout <<
"opening mask image file " << mask_opt[0] << std::endl;
859 maskReader.open(mask_opt[0]);
862 cerr << error << std::endl;
866 cerr <<
"error catched" << std::endl;
871 for(
int iline=0;iline<nrow;++iline){
872 vector<float> buffer(ncol);
873 vector<short> lineMask;
875 lineMask.resize(maskReader.nrOfCol());
877 if(priorimg_opt.size())
878 linePrior.resize(nclass,ncol);
882 vector<float> entropy(ncol);
884 if(classBag_opt.size())
885 classBag.resize(nbag,ncol);
889 for(
int iband=0;iband<band_opt.size();++iband){
890 if(verbose_opt[0]==2)
891 std::cout <<
"reading band " << band_opt[iband] << std::endl;
892 assert(band_opt[iband]>=0);
893 assert(band_opt[iband]<testImage.nrOfBand());
894 testImage.readData(buffer,GDT_Float32,iline,band_opt[iband]);
895 for(
int icol=0;icol<ncol;++icol)
896 hpixel[icol].push_back(buffer[icol]);
900 for(
int iband=0;iband<nband;++iband){
901 if(verbose_opt[0]==2)
902 std::cout <<
"reading band " << iband << std::endl;
904 assert(iband<testImage.nrOfBand());
905 testImage.readData(buffer,GDT_Float32,iline,iband);
906 for(
int icol=0;icol<ncol;++icol)
907 hpixel[icol].push_back(buffer[icol]);
911 catch(
string theError){
912 cerr <<
"Error reading " << input_opt[0] <<
": " << theError << std::endl;
916 cerr <<
"error catched" << std::endl;
919 assert(nband==hpixel[0].size());
920 if(verbose_opt[0]==2)
921 cout <<
"used bands: " << nband << endl;
923 if(priorimg_opt.size()){
925 for(
short iclass=0;iclass<nclass;++iclass){
926 if(verbose_opt.size()>1)
927 std::cout <<
"Reading " << priorimg_opt[0] <<
" band " << iclass <<
" line " << iline << std::endl;
928 priorReader.readData(linePrior[iclass],GDT_Float32,iline,iclass);
931 catch(
string theError){
932 std::cerr <<
"Error reading " << priorimg_opt[0] <<
": " << theError << std::endl;
936 cerr <<
"error catched" << std::endl;
940 double oldRowMask=-1;
942 for(
int icol=0;icol<ncol;++icol){
943 assert(hpixel[icol].size()==nband);
944 bool doClassify=
true;
950 testImage.image2geo(icol,iline,geox,geoy);
952 if(uly>=geoy&&lry<=geoy&&ulx<=geox&&lrx>=geox){
961 testImage.image2geo(icol,iline,geox,geoy);
962 maskReader.geo2image(geox,geoy,colMask,rowMask);
963 colMask=
static_cast<int>(colMask);
964 rowMask=
static_cast<int>(rowMask);
965 if(rowMask>=0&&rowMask<maskReader.nrOfRow()&&colMask>=0&&colMask<maskReader.nrOfCol()){
966 if(static_cast<int>(rowMask)!=
static_cast<int>(oldRowMask)){
967 assert(rowMask>=0&&rowMask<maskReader.nrOfRow());
970 maskReader.readData(lineMask,GDT_Int16,static_cast<int>(rowMask));
972 catch(
string errorstring){
973 cerr << errorstring << endl;
977 cerr <<
"error catched" << std::endl;
983 for(
short ivalue=0;ivalue<msknodata_opt.size();++ivalue){
984 if(msknodata_opt[ivalue]>=0){
985 if(lineMask[colMask]==msknodata_opt[ivalue]){
986 theMask=lineMask[colMask];
992 if(lineMask[colMask]!=-msknodata_opt[ivalue]){
993 theMask=lineMask[colMask];
1003 if(classBag_opt.size())
1004 for(
int ibag=0;ibag<nbag;++ibag)
1005 classBag[ibag][icol]=theMask;
1006 classOut[icol]=theMask;
1011 for(
int iband=0;iband<hpixel[icol].size();++iband){
1012 if(hpixel[icol][iband]){
1021 for(
short iclass=0;iclass<nclass;++iclass)
1022 probOut[iclass][icol]=0;
1024 if(classBag_opt.size())
1025 for(
int ibag=0;ibag<nbag;++ibag)
1026 classBag[ibag][icol]=nodata_opt[0];
1027 classOut[icol]=nodata_opt[0];
1030 if(verbose_opt[0]>1)
1031 std::cout <<
"begin classification " << std::endl;
1033 for(
int ibag=0;ibag<nbag;++ibag){
1035 fpixel[icol].clear();
1036 for(
int iband=0;iband<nband;++iband)
1037 fpixel[icol].push_back((hpixel[icol][iband]-offset[ibag][iband])/scale[ibag][iband]);
1038 vector<float> result(nclass);
1039 result=net[ibag].run(fpixel[icol]);
1041 vector<float> prValues(nclass);
1045 if(classBag_opt.size()){
1048 classBag[ibag][icol]=0;
1051 if(priorimg_opt.size()){
1052 for(
short iclass=0;iclass<nclass;++iclass)
1053 normPrior+=linePrior[iclass][icol];
1055 for(
int iclass=0;iclass<nclass;++iclass){
1056 result[iclass]=(result[iclass]+1.0)/2.0;
1057 if(priorimg_opt.size())
1058 priors[iclass]=linePrior[iclass][icol]/normPrior;
1059 switch(comb_opt[0]){
1062 probOut[iclass][icol]+=result[iclass]*priors[iclass];
1065 probOut[iclass][icol]*=pow(static_cast<float>(priors[iclass]),static_cast<float>(1.0-nbag)/nbag)*result[iclass];
1068 if(priors[iclass]*result[iclass]>probOut[iclass][icol])
1069 probOut[iclass][icol]=priors[iclass]*result[iclass];
1072 if(classBag_opt.size()){
1078 if(result[iclass]>maxP){
1079 maxP=result[iclass];
1080 classBag[ibag][icol]=iclass;
1090 for(
short iclass=0;iclass<nclass;++iclass){
1091 if(probOut[iclass][icol]>maxBag1){
1092 maxBag1=probOut[iclass][icol];
1093 classOut[icol]=classValueMap[nameVector[iclass]];
1095 else if(probOut[iclass][icol]>maxBag2)
1096 maxBag2=probOut[iclass][icol];
1097 normBag+=probOut[iclass][icol];
1101 for(
short iclass=0;iclass<nclass;++iclass){
1102 float prv=probOut[iclass][icol];
1104 entropy[icol]-=prv*log(prv)/log(2.0);
1107 probOut[iclass][icol]=
static_cast<short>(prv+0.5);
1112 entropy[icol]/=log(static_cast<double>(nclass))/log(2.0);
1113 entropy[icol]=
static_cast<short>(100*entropy[icol]+0.5);
1114 if(active_opt.size()){
1115 if(entropy[icol]>activePoints.back().value){
1116 activePoints.back().value=entropy[icol];
1117 activePoints.back().posx=icol;
1118 activePoints.back().posy=iline;
1121 std::cout << activePoints.back().posx <<
" " << activePoints.back().posy <<
" " << activePoints.back().value << std::endl;
1126 if(classBag_opt.size())
1127 for(
int ibag=0;ibag<nbag;++ibag)
1128 classImageBag.writeData(classBag[ibag],GDT_Byte,iline,ibag);
1129 if(prob_opt.size()){
1130 for(
int iclass=0;iclass<nclass;++iclass)
1131 probImage.writeData(probOut[iclass],GDT_Float32,iline,iclass);
1133 if(entropy_opt.size()){
1134 entropyImage.writeData(entropy,GDT_Float32,iline);
1136 classImageOut.writeData(classOut,GDT_Byte,iline);
1137 if(!verbose_opt[0]){
1138 progress=
static_cast<float>(iline+1.0)/classImageOut.nrOfRow();
1139 pfnProgress(progress,pszMessage,pProgressArg);
1143 if(active_opt.size()){
1144 for(
int iactive=0;iactive<activePoints.size();++iactive){
1145 std::map<string,double> pointMap;
1146 for(
int iband=0;iband<testImage.nrOfBand();++iband){
1148 testImage.readData(value,GDT_Float64,static_cast<int>(activePoints[iactive].posx),static_cast<int>(activePoints[iactive].posy),iband);
1151 pointMap[fs.str()]=value;
1153 pointMap[label_opt[0]]=0;
1155 testImage.image2geo(activePoints[iactive].posx,activePoints[iactive].posy,x,y);
1156 std::string fieldname=
"id";
1157 activeWriter.addPoint(x,y,pointMap,fieldname,++nactive);
1164 if(priorimg_opt.size())
1165 priorReader.close();
1168 if(entropy_opt.size())
1169 entropyImage.close();
1170 if(classBag_opt.size())
1171 classImageBag.close();
1172 classImageOut.close();
1177 for(
int ivalidation=0;ivalidation<input_opt.size();++ivalidation){
1178 if(output_opt.size())
1179 assert(output_opt.size()==input_opt.size());
1181 cout <<
"opening img reader " << input_opt[ivalidation] << endl;
1182 imgReaderOgr.open(input_opt[ivalidation]);
1185 if(output_opt.size()){
1187 std::cout <<
"opening img writer and copying fields from img reader" << output_opt[ivalidation] << std::endl;
1188 imgWriterOgr.open(output_opt[ivalidation],imgReaderOgr);
1191 cout <<
"number of layers in input ogr file: " << imgReaderOgr.getLayerCount() << endl;
1192 for(
int ilayer=0;ilayer<imgReaderOgr.getLayerCount();++ilayer){
1194 cout <<
"processing input layer " << ilayer << endl;
1195 if(output_opt.size()){
1197 std::cout <<
"creating field class" << std::endl;
1198 if(classValueMap.size())
1199 imgWriterOgr.createField(
"class",OFTInteger,ilayer);
1201 imgWriterOgr.createField(
"class",OFTString,ilayer);
1203 unsigned int nFeatures=imgReaderOgr.getFeatureCount(ilayer);
1204 unsigned int ifeature=0;
1206 pfnProgress(progress,pszMessage,pProgressArg);
1207 OGRFeature *poFeature;
1208 while( (poFeature = imgReaderOgr.getLayer(ilayer)->GetNextFeature()) != NULL ){
1209 if(verbose_opt[0]>1)
1210 cout <<
"feature " << ifeature << endl;
1211 if( poFeature == NULL ){
1212 cout <<
"Warning: could not read feature " << ifeature <<
" in layer " << imgReaderOgr.getLayerName(ilayer) << endl;
1215 OGRFeature *poDstFeature = NULL;
1216 if(output_opt.size()){
1217 poDstFeature=imgWriterOgr.createFeature(ilayer);
1218 if( poDstFeature->SetFrom( poFeature, TRUE ) != OGRERR_NONE ){
1219 CPLError( CE_Failure, CPLE_AppDefined,
1220 "Unable to translate feature %d from layer %s.\n",
1221 poFeature->GetFID(), imgWriterOgr.getLayerName(ilayer).c_str() );
1222 OGRFeature::DestroyFeature( poFeature );
1223 OGRFeature::DestroyFeature( poDstFeature );
1226 vector<float> validationPixel;
1227 vector<float> validationFeature;
1229 imgReaderOgr.readData(validationPixel,OFTReal,fields,poFeature,ilayer);
1230 assert(validationPixel.size()==nband);
1231 vector<float> probOut(nclass);
1232 for(
int iclass=0;iclass<nclass;++iclass)
1234 for(
int ibag=0;ibag<nbag;++ibag){
1235 for(
int iband=0;iband<nband;++iband){
1236 validationFeature.push_back((validationPixel[iband]-offset[ibag][iband])/scale[ibag][iband]);
1237 if(verbose_opt[0]==2)
1238 std:: cout <<
" " << validationFeature.back();
1240 if(verbose_opt[0]==2)
1241 std::cout << std:: endl;
1242 vector<float> result(nclass);
1243 result=net[ibag].run(validationFeature);
1245 if(verbose_opt[0]>1){
1246 for(
int iclass=0;iclass<result.size();++iclass)
1247 std::cout << result[iclass] <<
" ";
1248 std::cout << std::endl;
1251 for(
int iclass=0;iclass<nclass;++iclass){
1252 result[iclass]=(result[iclass]+1.0)/2.0;
1253 switch(comb_opt[0]){
1256 probOut[iclass]+=result[iclass]*priors[iclass];
1259 probOut[iclass]*=pow(static_cast<float>(priors[iclass]),static_cast<float>(1.0-nbag)/nbag)*result[iclass];
1262 if(priors[iclass]*result[iclass]>probOut[iclass])
1263 probOut[iclass]=priors[iclass]*result[iclass];
1271 string classOut=
"Unclassified";
1272 for(
int iclass=0;iclass<nclass;++iclass){
1273 if(verbose_opt[0]>1)
1274 std::cout << probOut[iclass] <<
" ";
1275 if(probOut[iclass]>maxBag){
1276 maxBag=probOut[iclass];
1277 classOut=nameVector[iclass];
1281 if(verbose_opt[0]>1){
1282 if(classValueMap.size())
1283 std::cout <<
"->" << classValueMap[classOut] << std::endl;
1285 std::cout <<
"->" << classOut << std::endl;
1287 if(output_opt.size()){
1288 if(classValueMap.size())
1289 poDstFeature->SetField(
"class",classValueMap[classOut]);
1291 poDstFeature->SetField(
"class",classOut.c_str());
1292 poDstFeature->SetFID( poFeature->GetFID() );
1294 int labelIndex=poFeature->GetFieldIndex(label_opt[0].c_str());
1296 string classRef=poFeature->GetFieldAsString(labelIndex);
1298 if(classValueMap.size())
1299 cm.incrementResult(type2string<short>(classValueMap[classRef]),type2string<short>(classValueMap[classOut]),1);
1301 cm.incrementResult(classRef,classOut,1);
1305 if(output_opt.size()){
1306 if(imgWriterOgr.createFeature(poDstFeature,ilayer) != OGRERR_NONE){
1307 CPLError( CE_Failure, CPLE_AppDefined,
1308 "Unable to translate feature %d from layer %s.\n",
1309 poFeature->GetFID(), imgWriterOgr.getLayerName(ilayer).c_str() );
1310 OGRFeature::DestroyFeature( poDstFeature );
1311 OGRFeature::DestroyFeature( poDstFeature );
1315 if(!verbose_opt[0]){
1316 progress=
static_cast<float>(ifeature+1.0)/nFeatures;
1317 pfnProgress(progress,pszMessage,pProgressArg);
1319 OGRFeature::DestroyFeature( poFeature );
1320 OGRFeature::DestroyFeature( poDstFeature );
1323 imgReaderOgr.close();
1324 if(output_opt.size())
1325 imgWriterOgr.close();
1327 if(cm.nReference()){
1328 std::cout << cm << std::endl;
1347 if(active_opt.size())
1348 activeWriter.close();
1350 catch(
string errorString){
1351 std::cerr <<
"Error: errorString" << std::endl;