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. 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);
374 totalSamples=trainingReaderBag.readDataImageOgr(trainingMap,fields,0,0,label_opt[0],tlayer_opt);
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 caught" << 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=
true;
745 if(verbose_opt[0]>=1)
746 cout <<
"opening image " << input_opt[0] << endl;
747 testImage.
open(input_opt[0]);
750 cerr << error << endl;
754 if(priorimg_opt.size()){
756 if(verbose_opt[0]>=1)
757 std::cout <<
"opening prior image " << priorimg_opt[0] << std::endl;
758 priorReader.
open(priorimg_opt[0]);
763 cerr << error << std::endl;
767 cerr <<
"error caught" << std::endl;
774 if(option_opt.findSubstring(
"INTERLEAVE=")==option_opt.end()){
775 string theInterleave=
"INTERLEAVE=";
777 option_opt.push_back(theInterleave);
779 vector<char> classOut(ncol);
788 if(oformat_opt.size())
789 imageType=oformat_opt[0];
792 if(verbose_opt[0]>=1)
793 cout <<
"opening class image for writing output " << output_opt[0] << endl;
794 if(classBag_opt.size()){
795 classImageBag.
open(classBag_opt[0],ncol,nrow,nbag,GDT_Byte,imageType,option_opt);
800 classImageOut.
open(output_opt[0],ncol,nrow,1,GDT_Byte,imageType,option_opt);
804 if(colorTable_opt.size())
807 probImage.
open(prob_opt[0],ncol,nrow,nclass,GDT_Byte,imageType,option_opt);
812 if(entropy_opt.size()){
813 entropyImage.
open(entropy_opt[0],ncol,nrow,1,GDT_Byte,imageType,option_opt);
820 cerr << error << endl;
827 maskWriter.
open(
"/vsimem/mask.tif",ncol,nrow,1,GDT_Float32,imageType,option_opt);
831 vector<double> burnValues(1,1);
833 extentReader.close();
837 cerr << error << std::endl;
841 cerr <<
"error caught" << std::endl;
845 mask_opt.push_back(
"/vsimem/mask.tif");
850 if(verbose_opt[0]>=1)
851 std::cout <<
"opening mask image file " << mask_opt[0] << std::endl;
852 maskReader.
open(mask_opt[0]);
855 cerr << error << std::endl;
859 cerr <<
"error caught" << std::endl;
864 for(
int iline=0;iline<nrow;++iline){
865 vector<float> buffer(ncol);
866 vector<short> lineMask;
868 lineMask.resize(maskReader.
nrOfCol());
870 if(priorimg_opt.size())
871 linePrior.resize(nclass,ncol);
875 vector<float> entropy(ncol);
877 if(classBag_opt.size())
878 classBag.resize(nbag,ncol);
882 for(
int iband=0;iband<band_opt.size();++iband){
883 if(verbose_opt[0]==2)
884 std::cout <<
"reading band " << band_opt[iband] << std::endl;
885 assert(band_opt[iband]>=0);
886 assert(band_opt[iband]<testImage.
nrOfBand());
887 testImage.
readData(buffer,iline,band_opt[iband]);
888 for(
int icol=0;icol<ncol;++icol)
889 hpixel[icol].push_back(buffer[icol]);
893 for(
int iband=0;iband<nband;++iband){
894 if(verbose_opt[0]==2)
895 std::cout <<
"reading band " << iband << std::endl;
898 testImage.
readData(buffer,iline,iband);
899 for(
int icol=0;icol<ncol;++icol)
900 hpixel[icol].push_back(buffer[icol]);
904 catch(
string theError){
905 cerr <<
"Error reading " << input_opt[0] <<
": " << theError << std::endl;
909 cerr <<
"error caught" << std::endl;
912 assert(nband==hpixel[0].size());
913 if(verbose_opt[0]==2)
914 cout <<
"used bands: " << nband << endl;
916 if(priorimg_opt.size()){
918 for(
short iclass=0;iclass<nclass;++iclass){
919 if(verbose_opt.size()>1)
920 std::cout <<
"Reading " << priorimg_opt[0] <<
" band " << iclass <<
" line " << iline << std::endl;
921 priorReader.
readData(linePrior[iclass],iline,iclass);
924 catch(
string theError){
925 std::cerr <<
"Error reading " << priorimg_opt[0] <<
": " << theError << std::endl;
929 cerr <<
"error caught" << std::endl;
933 double oldRowMask=-1;
935 for(
int icol=0;icol<ncol;++icol){
936 assert(hpixel[icol].size()==nband);
937 bool doClassify=
true;
943 testImage.
image2geo(icol,iline,geox,geoy);
945 if(uly>=geoy&&lry<=geoy&&ulx<=geox&&lrx>=geox){
954 testImage.
image2geo(icol,iline,geox,geoy);
955 maskReader.
geo2image(geox,geoy,colMask,rowMask);
956 colMask=
static_cast<int>(colMask);
957 rowMask=
static_cast<int>(rowMask);
958 if(rowMask>=0&&rowMask<maskReader.
nrOfRow()&&colMask>=0&&colMask<maskReader.
nrOfCol()){
959 if(static_cast<int>(rowMask)!=
static_cast<int>(oldRowMask)){
960 assert(rowMask>=0&&rowMask<maskReader.
nrOfRow());
963 maskReader.
readData(lineMask,static_cast<int>(rowMask));
965 catch(
string errorstring){
966 cerr << errorstring << endl;
970 cerr <<
"error caught" << std::endl;
976 for(
short ivalue=0;ivalue<msknodata_opt.size();++ivalue){
978 if(lineMask[colMask]==msknodata_opt[ivalue]){
979 theMask=lineMask[colMask];
996 if(classBag_opt.size())
997 for(
int ibag=0;ibag<nbag;++ibag)
998 classBag[ibag][icol]=theMask;
999 classOut[icol]=theMask;
1004 for(
int iband=0;iband<hpixel[icol].size();++iband){
1005 if(hpixel[icol][iband]){
1014 for(
short iclass=0;iclass<nclass;++iclass)
1015 probOut[iclass][icol]=0;
1017 if(classBag_opt.size())
1018 for(
int ibag=0;ibag<nbag;++ibag)
1019 classBag[ibag][icol]=nodata_opt[0];
1020 classOut[icol]=nodata_opt[0];
1023 if(verbose_opt[0]>1)
1024 std::cout <<
"begin classification " << std::endl;
1026 for(
int ibag=0;ibag<nbag;++ibag){
1028 fpixel[icol].clear();
1029 for(
int iband=0;iband<nband;++iband)
1030 fpixel[icol].push_back((hpixel[icol][iband]-offset[ibag][iband])/scale[ibag][iband]);
1031 vector<float> result(nclass);
1032 result=net[ibag].run(fpixel[icol]);
1034 vector<float> prValues(nclass);
1038 if(classBag_opt.size()){
1041 classBag[ibag][icol]=0;
1044 if(priorimg_opt.size()){
1045 for(
short iclass=0;iclass<nclass;++iclass)
1046 normPrior+=linePrior[iclass][icol];
1048 for(
int iclass=0;iclass<nclass;++iclass){
1049 result[iclass]=(result[iclass]+1.0)/2.0;
1050 if(priorimg_opt.size())
1051 priors[iclass]=linePrior[iclass][icol]/normPrior;
1052 switch(comb_opt[0]){
1055 probOut[iclass][icol]+=result[iclass]*priors[iclass];
1058 probOut[iclass][icol]*=pow(static_cast<float>(priors[iclass]),static_cast<float>(1.0-nbag)/nbag)*result[iclass];
1061 if(priors[iclass]*result[iclass]>probOut[iclass][icol])
1062 probOut[iclass][icol]=priors[iclass]*result[iclass];
1065 if(classBag_opt.size()){
1071 if(result[iclass]>maxP){
1072 maxP=result[iclass];
1073 classBag[ibag][icol]=iclass;
1083 for(
short iclass=0;iclass<nclass;++iclass){
1084 if(probOut[iclass][icol]>maxBag1){
1085 maxBag1=probOut[iclass][icol];
1086 classOut[icol]=classValueMap[nameVector[iclass]];
1088 else if(probOut[iclass][icol]>maxBag2)
1089 maxBag2=probOut[iclass][icol];
1090 normBag+=probOut[iclass][icol];
1094 for(
short iclass=0;iclass<nclass;++iclass){
1095 float prv=probOut[iclass][icol];
1097 entropy[icol]-=prv*log(prv)/log(2.0);
1100 probOut[iclass][icol]=
static_cast<short>(prv+0.5);
1105 entropy[icol]/=log(static_cast<double>(nclass))/log(2.0);
1106 entropy[icol]=
static_cast<short>(100*entropy[icol]+0.5);
1107 if(active_opt.size()){
1108 if(entropy[icol]>activePoints.back().value){
1109 activePoints.back().value=entropy[icol];
1110 activePoints.back().posx=icol;
1111 activePoints.back().posy=iline;
1114 std::cout << activePoints.back().posx <<
" " << activePoints.back().posy <<
" " << activePoints.back().value << std::endl;
1119 if(classBag_opt.size())
1120 for(
int ibag=0;ibag<nbag;++ibag)
1121 classImageBag.
writeData(classBag[ibag],iline,ibag);
1122 if(prob_opt.size()){
1123 for(
int iclass=0;iclass<nclass;++iclass)
1124 probImage.
writeData(probOut[iclass],iline,iclass);
1126 if(entropy_opt.size()){
1129 classImageOut.
writeData(classOut,iline);
1130 if(!verbose_opt[0]){
1131 progress=
static_cast<float>(iline+1.0)/classImageOut.
nrOfRow();
1132 pfnProgress(progress,pszMessage,pProgressArg);
1136 if(active_opt.size()){
1137 for(
int iactive=0;iactive<activePoints.size();++iactive){
1138 std::map<string,double> pointMap;
1139 for(
int iband=0;iband<testImage.
nrOfBand();++iband){
1141 testImage.
readData(value,static_cast<int>(activePoints[iactive].posx),static_cast<int>(activePoints[iactive].posy),iband);
1144 pointMap[fs.str()]=value;
1146 pointMap[label_opt[0]]=0;
1148 testImage.
image2geo(activePoints[iactive].posx,activePoints[iactive].posy,x,y);
1149 std::string fieldname=
"id";
1150 activeWriter.addPoint(x,y,pointMap,fieldname,++nactive);
1157 if(priorimg_opt.size())
1158 priorReader.
close();
1161 if(entropy_opt.size())
1162 entropyImage.
close();
1163 if(classBag_opt.size())
1164 classImageBag.
close();
1165 classImageOut.
close();
1168 if(active_opt.size())
1169 activeWriter.close();
1171 catch(
string errorString){
1172 std::cerr <<
"Error: errorString" << std::endl;
void rasterizeOgr(ImgReaderOgr &ogrReader, const std::vector< double > &burnValues, const std::vector< std::string > &controlOptions=std::vector< std::string >(), const std::vector< std::string > &layernames=std::vector< std::string >())
Rasterize an OGR vector dataset using the gdal algorithm "GDALRasterizeLayers".
bool geo2image(double x, double y, double &i, double &j) const
Convert georeferenced coordinates (x and y) to image coordinates (column and row) ...
void close(void)
Set the memory (in MB) to cache a number of rows in memory.
int nrOfCol(void) const
Get the number of columns of this dataset.
void setColorTable(const std::string &filename, int band=0)
Set the color table using an (ASCII) file with 5 columns (value R G B alpha)
void readData(T &value, int col, int row, int band=0)
Read a single pixel cell value at a specific column and row for a specific band (all indices start co...
int nrOfRow(void) const
Get the number of rows of this dataset.
bool image2geo(double i, double j, double &x, double &y) const
Convert image coordinates (column and row) to georeferenced coordinates (x and y) ...
bool writeData(T &value, int col, int row, int band=0)
Write a single pixel cell value at a specific column and row for a specific band (all indices start c...
void copyGeoTransform(const ImgRasterGdal &imgSrc)
Copy geotransform information from another georeferenced image.
void open(const std::string &filename, const ImgReaderGdal &imgSrc, const std::vector< std::string > &options=std::vector< std::string >())
Open an image for writing, copying image attributes from a source image. Image is directly written to...
std::string getProjection(void) const
Get the projection string (deprecated, use getProjectionRef instead)
CPLErr setProjection(const std::string &projection)
Set the projection for this dataset in well known text (wkt) format.
void close(void)
Close the image.
CPLErr GDALSetNoDataValue(double noDataValue, int band=0)
Set the GDAL (internal) no data value for this data set. Only a single no data value per band is supp...
void open(const std::string &filename, const GDALAccess &readMode=GA_ReadOnly)
Open an image.
int nrOfBand(void) const
Get the number of bands of this dataset.
std::string getInterleave() const
Get the band coding (interleave)