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<short> band_opt(
"b",
"band",
"band index (starting from 0, either use band option or use start to end)");
124 Optionpk<double> bend_opt(
"e",
"end",
"end band sequence number (set to 0 to include bands)", 0);
125 Optionpk<double> offset_opt(
"\0",
"offset",
"offset value for each spectral band input features: refl[band]=(DN[band]-offset[band])/scale[band]", 0.0);
126 Optionpk<double> scale_opt(
"\0",
"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",
"Use the first band of the specified file as a validity mask. Nodata values can be set 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). Empty string: inherit from input image");
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);
159 bstart_opt.setHide(1);
161 balance_opt.setHide(1);
162 minSize_opt.setHide(1);
164 bagSize_opt.setHide(1);
166 classBag_opt.setHide(1);
167 minSize_opt.setHide(1);
169 priorimg_opt.setHide(1);
170 minSize_opt.setHide(1);
171 offset_opt.setHide(1);
172 scale_opt.setHide(1);
173 connection_opt.setHide(1);
174 weights_opt.setHide(1);
175 maxit_opt.setHide(1);
176 learning_opt.setHide(1);
180 doProcess=input_opt.retrieveOption(argc,argv);
181 training_opt.retrieveOption(argc,argv);
182 tlayer_opt.retrieveOption(argc,argv);
183 label_opt.retrieveOption(argc,argv);
184 balance_opt.retrieveOption(argc,argv);
185 random_opt.retrieveOption(argc,argv);
186 minSize_opt.retrieveOption(argc,argv);
187 band_opt.retrieveOption(argc,argv);
188 bstart_opt.retrieveOption(argc,argv);
189 bend_opt.retrieveOption(argc,argv);
190 offset_opt.retrieveOption(argc,argv);
191 scale_opt.retrieveOption(argc,argv);
192 aggreg_opt.retrieveOption(argc,argv);
193 priors_opt.retrieveOption(argc,argv);
194 priorimg_opt.retrieveOption(argc,argv);
195 cv_opt.retrieveOption(argc,argv);
196 cmformat_opt.retrieveOption(argc,argv);
197 nneuron_opt.retrieveOption(argc,argv);
198 connection_opt.retrieveOption(argc,argv);
199 weights_opt.retrieveOption(argc,argv);
200 learning_opt.retrieveOption(argc,argv);
201 maxit_opt.retrieveOption(argc,argv);
202 comb_opt.retrieveOption(argc,argv);
203 bag_opt.retrieveOption(argc,argv);
204 bagSize_opt.retrieveOption(argc,argv);
205 classBag_opt.retrieveOption(argc,argv);
206 mask_opt.retrieveOption(argc,argv);
207 msknodata_opt.retrieveOption(argc,argv);
208 nodata_opt.retrieveOption(argc,argv);
209 output_opt.retrieveOption(argc,argv);
210 otype_opt.retrieveOption(argc,argv);
211 oformat_opt.retrieveOption(argc,argv);
212 colorTable_opt.retrieveOption(argc,argv);
213 option_opt.retrieveOption(argc,argv);
214 prob_opt.retrieveOption(argc,argv);
215 entropy_opt.retrieveOption(argc,argv);
216 active_opt.retrieveOption(argc,argv);
217 ogrformat_opt.retrieveOption(argc,argv);
218 nactive_opt.retrieveOption(argc,argv);
219 classname_opt.retrieveOption(argc,argv);
220 classvalue_opt.retrieveOption(argc,argv);
221 verbose_opt.retrieveOption(argc,argv);
223 catch(
string predefinedString){
224 std::cout << predefinedString << std::endl;
229 cout <<
"Usage: pkann -t training [-i input -o output] [-cv value]" << endl;
231 cout <<
"short option -h shows basic options only, use long option --help to show all options" << endl;
235 if(entropy_opt[0]==
"")
237 if(active_opt[0]==
"")
239 if(priorimg_opt[0]==
"")
240 priorimg_opt.clear();
242 if(verbose_opt[0]>=1){
244 cout <<
"image filename: " << input_opt[0] << endl;
246 cout <<
"mask filename: " << mask_opt[0] << endl;
247 if(training_opt.size()){
248 cout <<
"training vector file: " << endl;
249 for(
int ifile=0;ifile<training_opt.size();++ifile)
250 cout << training_opt[ifile] << endl;
253 cerr <<
"no training file set!" << endl;
254 cout <<
"verbose: " << verbose_opt[0] << endl;
256 unsigned short nbag=(training_opt.size()>1)?training_opt.size():bag_opt[0];
257 if(verbose_opt[0]>=1)
258 cout <<
"number of bootstrap aggregations: " << nbag << endl;
261 if(active_opt.size()){
263 activeWriter.open(active_opt[0],ogrformat_opt[0]);
264 activeWriter.createLayer(active_opt[0],trainingReader.getProjection(),wkbPoint,NULL);
265 activeWriter.copyFields(trainingReader);
267 vector<PosValue> activePoints(nactive_opt[0]);
268 for(
int iactive=0;iactive<activePoints.size();++iactive){
269 activePoints[iactive].value=1.0;
270 activePoints[iactive].posx=0.0;
271 activePoints[iactive].posy=0.0;
274 unsigned int totalSamples=0;
275 unsigned int nactive=0;
276 vector<FANN::neural_net> net(nbag);
278 unsigned int nclass=0;
282 if(priors_opt.size()>1){
283 priors.resize(priors_opt.size());
285 for(
int iclass=0;iclass<priors_opt.size();++iclass){
286 priors[iclass]=priors_opt[iclass];
287 normPrior+=priors[iclass];
290 for(
int iclass=0;iclass<priors_opt.size();++iclass)
291 priors[iclass]/=normPrior;
296 std::sort(band_opt.begin(),band_opt.end());
298 map<string,short> classValueMap;
299 vector<std::string> nameVector;
300 if(classname_opt.size()){
301 assert(classname_opt.size()==classvalue_opt.size());
302 for(
int iclass=0;iclass<classname_opt.size();++iclass)
303 classValueMap[classname_opt[iclass]]=classvalue_opt[iclass];
307 vector< vector<double> > offset(nbag);
308 vector< vector<double> > scale(nbag);
309 map<string,Vector2d<float> > trainingMap;
310 vector< Vector2d<float> > trainingPixels;
311 vector<string> fields;
312 for(
int ibag=0;ibag<nbag;++ibag){
314 if(ibag<training_opt.size()){
316 trainingPixels.clear();
317 if(verbose_opt[0]>=1)
318 cout <<
"reading imageVector file " << training_opt[0] << endl;
322 totalSamples=trainingReaderBag.readDataImageOgr(trainingMap,fields,band_opt,label_opt[0],tlayer_opt,verbose_opt[0]);
324 totalSamples=trainingReaderBag.readDataImageOgr(trainingMap,fields,bstart_opt[0],bend_opt[0],label_opt[0],tlayer_opt,verbose_opt[0]);
325 if(trainingMap.size()<2){
326 string errorstring=
"Error: could not read at least two classes from training file, did you provide class labels in training sample (see option label)?";
329 trainingReaderBag.close();
332 cerr << error << std::endl;
336 cerr <<
"error catched" << std::endl;
346 std::cout <<
"training pixels: " << std::endl;
347 map<string,Vector2d<float> >::iterator mapit=trainingMap.begin();
348 while(mapit!=trainingMap.end()){
350 if((mapit->second).size()<minSize_opt[0]){
351 trainingMap.erase(mapit);
354 trainingPixels.push_back(mapit->second);
356 std::cout << mapit->first <<
": " << (mapit->second).size() <<
" samples" << std::endl;
360 nclass=trainingPixels.size();
361 if(classname_opt.size())
362 assert(nclass==classname_opt.size());
363 nband=(training_opt.size())?trainingPixels[0][0].size()-2:trainingPixels[0][0].size();
366 assert(nclass==trainingPixels.size());
367 assert(nband==(training_opt.size())?trainingPixels[0][0].size()-2:trainingPixels[0][0].size());
372 if(balance_opt[0]>0){
373 while(balance_opt.size()<nclass)
374 balance_opt.push_back(balance_opt.back());
378 for(
int iclass=0;iclass<nclass;++iclass){
379 if(trainingPixels[iclass].size()>balance_opt[iclass]){
380 while(trainingPixels[iclass].size()>balance_opt[iclass]){
381 int index=rand()%trainingPixels[iclass].size();
382 trainingPixels[iclass].erase(trainingPixels[iclass].begin()+index);
386 int oldsize=trainingPixels[iclass].size();
387 for(
int isample=trainingPixels[iclass].size();isample<balance_opt[iclass];++isample){
388 int index = rand()%oldsize;
389 trainingPixels[iclass].push_back(trainingPixels[iclass][index]);
392 totalSamples+=trainingPixels[iclass].size();
397 offset[ibag].resize(nband);
398 scale[ibag].resize(nband);
399 if(offset_opt.size()>1)
400 assert(offset_opt.size()==nband);
401 if(scale_opt.size()>1)
402 assert(scale_opt.size()==nband);
403 for(
int iband=0;iband<nband;++iband){
404 if(verbose_opt[0]>=1)
405 cout <<
"scaling for band" << iband << endl;
406 offset[ibag][iband]=(offset_opt.size()==1)?offset_opt[0]:offset_opt[iband];
407 scale[ibag][iband]=(scale_opt.size()==1)?scale_opt[0]:scale_opt[iband];
409 if(scale[ibag][iband]<=0){
410 float theMin=trainingPixels[0][0][iband+startBand];
411 float theMax=trainingPixels[0][0][iband+startBand];
412 for(
int iclass=0;iclass<nclass;++iclass){
413 for(
int isample=0;isample<trainingPixels[iclass].size();++isample){
414 if(theMin>trainingPixels[iclass][isample][iband+startBand])
415 theMin=trainingPixels[iclass][isample][iband+startBand];
416 if(theMax<trainingPixels[iclass][isample][iband+startBand])
417 theMax=trainingPixels[iclass][isample][iband+startBand];
420 offset[ibag][iband]=theMin+(theMax-theMin)/2.0;
421 scale[ibag][iband]=(theMax-theMin)/2.0;
422 if(verbose_opt[0]>=1){
423 std::cout <<
"Extreme image values for band " << iband <<
": [" << theMin <<
"," << theMax <<
"]" << std::endl;
424 std::cout <<
"Using offset, scale: " << offset[ibag][iband] <<
", " << scale[ibag][iband] << std::endl;
425 std::cout <<
"scaled values for band " << iband <<
": [" << (theMin-offset[ibag][iband])/scale[ibag][iband] <<
"," << (theMax-offset[ibag][iband])/scale[ibag][iband] <<
"]" << std::endl;
431 offset[ibag].resize(nband);
432 scale[ibag].resize(nband);
433 for(
int iband=0;iband<nband;++iband){
434 offset[ibag][iband]=offset[0][iband];
435 scale[ibag][iband]=scale[0][iband];
440 if(priors_opt.size()==1){
441 priors.resize(nclass);
442 for(
int iclass=0;iclass<nclass;++iclass)
443 priors[iclass]=1.0/nclass;
445 assert(priors_opt.size()==1||priors_opt.size()==nclass);
448 while(bagSize_opt.size()<nclass)
449 bagSize_opt.push_back(bagSize_opt.back());
451 if(verbose_opt[0]>=1){
452 std::cout <<
"number of bands: " << nband << std::endl;
453 std::cout <<
"number of classes: " << nclass << std::endl;
454 std::cout <<
"priors:";
455 if(priorimg_opt.empty()){
456 for(
int iclass=0;iclass<nclass;++iclass)
457 std::cout <<
" " << priors[iclass];
458 std::cout << std::endl;
461 map<string,Vector2d<float> >::iterator mapit=trainingMap.begin();
463 while(mapit!=trainingMap.end()){
464 nameVector.push_back(mapit->first);
465 if(classValueMap.size()){
467 if(classValueMap[mapit->first]>0){
468 if(cm.getClassIndex(type2string<short>(classValueMap[mapit->first]))<0)
469 cm.pushBackClassName(type2string<short>(classValueMap[mapit->first]),doSort);
472 std::cerr <<
"Error: names in classname option are not complete, please check names in training vector and make sure classvalue is > 0" << std::endl;
477 cm.pushBackClassName(mapit->first,doSort);
480 if(classname_opt.empty()){
482 for(
int iclass=0;iclass<nclass;++iclass){
484 std::cout << iclass <<
" " << cm.getClass(iclass) <<
" -> " << string2type<short>(cm.getClass(iclass)) << std::endl;
485 classValueMap[cm.getClass(iclass)]=string2type<short>(cm.getClass(iclass));
488 if(priors_opt.size()==nameVector.size()){
489 std::cerr <<
"Warning: please check if priors are provided in correct order!!!" << std::endl;
490 for(
int iclass=0;iclass<nameVector.size();++iclass)
491 std::cerr << nameVector[iclass] <<
" " << priors_opt[iclass] << std::endl;
496 vector< Vector2d<float> > trainingFeatures(nclass);
497 for(
int iclass=0;iclass<nclass;++iclass){
499 if(verbose_opt[0]>=1)
500 cout <<
"calculating features for class " << iclass << endl;
503 nctraining=(bagSize_opt[iclass]<100)? trainingPixels[iclass].size()/100.0*bagSize_opt[iclass] : trainingPixels[iclass].size();
506 assert(nctraining<=trainingPixels[iclass].size());
508 if(bagSize_opt[iclass]<100)
509 random_shuffle(trainingPixels[iclass].begin(),trainingPixels[iclass].end());
511 trainingFeatures[iclass].resize(nctraining);
512 for(
int isample=0;isample<nctraining;++isample){
514 for(
int iband=0;iband<nband;++iband){
515 float value=trainingPixels[iclass][isample][iband+startBand];
516 trainingFeatures[iclass][isample].push_back((value-offset[ibag][iband])/scale[ibag][iband]);
519 assert(trainingFeatures[iclass].size()==nctraining);
522 unsigned int nFeatures=trainingFeatures[0][0].size();
523 unsigned int ntraining=0;
524 for(
int iclass=0;iclass<nclass;++iclass)
525 ntraining+=trainingFeatures[iclass].size();
527 const unsigned int num_layers = nneuron_opt.size()+2;
528 const float desired_error = 0.0003;
529 const unsigned int iterations_between_reports = (verbose_opt[0])? maxit_opt[0]+1:0;
530 if(verbose_opt[0]>=1){
531 cout <<
"number of features: " << nFeatures << endl;
532 cout <<
"creating artificial neural network with " << nneuron_opt.size() <<
" hidden layer, having " << endl;
533 for(
int ilayer=0;ilayer<nneuron_opt.size();++ilayer)
534 cout << nneuron_opt[ilayer] <<
" ";
535 cout <<
"neurons" << endl;
536 cout <<
"connection_opt[0]: " << connection_opt[0] << std::endl;
537 cout <<
"num_layers: " << num_layers << std::endl;
538 cout <<
"nFeatures: " << nFeatures << std::endl;
539 cout <<
"nneuron_opt[0]: " << nneuron_opt[0] << std::endl;
540 cout <<
"number of classes (nclass): " << nclass << std::endl;
545 unsigned int layers[3];
547 layers[1]=nneuron_opt[0];
549 net[ibag].create_sparse_array(connection_opt[0],num_layers,layers);
553 unsigned int layers[4];
555 layers[1]=nneuron_opt[0];
556 layers[2]=nneuron_opt[1];
562 net[ibag].create_sparse_array(connection_opt[0],num_layers,layers);
566 cerr <<
"Only 1 or 2 hidden layers are supported!" << endl;
570 if(verbose_opt[0]>=1)
571 cout <<
"network created" << endl;
573 net[ibag].set_learning_rate(learning_opt[0]);
578 net[ibag].set_activation_function_hidden(FANN::SIGMOID_SYMMETRIC_STEPWISE);
579 net[ibag].set_activation_function_output(FANN::SIGMOID_SYMMETRIC_STEPWISE);
585 if(verbose_opt[0]>=1){
586 cout << endl <<
"Network Type : ";
587 switch (net[ibag].get_network_type())
590 cout <<
"LAYER" << endl;
593 cout <<
"SHORTCUT" << endl;
596 cout <<
"UNKNOWN" << endl;
599 net[ibag].print_parameters();
604 std::cout <<
"cross validation" << std::endl;
605 vector<unsigned short> referenceVector;
606 vector<unsigned short> outputVector;
607 float rmse=net[ibag].cross_validation(trainingFeatures,
615 map<string,Vector2d<float> >::iterator mapit=trainingMap.begin();
616 for(
int isample=0;isample<referenceVector.size();++isample){
617 string refClassName=nameVector[referenceVector[isample]];
618 string className=nameVector[outputVector[isample]];
619 if(classValueMap.size())
620 cm.incrementResult(type2string<short>(classValueMap[refClassName]),type2string<short>(classValueMap[className]),1.0/nbag);
622 cm.incrementResult(cm.getClass(referenceVector[isample]),cm.getClass(outputVector[isample]),1.0/nbag);
626 if(verbose_opt[0]>=1)
627 cout << endl <<
"Set training data" << endl;
629 if(verbose_opt[0]>=1)
630 cout << endl <<
"Training network" << endl;
632 if(verbose_opt[0]>=1){
633 cout <<
"Max Epochs " << setw(8) << maxit_opt[0] <<
". "
634 <<
"Desired Error: " << left << desired_error << right << endl;
636 if(weights_opt.size()==net[ibag].get_total_connections()){
637 vector<fann_connection> convector;
638 net[ibag].get_connection_array(convector);
639 for(
int i_connection=0;i_connection<net[ibag].get_total_connections();++i_connection)
640 convector[i_connection].weight=weights_opt[i_connection];
641 net[ibag].set_weight_array(convector);
644 bool initWeights=
true;
645 net[ibag].train_on_data(trainingFeatures,ntraining,initWeights, maxit_opt[0],
646 iterations_between_reports, desired_error);
650 if(verbose_opt[0]>=2){
651 net[ibag].print_connections();
652 vector<fann_connection> convector;
653 net[ibag].get_connection_array(convector);
654 for(
int i_connection=0;i_connection<net[ibag].get_total_connections();++i_connection)
655 cout <<
"connection " << i_connection <<
": " << convector[i_connection].weight << endl;
660 assert(cm.nReference());
661 cm.setFormat(cmformat_opt[0]);
662 cm.reportSE95(
false);
663 std::cout << cm << std::endl;
664 cout <<
"class #samples userAcc prodAcc" << endl;
671 for(
int iclass=0;iclass<cm.nClasses();++iclass){
672 dua=cm.ua_pct(cm.getClass(iclass),&se95_ua);
673 dpa=cm.pa_pct(cm.getClass(iclass),&se95_pa);
674 cout << cm.getClass(iclass) <<
" " << cm.nReference(cm.getClass(iclass)) <<
" " << dua <<
" (" << se95_ua <<
")" <<
" " << dpa <<
" (" << se95_pa <<
")" << endl;
676 std::cout <<
"Kappa: " << cm.kappa() << std::endl;
677 doa=cm.oa_pct(&se95_oa);
678 std::cout <<
"Overall Accuracy: " << doa <<
" (" << se95_oa <<
")" << std::endl;
681 if(input_opt.empty())
684 const char* pszMessage;
685 void* pProgressArg=NULL;
686 GDALProgressFunc pfnProgress=GDALTermProgress;
689 bool inputIsRaster=
false;
692 imgReaderOgr.open(input_opt[0]);
693 imgReaderOgr.close();
695 catch(
string errorString){
702 if(verbose_opt[0]>=1)
703 cout <<
"opening image " << input_opt[0] << endl;
704 testImage.open(input_opt[0]);
707 cerr << error << endl;
713 if(verbose_opt[0]>=1)
714 std::cout <<
"opening mask image file " << mask_opt[0] << std::endl;
715 maskReader.open(mask_opt[0]);
718 cerr << error << endl;
722 cerr <<
"error catched" << endl;
727 if(priorimg_opt.size()){
729 if(verbose_opt[0]>=1)
730 std::cout <<
"opening prior image " << priorimg_opt[0] << std::endl;
731 priorReader.open(priorimg_opt[0]);
732 assert(priorReader.nrOfCol()==testImage.nrOfCol());
733 assert(priorReader.nrOfRow()==testImage.nrOfRow());
736 cerr << error << std::endl;
740 cerr <<
"error catched" << std::endl;
745 int nrow=testImage.nrOfRow();
746 int ncol=testImage.nrOfCol();
747 if(option_opt.findSubstring(
"INTERLEAVE=")==option_opt.end()){
748 string theInterleave=
"INTERLEAVE=";
749 theInterleave+=testImage.getInterleave();
750 option_opt.push_back(theInterleave);
752 vector<char> classOut(ncol);
760 string imageType=testImage.getImageType();
761 if(oformat_opt.size())
762 imageType=oformat_opt[0];
765 if(verbose_opt[0]>=1)
766 cout <<
"opening class image for writing output " << output_opt[0] << endl;
767 if(classBag_opt.size()){
768 classImageBag.open(classBag_opt[0],ncol,nrow,nbag,GDT_Byte,imageType,option_opt);
769 classImageBag.GDALSetNoDataValue(nodata_opt[0]);
770 classImageBag.copyGeoTransform(testImage);
771 classImageBag.setProjection(testImage.getProjection());
773 classImageOut.open(output_opt[0],ncol,nrow,1,GDT_Byte,imageType,option_opt);
774 classImageOut.GDALSetNoDataValue(nodata_opt[0]);
775 classImageOut.copyGeoTransform(testImage);
776 classImageOut.setProjection(testImage.getProjection());
777 if(colorTable_opt.size())
778 classImageOut.setColorTable(colorTable_opt[0],0);
780 probImage.open(prob_opt[0],ncol,nrow,nclass,GDT_Byte,imageType,option_opt);
781 probImage.GDALSetNoDataValue(nodata_opt[0]);
782 probImage.copyGeoTransform(testImage);
783 probImage.setProjection(testImage.getProjection());
785 if(entropy_opt.size()){
786 entropyImage.open(entropy_opt[0],ncol,nrow,1,GDT_Byte,imageType,option_opt);
787 entropyImage.GDALSetNoDataValue(nodata_opt[0]);
788 entropyImage.copyGeoTransform(testImage);
789 entropyImage.setProjection(testImage.getProjection());
793 cerr << error << endl;
796 for(
int iline=0;iline<nrow;++iline){
797 vector<float> buffer(ncol);
798 vector<short> lineMask;
800 lineMask.resize(maskReader.nrOfCol());
802 if(priorimg_opt.size())
803 linePrior.resize(nclass,ncol);
807 vector<float> entropy(ncol);
809 if(classBag_opt.size())
810 classBag.resize(nbag,ncol);
814 for(
int iband=0;iband<band_opt.size();++iband){
815 if(verbose_opt[0]==2)
816 std::cout <<
"reading band " << band_opt[iband] << std::endl;
817 assert(band_opt[iband]>=0);
818 assert(band_opt[iband]<testImage.nrOfBand());
819 testImage.readData(buffer,GDT_Float32,iline,band_opt[iband]);
820 for(
int icol=0;icol<ncol;++icol)
821 hpixel[icol].push_back(buffer[icol]);
825 for(
int iband=bstart_opt[0];iband<bstart_opt[0]+nband;++iband){
826 if(verbose_opt[0]==2)
827 std::cout <<
"reading band " << iband << std::endl;
829 assert(iband<testImage.nrOfBand());
830 testImage.readData(buffer,GDT_Float32,iline,iband);
831 for(
int icol=0;icol<ncol;++icol)
832 hpixel[icol].push_back(buffer[icol]);
836 catch(
string theError){
837 cerr <<
"Error reading " << input_opt[0] <<
": " << theError << std::endl;
841 cerr <<
"error catched" << std::endl;
844 assert(nband==hpixel[0].size());
845 if(verbose_opt[0]==2)
846 cout <<
"used bands: " << nband << endl;
848 if(priorimg_opt.size()){
850 for(
short iclass=0;iclass<nclass;++iclass){
851 if(verbose_opt.size()>1)
852 std::cout <<
"Reading " << priorimg_opt[0] <<
" band " << iclass <<
" line " << iline << std::endl;
853 priorReader.readData(linePrior[iclass],GDT_Float32,iline,iclass);
856 catch(
string theError){
857 std::cerr <<
"Error reading " << priorimg_opt[0] <<
": " << theError << std::endl;
861 cerr <<
"error catched" << std::endl;
865 double oldRowMask=-1;
867 for(
int icol=0;icol<ncol;++icol){
868 assert(hpixel[icol].size()==nband);
877 testImage.image2geo(icol,iline,geox,geoy);
878 maskReader.geo2image(geox,geoy,colMask,rowMask);
879 colMask=
static_cast<int>(colMask);
880 rowMask=
static_cast<int>(rowMask);
881 if(rowMask>=0&&rowMask<maskReader.nrOfRow()&&colMask>=0&&colMask<maskReader.nrOfCol()){
882 if(static_cast<int>(rowMask)!=
static_cast<int>(oldRowMask)){
883 assert(rowMask>=0&&rowMask<maskReader.nrOfRow());
886 maskReader.readData(lineMask,GDT_Int16,static_cast<int>(rowMask));
888 catch(
string errorstring){
889 cerr << errorstring << endl;
893 cerr <<
"error catched" << std::endl;
899 for(
short ivalue=0;ivalue<msknodata_opt.size();++ivalue){
900 if(msknodata_opt[ivalue]>=0){
901 if(lineMask[colMask]==msknodata_opt[ivalue]){
902 theMask=lineMask[colMask];
908 if(lineMask[colMask]!=-msknodata_opt[ivalue]){
909 theMask=lineMask[colMask];
919 if(classBag_opt.size())
920 for(
int ibag=0;ibag<nbag;++ibag)
921 classBag[ibag][icol]=theMask;
922 classOut[icol]=theMask;
927 for(
int iband=0;iband<nband;++iband){
928 if(hpixel[icol][iband]){
934 if(classBag_opt.size())
935 for(
int ibag=0;ibag<nbag;++ibag)
936 classBag[ibag][icol]=nodata_opt[0];
937 classOut[icol]=nodata_opt[0];
941 for(
int iclass=0;iclass<nclass;++iclass)
942 probOut[iclass][icol]=0;
944 std::cout <<
"begin classification " << std::endl;
946 for(
int ibag=0;ibag<nbag;++ibag){
948 fpixel[icol].clear();
949 for(
int iband=0;iband<nband;++iband)
950 fpixel[icol].push_back((hpixel[icol][iband]-offset[ibag][iband])/scale[ibag][iband]);
951 vector<float> result(nclass);
952 result=net[ibag].run(fpixel[icol]);
954 vector<float> prValues(nclass);
958 if(classBag_opt.size()){
961 classBag[ibag][icol]=0;
964 if(priorimg_opt.size()){
965 for(
short iclass=0;iclass<nclass;++iclass)
966 normPrior+=linePrior[iclass][icol];
968 for(
int iclass=0;iclass<nclass;++iclass){
969 result[iclass]=(result[iclass]+1.0)/2.0;
970 if(priorimg_opt.size())
971 priors[iclass]=linePrior[iclass][icol]/normPrior;
975 probOut[iclass][icol]+=result[iclass]*priors[iclass];
978 probOut[iclass][icol]*=pow(static_cast<float>(priors[iclass]),static_cast<float>(1.0-nbag)/nbag)*result[iclass];
981 if(priors[iclass]*result[iclass]>probOut[iclass][icol])
982 probOut[iclass][icol]=priors[iclass]*result[iclass];
985 if(classBag_opt.size()){
991 if(result[iclass]>maxP){
993 classBag[ibag][icol]=iclass;
1003 for(
short iclass=0;iclass<nclass;++iclass){
1004 if(probOut[iclass][icol]>maxBag1){
1005 maxBag1=probOut[iclass][icol];
1006 classOut[icol]=classValueMap[nameVector[iclass]];
1008 else if(probOut[iclass][icol]>maxBag2)
1009 maxBag2=probOut[iclass][icol];
1010 normBag+=probOut[iclass][icol];
1014 for(
short iclass=0;iclass<nclass;++iclass){
1015 float prv=probOut[iclass][icol];
1017 entropy[icol]-=prv*log(prv)/log(2.0);
1020 probOut[iclass][icol]=
static_cast<short>(prv+0.5);
1025 entropy[icol]/=log(static_cast<double>(nclass))/log(2.0);
1026 entropy[icol]=
static_cast<short>(100*entropy[icol]+0.5);
1027 if(active_opt.size()){
1028 if(entropy[icol]>activePoints.back().value){
1029 activePoints.back().value=entropy[icol];
1030 activePoints.back().posx=icol;
1031 activePoints.back().posy=iline;
1034 std::cout << activePoints.back().posx <<
" " << activePoints.back().posy <<
" " << activePoints.back().value << std::endl;
1039 if(classBag_opt.size())
1040 for(
int ibag=0;ibag<nbag;++ibag)
1041 classImageBag.writeData(classBag[ibag],GDT_Byte,iline,ibag);
1042 if(prob_opt.size()){
1043 for(
int iclass=0;iclass<nclass;++iclass)
1044 probImage.writeData(probOut[iclass],GDT_Float32,iline,iclass);
1046 if(entropy_opt.size()){
1047 entropyImage.writeData(entropy,GDT_Float32,iline);
1049 classImageOut.writeData(classOut,GDT_Byte,iline);
1050 if(!verbose_opt[0]){
1051 progress=
static_cast<float>(iline+1.0)/classImageOut.nrOfRow();
1052 pfnProgress(progress,pszMessage,pProgressArg);
1056 if(active_opt.size()){
1057 for(
int iactive=0;iactive<activePoints.size();++iactive){
1058 std::map<string,double> pointMap;
1059 for(
int iband=0;iband<testImage.nrOfBand();++iband){
1061 testImage.readData(value,GDT_Float64,static_cast<int>(activePoints[iactive].posx),static_cast<int>(activePoints[iactive].posy),iband);
1064 pointMap[fs.str()]=value;
1066 pointMap[label_opt[0]]=0;
1068 testImage.image2geo(activePoints[iactive].posx,activePoints[iactive].posy,x,y);
1069 std::string fieldname=
"id";
1070 activeWriter.addPoint(x,y,pointMap,fieldname,++nactive);
1077 if(priorimg_opt.size())
1078 priorReader.close();
1081 if(entropy_opt.size())
1082 entropyImage.close();
1083 if(classBag_opt.size())
1084 classImageBag.close();
1085 classImageOut.close();
1090 for(
int ivalidation=0;ivalidation<input_opt.size();++ivalidation){
1091 if(output_opt.size())
1092 assert(output_opt.size()==input_opt.size());
1094 cout <<
"opening img reader " << input_opt[ivalidation] << endl;
1095 imgReaderOgr.open(input_opt[ivalidation]);
1098 if(output_opt.size()){
1100 std::cout <<
"opening img writer and copying fields from img reader" << output_opt[ivalidation] << std::endl;
1101 imgWriterOgr.open(output_opt[ivalidation],imgReaderOgr);
1104 cout <<
"number of layers in input ogr file: " << imgReaderOgr.getLayerCount() << endl;
1105 for(
int ilayer=0;ilayer<imgReaderOgr.getLayerCount();++ilayer){
1107 cout <<
"processing input layer " << ilayer << endl;
1108 if(output_opt.size()){
1110 std::cout <<
"creating field class" << std::endl;
1111 if(classValueMap.size())
1112 imgWriterOgr.createField(
"class",OFTInteger,ilayer);
1114 imgWriterOgr.createField(
"class",OFTString,ilayer);
1116 unsigned int nFeatures=imgReaderOgr.getFeatureCount(ilayer);
1117 unsigned int ifeature=0;
1119 pfnProgress(progress,pszMessage,pProgressArg);
1120 OGRFeature *poFeature;
1121 while( (poFeature = imgReaderOgr.getLayer(ilayer)->GetNextFeature()) != NULL ){
1122 if(verbose_opt[0]>1)
1123 cout <<
"feature " << ifeature << endl;
1124 if( poFeature == NULL ){
1125 cout <<
"Warning: could not read feature " << ifeature <<
" in layer " << imgReaderOgr.getLayerName(ilayer) << endl;
1128 OGRFeature *poDstFeature = NULL;
1129 if(output_opt.size()){
1130 poDstFeature=imgWriterOgr.createFeature(ilayer);
1131 if( poDstFeature->SetFrom( poFeature, TRUE ) != OGRERR_NONE ){
1132 CPLError( CE_Failure, CPLE_AppDefined,
1133 "Unable to translate feature %d from layer %s.\n",
1134 poFeature->GetFID(), imgWriterOgr.getLayerName(ilayer).c_str() );
1135 OGRFeature::DestroyFeature( poFeature );
1136 OGRFeature::DestroyFeature( poDstFeature );
1139 vector<float> validationPixel;
1140 vector<float> validationFeature;
1142 imgReaderOgr.readData(validationPixel,OFTReal,fields,poFeature,ilayer);
1143 assert(validationPixel.size()==nband);
1144 vector<float> probOut(nclass);
1145 for(
int iclass=0;iclass<nclass;++iclass)
1147 for(
int ibag=0;ibag<nbag;++ibag){
1148 for(
int iband=0;iband<nband;++iband){
1149 validationFeature.push_back((validationPixel[iband]-offset[ibag][iband])/scale[ibag][iband]);
1150 if(verbose_opt[0]==2)
1151 std:: cout <<
" " << validationFeature.back();
1153 if(verbose_opt[0]==2)
1154 std::cout << std:: endl;
1155 vector<float> result(nclass);
1156 result=net[ibag].run(validationFeature);
1158 if(verbose_opt[0]>1){
1159 for(
int iclass=0;iclass<result.size();++iclass)
1160 std::cout << result[iclass] <<
" ";
1161 std::cout << std::endl;
1164 for(
int iclass=0;iclass<nclass;++iclass){
1165 result[iclass]=(result[iclass]+1.0)/2.0;
1166 switch(comb_opt[0]){
1169 probOut[iclass]+=result[iclass]*priors[iclass];
1172 probOut[iclass]*=pow(static_cast<float>(priors[iclass]),static_cast<float>(1.0-nbag)/nbag)*result[iclass];
1175 if(priors[iclass]*result[iclass]>probOut[iclass])
1176 probOut[iclass]=priors[iclass]*result[iclass];
1184 string classOut=
"Unclassified";
1185 for(
int iclass=0;iclass<nclass;++iclass){
1186 if(verbose_opt[0]>1)
1187 std::cout << probOut[iclass] <<
" ";
1188 if(probOut[iclass]>maxBag){
1189 maxBag=probOut[iclass];
1190 classOut=nameVector[iclass];
1194 if(verbose_opt[0]>1){
1195 if(classValueMap.size())
1196 std::cout <<
"->" << classValueMap[classOut] << std::endl;
1198 std::cout <<
"->" << classOut << std::endl;
1200 if(output_opt.size()){
1201 if(classValueMap.size())
1202 poDstFeature->SetField(
"class",classValueMap[classOut]);
1204 poDstFeature->SetField(
"class",classOut.c_str());
1205 poDstFeature->SetFID( poFeature->GetFID() );
1207 int labelIndex=poFeature->GetFieldIndex(label_opt[0].c_str());
1209 string classRef=poFeature->GetFieldAsString(labelIndex);
1211 if(classValueMap.size())
1212 cm.incrementResult(type2string<short>(classValueMap[classRef]),type2string<short>(classValueMap[classOut]),1);
1214 cm.incrementResult(classRef,classOut,1);
1218 if(output_opt.size()){
1219 if(imgWriterOgr.createFeature(poDstFeature,ilayer) != OGRERR_NONE){
1220 CPLError( CE_Failure, CPLE_AppDefined,
1221 "Unable to translate feature %d from layer %s.\n",
1222 poFeature->GetFID(), imgWriterOgr.getLayerName(ilayer).c_str() );
1223 OGRFeature::DestroyFeature( poDstFeature );
1224 OGRFeature::DestroyFeature( poDstFeature );
1228 if(!verbose_opt[0]){
1229 progress=
static_cast<float>(ifeature+1.0)/nFeatures;
1230 pfnProgress(progress,pszMessage,pProgressArg);
1232 OGRFeature::DestroyFeature( poFeature );
1233 OGRFeature::DestroyFeature( poDstFeature );
1236 imgReaderOgr.close();
1237 if(output_opt.size())
1238 imgWriterOgr.close();
1240 if(cm.nReference()){
1241 std::cout << cm << std::endl;
1260 if(active_opt.size())
1261 activeWriter.close();
1263 catch(
string errorString){
1264 std::cerr <<
"Error: errorString" << std::endl;