pktools 2.6.7
Processing Kernel for geospatial data
pkann.cc
1/**********************************************************************
2pkann.cc: classify raster image using Artificial Neural Network
3Copyright (C) 2008-2014 Pieter Kempeneers
4
5This file is part of pktools
6
7pktools is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
11
12pktools is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with pktools. If not, see <http://www.gnu.org/licenses/>.
19***********************************************************************/
20#include <stdlib.h>
21#include <vector>
22#include <map>
23#include <algorithm>
24#include "imageclasses/ImgReaderGdal.h"
25#include "imageclasses/ImgWriterGdal.h"
26#include "imageclasses/ImgReaderOgr.h"
27#include "imageclasses/ImgWriterOgr.h"
28#include "base/Optionpk.h"
29#include "base/PosValue.h"
30#include "algorithms/ConfusionMatrix.h"
31#include "floatfann.h"
32#include "algorithms/myfann_cpp.h"
33
34/******************************************************************************/
108using namespace std;
109
110int main(int argc, char *argv[])
111{
112 vector<double> priors;
113
114 //--------------------------- command line options ------------------------------------
115 Optionpk<string> input_opt("i", "input", "input image");
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)");
117 Optionpk<string> tlayer_opt("tln", "tln", "training layer name(s)");
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)");
123 Optionpk<unsigned short> bstart_opt("sband", "startband", "Start band sequence number");
124 Optionpk<unsigned short> bend_opt("eband", "endband", "End band sequence number");
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);
130 Optionpk<unsigned short> cv_opt("cv", "cv", "n-fold cross validation mode",0);
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);
138 Optionpk<unsigned short> bag_opt("bag", "bag", "Number of bootstrap aggregations (default is no bagging: 1)", 1);
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);
143 Optionpk<unsigned short> nodata_opt("nodata", "nodata", "nodata value to put where image is masked as nodata", 0);
144 Optionpk<string> output_opt("o", "output", "output classification image");
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");
153 Optionpk<unsigned int> nactive_opt("na", "nactive", "number of active training points",1);
154 Optionpk<string> classname_opt("c", "class", "list of class names.");
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);
157
158 option_opt.setHide(1);
159 oformat_opt.setHide(1);
160 band_opt.setHide(1);
161 bstart_opt.setHide(1);
162 bend_opt.setHide(1);
163 balance_opt.setHide(1);
164 minSize_opt.setHide(1);
165 bag_opt.setHide(1);
166 bagSize_opt.setHide(1);
167 comb_opt.setHide(1);
168 classBag_opt.setHide(1);
169 minSize_opt.setHide(1);
170 prob_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);
179
180 verbose_opt.setHide(2);
181
182 bool doProcess;//stop process when program was invoked with help option (-h --help)
183 try{
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);
226 }
227 catch(string predefinedString){
228 std::cout << predefinedString << std::endl;
229 exit(0);
230 }
231 if(!doProcess){
232 cout << endl;
233 cout << "Usage: pkann -t training [-i input -o output] [-cv value]" << endl;
234 cout << endl;
235 cout << "short option -h shows basic options only, use long option --help to show all options" << endl;
236 exit(0);//help was invoked, stop processing
237 }
238
239 if(entropy_opt[0]=="")
240 entropy_opt.clear();
241 if(active_opt[0]=="")
242 active_opt.clear();
243 if(priorimg_opt[0]=="")
244 priorimg_opt.clear();
245
246 if(verbose_opt[0]>=1){
247 if(input_opt.size())
248 cout << "image filename: " << input_opt[0] << endl;
249 if(mask_opt.size())
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;
255 }
256 else
257 cerr << "no training file set!" << endl;
258 cout << "verbose: " << verbose_opt[0] << endl;
259 }
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;
263
264 ImgReaderOgr extentReader;
265 OGRLayer *readLayer;
266
267 double ulx=0;
268 double uly=0;
269 double lrx=0;
270 double lry=0;
271
272 bool maskIsVector=false;
273 if(mask_opt.size()){
274 try{
275 extentReader.open(mask_opt[0]);
276 maskIsVector=true;
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;
280 exit(1);
281 }
282 }
283 catch(string errorString){
284 maskIsVector=false;
285 }
286 }
287
288 ImgWriterOgr activeWriter;
289 if(active_opt.size()){
290 ImgReaderOgr trainingReader(training_opt[0]);
291 activeWriter.open(active_opt[0],ogrformat_opt[0]);
292 activeWriter.createLayer(active_opt[0],trainingReader.getProjection(),wkbPoint,NULL);
293 activeWriter.copyFields(trainingReader);
294 }
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;
300 }
301
302 unsigned int totalSamples=0;
303 unsigned int nactive=0;
304 vector<FANN::neural_net> net(nbag);//the neural network
305
306 unsigned int nclass=0;
307 int nband=0;
308 int startBand=2;//first two bands represent X and Y pos
309
310 if(priors_opt.size()>1){//priors from argument list
311 priors.resize(priors_opt.size());
312 double normPrior=0;
313 for(int iclass=0;iclass<priors_opt.size();++iclass){
314 priors[iclass]=priors_opt[iclass];
315 normPrior+=priors[iclass];
316 }
317 //normalize
318 for(int iclass=0;iclass<priors_opt.size();++iclass)
319 priors[iclass]/=normPrior;
320 }
321
322 //convert start and end band options to vector of band indexes
323 try{
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";
327 throw(errorstring);
328 }
329 band_opt.clear();
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";
333 throw(errorstring);
334 }
335 for(int iband=bstart_opt[ipair];iband<=bend_opt[ipair];++iband)
336 band_opt.push_back(iband);
337 }
338 }
339 }
340 catch(string error){
341 cerr << error << std::endl;
342 exit(1);
343 }
344 //sort bands
345 if(band_opt.size())
346 std::sort(band_opt.begin(),band_opt.end());
347
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];
354 }
355 //----------------------------------- Training -------------------------------
357 vector< vector<double> > offset(nbag);
358 vector< vector<double> > scale(nbag);
359 map<string,Vector2d<float> > trainingMap;
360 vector< Vector2d<float> > trainingPixels;//[class][sample][band]
361 vector<string> fields;
362 for(int ibag=0;ibag<nbag;++ibag){
363 //organize training data
364 if(ibag<training_opt.size()){//if bag contains new training pixels
365 trainingMap.clear();
366 trainingPixels.clear();
367 if(verbose_opt[0]>=1)
368 cout << "reading imageVector file " << training_opt[0] << endl;
369 try{
370 ImgReaderOgr trainingReaderBag(training_opt[ibag]);
371 if(band_opt.size())
372 totalSamples=trainingReaderBag.readDataImageOgr(trainingMap,fields,band_opt,label_opt[0],tlayer_opt);
373 else
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)?";
377 throw(errorstring);
378 }
379 trainingReaderBag.close();
380 }
381 catch(string error){
382 cerr << error << std::endl;
383 exit(1);
384 }
385 catch(...){
386 cerr << "error caught" << std::endl;
387 exit(1);
388 }
389 //delete class 0 ?
390 // if(verbose_opt[0]>=1)
391 // std::cout << "erasing class 0 from training set (" << trainingMap[0].size() << " from " << totalSamples << ") samples" << std::endl;
392 // totalSamples-=trainingMap[0].size();
393 // trainingMap.erase(0);
394 //convert map to vector
395 if(verbose_opt[0]>1)
396 std::cout << "training pixels: " << std::endl;
397 map<string,Vector2d<float> >::iterator mapit=trainingMap.begin();
398 while(mapit!=trainingMap.end()){
399 //delete small classes
400 if((mapit->second).size()<minSize_opt[0]){
401 trainingMap.erase(mapit);
402 continue;
403 }
404 trainingPixels.push_back(mapit->second);
405 if(verbose_opt[0]>1)
406 std::cout << mapit->first << ": " << (mapit->second).size() << " samples" << std::endl;
407 ++mapit;
408 }
409 if(!ibag){
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();//X and Y
414 }
415 else{
416 assert(nclass==trainingPixels.size());
417 assert(nband==(training_opt.size())?trainingPixels[0][0].size()-2:trainingPixels[0][0].size());
418 }
419
420 //do not remove outliers here: could easily be obtained through ogr2ogr -where 'B2<110' output.shp input.shp
421 //balance training data
422 if(balance_opt[0]>0){
423 while(balance_opt.size()<nclass)
424 balance_opt.push_back(balance_opt.back());
425 if(random_opt[0])
426 srand(time(NULL));
427 totalSamples=0;
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);
433 }
434 }
435 else{
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]);
440 }
441 }
442 totalSamples+=trainingPixels[iclass].size();
443 }
444 }
445
446 //set scale and offset
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];
458 //search for min and maximum
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];
468 }
469 }
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;
476 }
477 }
478 }
479 }
480 else{//use same offset and scale
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];
486 }
487 }
488
489 if(!ibag){
490 if(priors_opt.size()==1){//default: equal priors for each class
491 priors.resize(nclass);
492 for(int iclass=0;iclass<nclass;++iclass)
493 priors[iclass]=1.0/nclass;
494 }
495 assert(priors_opt.size()==1||priors_opt.size()==nclass);
496
497 //set bagsize for each class if not done already via command line
498 while(bagSize_opt.size()<nclass)
499 bagSize_opt.push_back(bagSize_opt.back());
500
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;
509 }
510 }
511 map<string,Vector2d<float> >::iterator mapit=trainingMap.begin();
512 bool doSort=true;
513 while(mapit!=trainingMap.end()){
514 nameVector.push_back(mapit->first);
515 if(classValueMap.size()){
516 //check if name in training is covered by classname_opt (values can not be 0)
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);
520 }
521 else{
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;
523 exit(1);
524 }
525 }
526 else
527 cm.pushBackClassName(mapit->first,doSort);
528 ++mapit;
529 }
530 if(classname_opt.empty()){
531 //std::cerr << "Warning: no class name and value pair provided for all " << nclass << " classes, using string2type<int> instead!" << std::endl;
532 for(int iclass=0;iclass<nclass;++iclass){
533 if(verbose_opt[0])
534 std::cout << iclass << " " << cm.getClass(iclass) << " -> " << string2type<short>(cm.getClass(iclass)) << std::endl;
535 classValueMap[cm.getClass(iclass)]=string2type<short>(cm.getClass(iclass));
536 }
537 }
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;
542 }
543 }//if(!ibag)
544
545 //Calculate features of training set
546 vector< Vector2d<float> > trainingFeatures(nclass);
547 for(int iclass=0;iclass<nclass;++iclass){
548 int nctraining=0;
549 if(verbose_opt[0]>=1)
550 cout << "calculating features for class " << iclass << endl;
551 if(random_opt[0])
552 srand(time(NULL));
553 nctraining=(bagSize_opt[iclass]<100)? trainingPixels[iclass].size()/100.0*bagSize_opt[iclass] : trainingPixels[iclass].size();//bagSize_opt[iclass] given in % of training size
554 if(nctraining<=0)
555 nctraining=1;
556 assert(nctraining<=trainingPixels[iclass].size());
557 int index=0;
558 if(bagSize_opt[iclass]<100)
559 random_shuffle(trainingPixels[iclass].begin(),trainingPixels[iclass].end());
560
561 trainingFeatures[iclass].resize(nctraining);
562 for(int isample=0;isample<nctraining;++isample){
563 //scale pixel values according to scale and offset!!!
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]);
567 }
568 }
569 assert(trainingFeatures[iclass].size()==nctraining);
570 }
571
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();
576
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;
591 }
592 switch(num_layers){
593 case(3):{
594 // net[ibag].create_sparse(connection_opt[0],num_layers, nFeatures, nneuron_opt[0], nclass);//replace all create_sparse with create_sparse_array due to bug in FANN!
595 unsigned int layers[3];
596 layers[0]=nFeatures;
597 layers[1]=nneuron_opt[0];
598 layers[2]=nclass;
599 net[ibag].create_sparse_array(connection_opt[0],num_layers,layers);
600 break;
601 }
602 case(4):{
603 unsigned int layers[4];
604 layers[0]=nFeatures;
605 layers[1]=nneuron_opt[0];
606 layers[2]=nneuron_opt[1];
607 layers[3]=nclass;
608 // layers.push_back(nFeatures);
609 // for(int ihidden=0;ihidden<nneuron_opt.size();++ihidden)
610 // layers.push_back(nneuron_opt[ihidden]);
611 // layers.push_back(nclass);
612 net[ibag].create_sparse_array(connection_opt[0],num_layers,layers);
613 break;
614 }
615 default:
616 cerr << "Only 1 or 2 hidden layers are supported!" << endl;
617 exit(1);
618 break;
619 }
620 if(verbose_opt[0]>=1)
621 cout << "network created" << endl;
622
623 net[ibag].set_learning_rate(learning_opt[0]);
624
625 // net.set_activation_steepness_hidden(1.0);
626 // net.set_activation_steepness_output(1.0);
627
628 net[ibag].set_activation_function_hidden(FANN::SIGMOID_SYMMETRIC_STEPWISE);
629 net[ibag].set_activation_function_output(FANN::SIGMOID_SYMMETRIC_STEPWISE);
630
631 // Set additional properties such as the training algorithm
632 // net.set_training_algorithm(FANN::TRAIN_QUICKPROP);
633
634 // Output network type and parameters
635 if(verbose_opt[0]>=1){
636 cout << endl << "Network Type : ";
637 switch (net[ibag].get_network_type())
638 {
639 case FANN::LAYER:
640 cout << "LAYER" << endl;
641 break;
642 case FANN::SHORTCUT:
643 cout << "SHORTCUT" << endl;
644 break;
645 default:
646 cout << "UNKNOWN" << endl;
647 break;
648 }
649 net[ibag].print_parameters();
650 }
651
652 if(cv_opt[0]>1){
653 if(verbose_opt[0])
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,
658 ntraining,
659 cv_opt[0],
660 maxit_opt[0],
661 desired_error,
662 referenceVector,
663 outputVector,
664 verbose_opt[0]);
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);
671 else
672 cm.incrementResult(cm.getClass(referenceVector[isample]),cm.getClass(outputVector[isample]),1.0/nbag);
673 }
674 }
675
676 if(verbose_opt[0]>=1)
677 cout << endl << "Set training data" << endl;
678
679 if(verbose_opt[0]>=1)
680 cout << endl << "Training network" << endl;
681
682 if(verbose_opt[0]>=1){
683 cout << "Max Epochs " << setw(8) << maxit_opt[0] << ". "
684 << "Desired Error: " << left << desired_error << right << endl;
685 }
686 if(weights_opt.size()==net[ibag].get_total_connections()){//no new training needed (same training sample)
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);
692 }
693 else{
694 bool initWeights=true;
695 net[ibag].train_on_data(trainingFeatures,ntraining,initWeights, maxit_opt[0],
696 iterations_between_reports, desired_error);
697 }
698
699
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;
706
707 }
708 }//for ibag
709 if(cv_opt[0]>1){
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;
715 double se95_ua=0;
716 double se95_pa=0;
717 double se95_oa=0;
718 double dua=0;
719 double dpa=0;
720 double doa=0;
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;
725 }
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;
729 }
730 //--------------------------------- end of training -----------------------------------
731 if(input_opt.empty())
732 exit(0);
733
734 const char* pszMessage;
735 void* pProgressArg=NULL;
736 GDALProgressFunc pfnProgress=GDALTermProgress;
737 float progress=0;
738 //-------------------------------- open image file ------------------------------------
739 bool inputIsRaster=true;
740 ImgReaderOgr imgReaderOgr;
741 if(inputIsRaster){
742 // if(input_opt[0].find(".shp")==string::npos){
743 ImgReaderGdal testImage;
744 try{
745 if(verbose_opt[0]>=1)
746 cout << "opening image " << input_opt[0] << endl;
747 testImage.open(input_opt[0]);
748 }
749 catch(string error){
750 cerr << error << endl;
751 exit(2);
752 }
753 ImgReaderGdal priorReader;
754 if(priorimg_opt.size()){
755 try{
756 if(verbose_opt[0]>=1)
757 std::cout << "opening prior image " << priorimg_opt[0] << std::endl;
758 priorReader.open(priorimg_opt[0]);
759 assert(priorReader.nrOfCol()==testImage.nrOfCol());
760 assert(priorReader.nrOfRow()==testImage.nrOfRow());
761 }
762 catch(string error){
763 cerr << error << std::endl;
764 exit(2);
765 }
766 catch(...){
767 cerr << "error caught" << std::endl;
768 exit(1);
769 }
770 }
771
772 int nrow=testImage.nrOfRow();
773 int ncol=testImage.nrOfCol();
774 if(option_opt.findSubstring("INTERLEAVE=")==option_opt.end()){
775 string theInterleave="INTERLEAVE=";
776 theInterleave+=testImage.getInterleave();
777 option_opt.push_back(theInterleave);
778 }
779 vector<char> classOut(ncol);//classified line for writing to image file
780
781 // assert(nband==testImage.nrOfBand());
782 ImgWriterGdal classImageBag;
783 ImgWriterGdal classImageOut;
784 ImgWriterGdal probImage;
785 ImgWriterGdal entropyImage;
786
787 string imageType;//testImage.getImageType();
788 if(oformat_opt.size())//default
789 imageType=oformat_opt[0];
790 try{
791
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);
796 classImageBag.GDALSetNoDataValue(nodata_opt[0]);
797 classImageBag.copyGeoTransform(testImage);
798 classImageBag.setProjection(testImage.getProjection());
799 }
800 classImageOut.open(output_opt[0],ncol,nrow,1,GDT_Byte,imageType,option_opt);
801 classImageOut.GDALSetNoDataValue(nodata_opt[0]);
802 classImageOut.copyGeoTransform(testImage);
803 classImageOut.setProjection(testImage.getProjection());
804 if(colorTable_opt.size())
805 classImageOut.setColorTable(colorTable_opt[0],0);
806 if(prob_opt.size()){
807 probImage.open(prob_opt[0],ncol,nrow,nclass,GDT_Byte,imageType,option_opt);
808 probImage.GDALSetNoDataValue(nodata_opt[0]);
809 probImage.copyGeoTransform(testImage);
810 probImage.setProjection(testImage.getProjection());
811 }
812 if(entropy_opt.size()){
813 entropyImage.open(entropy_opt[0],ncol,nrow,1,GDT_Byte,imageType,option_opt);
814 entropyImage.GDALSetNoDataValue(nodata_opt[0]);
815 entropyImage.copyGeoTransform(testImage);
816 entropyImage.setProjection(testImage.getProjection());
817 }
818 }
819 catch(string error){
820 cerr << error << endl;
821 }
822
823 ImgWriterGdal maskWriter;
824
825 if(maskIsVector){
826 try{
827 maskWriter.open("/vsimem/mask.tif",ncol,nrow,1,GDT_Float32,imageType,option_opt);
828 maskWriter.GDALSetNoDataValue(nodata_opt[0]);
829 maskWriter.copyGeoTransform(testImage);
830 maskWriter.setProjection(testImage.getProjection());
831 vector<double> burnValues(1,1);//burn value is 1 (single band)
832 maskWriter.rasterizeOgr(extentReader,burnValues);
833 extentReader.close();
834 maskWriter.close();
835 }
836 catch(string error){
837 cerr << error << std::endl;
838 exit(2);
839 }
840 catch(...){
841 cerr << "error caught" << std::endl;
842 exit(1);
843 }
844 mask_opt.clear();
845 mask_opt.push_back("/vsimem/mask.tif");
846 }
847 ImgReaderGdal maskReader;
848 if(mask_opt.size()){
849 try{
850 if(verbose_opt[0]>=1)
851 std::cout << "opening mask image file " << mask_opt[0] << std::endl;
852 maskReader.open(mask_opt[0]);
853 }
854 catch(string error){
855 cerr << error << std::endl;
856 exit(2);
857 }
858 catch(...){
859 cerr << "error caught" << std::endl;
860 exit(1);
861 }
862 }
863
864 for(int iline=0;iline<nrow;++iline){
865 vector<float> buffer(ncol);
866 vector<short> lineMask;
867 if(mask_opt.size())
868 lineMask.resize(maskReader.nrOfCol());
869 Vector2d<float> linePrior;
870 if(priorimg_opt.size())
871 linePrior.resize(nclass,ncol);//prior prob for each class
872 Vector2d<float> hpixel(ncol);
873 Vector2d<float> fpixel(ncol);
874 Vector2d<float> probOut(nclass,ncol);//posterior prob for each (internal) class
875 vector<float> entropy(ncol);
876 Vector2d<char> classBag;//classified line for writing to image file
877 if(classBag_opt.size())
878 classBag.resize(nbag,ncol);
879 //read all bands of all pixels in this line in hline
880 try{
881 if(band_opt.size()){
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]);
890 }
891 }
892 else{
893 for(int iband=0;iband<nband;++iband){
894 if(verbose_opt[0]==2)
895 std::cout << "reading band " << iband << std::endl;
896 assert(iband>=0);
897 assert(iband<testImage.nrOfBand());
898 testImage.readData(buffer,iline,iband);
899 for(int icol=0;icol<ncol;++icol)
900 hpixel[icol].push_back(buffer[icol]);
901 }
902 }
903 }
904 catch(string theError){
905 cerr << "Error reading " << input_opt[0] << ": " << theError << std::endl;
906 exit(3);
907 }
908 catch(...){
909 cerr << "error caught" << std::endl;
910 exit(3);
911 }
912 assert(nband==hpixel[0].size());
913 if(verbose_opt[0]==2)
914 cout << "used bands: " << nband << endl;
915 //read prior
916 if(priorimg_opt.size()){
917 try{
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);
922 }
923 }
924 catch(string theError){
925 std::cerr << "Error reading " << priorimg_opt[0] << ": " << theError << std::endl;
926 exit(3);
927 }
928 catch(...){
929 cerr << "error caught" << std::endl;
930 exit(3);
931 }
932 }
933 double oldRowMask=-1;//keep track of row mask to optimize number of line readings
934 //process per pixel
935 for(int icol=0;icol<ncol;++icol){
936 assert(hpixel[icol].size()==nband);
937 bool doClassify=true;
938 bool masked=false;
939 double geox=0;
940 double geoy=0;
941 if(maskIsVector){
942 doClassify=false;
943 testImage.image2geo(icol,iline,geox,geoy);
944 //check enveloppe first
945 if(uly>=geoy&&lry<=geoy&&ulx<=geox&&lrx>=geox){
946 doClassify=true;
947 }
948 }
949 if(mask_opt.size()){
950 //read mask
951 double colMask=0;
952 double rowMask=0;
953
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());
961 try{
962 // maskReader.readData(lineMask[imask],GDT_Int32,static_cast<int>(rowMask));
963 maskReader.readData(lineMask,static_cast<int>(rowMask));
964 }
965 catch(string errorstring){
966 cerr << errorstring << endl;
967 exit(1);
968 }
969 catch(...){
970 cerr << "error caught" << std::endl;
971 exit(3);
972 }
973 oldRowMask=rowMask;
974 }
975 short theMask=0;
976 for(short ivalue=0;ivalue<msknodata_opt.size();++ivalue){
977 // if(msknodata_opt[ivalue]>=0){//values set in msknodata_opt are invalid
978 if(lineMask[colMask]==msknodata_opt[ivalue]){
979 theMask=lineMask[colMask];
980 masked=true;
981 break;
982 }
983 // }
984 // else{//only values set in msknodata_opt are valid
985 // if(lineMask[colMask]!=-msknodata_opt[ivalue]){
986 // theMask=lineMask[colMask];
987 // masked=true;
988 // }
989 // else{
990 // masked=false;
991 // break;
992 // }
993 // }
994 }
995 if(masked){
996 if(classBag_opt.size())
997 for(int ibag=0;ibag<nbag;++ibag)
998 classBag[ibag][icol]=theMask;
999 classOut[icol]=theMask;
1000 continue;
1001 }
1002 }
1003 bool valid=false;
1004 for(int iband=0;iband<hpixel[icol].size();++iband){
1005 if(hpixel[icol][iband]){
1006 valid=true;
1007 break;
1008 }
1009 }
1010 if(!valid)
1011 doClassify=false;
1012
1013 }
1014 for(short iclass=0;iclass<nclass;++iclass)
1015 probOut[iclass][icol]=0;
1016 if(!doClassify){
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];
1021 continue;//next column
1022 }
1023 if(verbose_opt[0]>1)
1024 std::cout << "begin classification " << std::endl;
1025 //----------------------------------- classification -------------------
1026 for(int ibag=0;ibag<nbag;++ibag){
1027 //calculate image features
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]);
1033 int maxClass=0;
1034 vector<float> prValues(nclass);
1035 float maxP=0;
1036
1037 //calculate posterior prob of bag
1038 if(classBag_opt.size()){
1039 //search for max prob within bag
1040 maxP=0;
1041 classBag[ibag][icol]=0;
1042 }
1043 double normPrior=0;
1044 if(priorimg_opt.size()){
1045 for(short iclass=0;iclass<nclass;++iclass)
1046 normPrior+=linePrior[iclass][icol];
1047 }
1048 for(int iclass=0;iclass<nclass;++iclass){
1049 result[iclass]=(result[iclass]+1.0)/2.0;//bring back to scale [0,1]
1050 if(priorimg_opt.size())
1051 priors[iclass]=linePrior[iclass][icol]/normPrior;//todo: check if correct for all cases... (automatic classValueMap and manual input for names and values)
1052 switch(comb_opt[0]){
1053 default:
1054 case(0)://sum rule
1055 probOut[iclass][icol]+=result[iclass]*priors[iclass];//add probabilities for each bag
1056 break;
1057 case(1)://product rule
1058 probOut[iclass][icol]*=pow(static_cast<float>(priors[iclass]),static_cast<float>(1.0-nbag)/nbag)*result[iclass];//multiply probabilities for each bag
1059 break;
1060 case(2)://max rule
1061 if(priors[iclass]*result[iclass]>probOut[iclass][icol])
1062 probOut[iclass][icol]=priors[iclass]*result[iclass];
1063 break;
1064 }
1065 if(classBag_opt.size()){
1066 //search for max prob within bag
1067 // if(prValues[iclass]>maxP){
1068 // maxP=prValues[iclass];
1069 // classBag[ibag][icol]=vcode[iclass];
1070 // }
1071 if(result[iclass]>maxP){
1072 maxP=result[iclass];
1073 classBag[ibag][icol]=iclass;
1074 }
1075 }
1076 }
1077 }//ibag
1078
1079 //search for max class prob
1080 float maxBag1=0;//max probability
1081 float maxBag2=0;//second max probability
1082 float normBag=0;
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]];
1087 }
1088 else if(probOut[iclass][icol]>maxBag2)
1089 maxBag2=probOut[iclass][icol];
1090 normBag+=probOut[iclass][icol];
1091 }
1092 //normalize probOut and convert to percentage
1093 entropy[icol]=0;
1094 for(short iclass=0;iclass<nclass;++iclass){
1095 float prv=probOut[iclass][icol];
1096 prv/=normBag;
1097 entropy[icol]-=prv*log(prv)/log(2.0);
1098 prv*=100.0;
1099
1100 probOut[iclass][icol]=static_cast<short>(prv+0.5);
1101 // assert(classValueMap[nameVector[iclass]]<probOut.size());
1102 // assert(classValueMap[nameVector[iclass]]>=0);
1103 // probOut[classValueMap[nameVector[iclass]]][icol]=static_cast<short>(prv+0.5);
1104 }
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];//replace largest value (last)
1110 activePoints.back().posx=icol;
1111 activePoints.back().posy=iline;
1112 std::sort(activePoints.begin(),activePoints.end(),Decrease_PosValue());//sort in descending order (largest first, smallest last)
1113 if(verbose_opt[0])
1114 std::cout << activePoints.back().posx << " " << activePoints.back().posy << " " << activePoints.back().value << std::endl;
1115 }
1116 }
1117 }//icol
1118 //----------------------------------- write output ------------------------------------------
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);
1125 }
1126 if(entropy_opt.size()){
1127 entropyImage.writeData(entropy,iline);
1128 }
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);
1133 }
1134 }
1135 //write active learning points
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){
1140 double value;
1141 testImage.readData(value,static_cast<int>(activePoints[iactive].posx),static_cast<int>(activePoints[iactive].posy),iband);
1142 ostringstream fs;
1143 fs << "B" << iband;
1144 pointMap[fs.str()]=value;
1145 }
1146 pointMap[label_opt[0]]=0;
1147 double x, y;
1148 testImage.image2geo(activePoints[iactive].posx,activePoints[iactive].posy,x,y);
1149 std::string fieldname="id";//number of the point
1150 activeWriter.addPoint(x,y,pointMap,fieldname,++nactive);
1151 }
1152 }
1153
1154 testImage.close();
1155 if(mask_opt.size())
1156 maskReader.close();
1157 if(priorimg_opt.size())
1158 priorReader.close();
1159 if(prob_opt.size())
1160 probImage.close();
1161 if(entropy_opt.size())
1162 entropyImage.close();
1163 if(classBag_opt.size())
1164 classImageBag.close();
1165 classImageOut.close();
1166 }
1167 try{
1168 if(active_opt.size())
1169 activeWriter.close();
1170 }
1171 catch(string errorString){
1172 std::cerr << "Error: errorString" << std::endl;
1173 }
1174 return 0;
1175}
int nrOfRow(void) const
Get the number of rows of this dataset.
bool geo2image(double x, double y, double &i, double &j) const
Convert georeferenced coordinates (x and y) to image coordinates (column and row)
std::string getProjection(void) const
Get the projection string (deprecated, use getProjectionRef instead)
int nrOfBand(void) const
Get the number of bands of this dataset.
void copyGeoTransform(const ImgRasterGdal &imgSrc)
Copy geotransform information from another georeferenced image.
int nrOfCol(void) const
Get the number of columns of this dataset.
Definition: ImgRasterGdal.h:98
std::string getInterleave() const
Get the band coding (interleave)
bool image2geo(double i, double j, double &x, double &y) const
Convert image coordinates (column and row) to georeferenced coordinates (x and y)
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...
CPLErr setProjection(const std::string &projection)
Set the projection for this dataset in well known text (wkt) format.
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...
Definition: ImgReaderGdal.h:95
void close(void)
Set the memory (in MB) to cache a number of rows in memory.
void open(const std::string &filename, const GDALAccess &readMode=GA_ReadOnly)
Open an image.
void close(void)
Close the 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...
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".
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)
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...
Definition: ImgWriterGdal.h:96