21 #include "imageclasses/ImgReaderGdal.h"
22 #include "imageclasses/ImgWriterGdal.h"
23 #include "imageclasses/ImgReaderOgr.h"
24 #include "imageclasses/ImgWriterOgr.h"
25 #include "base/Optionpk.h"
26 #include "algorithms/ConfusionMatrix.h"
95 int main(
int argc,
char *argv[])
98 Optionpk<string> reference_opt(
"ref",
"reference",
"Reference (raster or vector) dataset");
99 Optionpk<string> layer_opt(
"ln",
"ln",
"Layer name(s) in sample. Leave empty to select all (for vector reference datasets only)");
100 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.");
101 Optionpk<double> msknodata_opt(
"msknodata",
"msknodata",
"Mask value(s) where image is invalid. Use negative value for valid data (example: use -t -1: if only -1 is valid value)", 0);
102 Optionpk<double> nodata_opt(
"nodata",
"nodata",
"No data value(s) in input or reference dataset are ignored");
103 Optionpk<short> band_opt(
"b",
"band",
"Input (reference) raster band. Optionally, you can define different bands for input and reference bands respectively: -b 1 -b 0.", 0);
104 Optionpk<bool> rmse_opt(
"rmse",
"rmse",
"Report root mean squared error",
false);
105 Optionpk<bool> regression_opt(
"reg",
"reg",
"Report linear regression (Input = c0+c1*Reference)",
false);
106 Optionpk<bool> confusion_opt(
"cm",
"confusion",
"Create confusion matrix (to std out)",
false);
107 Optionpk<string> cmformat_opt(
"cmf",
"cmf",
"Format for confusion matrix (ascii or latex)",
"ascii");
108 Optionpk<string> cmoutput_opt(
"cmo",
"cmo",
"Output file for confusion matrix");
109 Optionpk<bool> se95_opt(
"se95",
"se95",
"Report standard error for 95 confidence interval",
false);
110 Optionpk<string> labelref_opt(
"lr",
"lref",
"Attribute name of the reference label (for vector reference datasets only)",
"label");
112 Optionpk<short> classvalue_opt(
"r",
"reclass",
"List of class values (use same order as in classname option).");
114 Optionpk<string> ogrformat_opt(
"f",
"f",
"OGR format for output vector (for vector reference datasets only)",
"SQLite");
115 Optionpk<string> oformat_opt(
"of",
"oformat",
"Output image format (see also gdal_translate).",
"GTiff");
116 Optionpk<string> labelclass_opt(
"lc",
"lclass",
"Attribute name of the classified label (for vector reference datasets only)",
"class");
117 Optionpk<short> boundary_opt(
"bnd",
"boundary",
"Boundary for selecting the sample (for vector reference datasets only)", 1,1);
118 Optionpk<bool> homogeneous_opt(
"hom",
"homogeneous",
"Only take regions with homogeneous boundary into account (for reference datasets only)",
false,1);
119 Optionpk<bool> disc_opt(
"circ",
"circular",
"Use circular boundary (for vector reference datasets only)",
false,1);
120 Optionpk<string> colorTable_opt(
"ct",
"ct",
"Color table in ASCII format having 5 columns: id R G B ALFA (0: transparent, 255: solid).");
121 Optionpk<string> option_opt(
"co",
"co",
"Creation option for output file. Multiple options can be specified.");
122 Optionpk<short> valueE_opt(
"\0",
"correct",
"Value for correct pixels", 0,2);
123 Optionpk<short> valueO_opt(
"\0",
"omission",
"Value for omission errors: input label > reference label", 1,2);
124 Optionpk<short> valueC_opt(
"\0",
"commission",
"Value for commission errors: input label < reference label", 2,1);
127 output_opt.setHide(1);
128 ogrformat_opt.setHide(1);
129 oformat_opt.setHide(1);
130 labelclass_opt.setHide(1);
131 boundary_opt.setHide(1);
132 homogeneous_opt.setHide(1);
134 colorTable_opt.setHide(1);
135 option_opt.setHide(1);
139 doProcess=input_opt.retrieveOption(argc,argv);
140 reference_opt.retrieveOption(argc,argv);
141 layer_opt.retrieveOption(argc,argv);
142 band_opt.retrieveOption(argc,argv);
143 rmse_opt.retrieveOption(argc,argv);
144 regression_opt.retrieveOption(argc,argv);
145 confusion_opt.retrieveOption(argc,argv);
146 labelref_opt.retrieveOption(argc,argv);
147 classname_opt.retrieveOption(argc,argv);
148 classvalue_opt.retrieveOption(argc,argv);
149 nodata_opt.retrieveOption(argc,argv);
150 mask_opt.retrieveOption(argc,argv);
151 msknodata_opt.retrieveOption(argc,argv);
152 output_opt.retrieveOption(argc,argv);
153 ogrformat_opt.retrieveOption(argc,argv);
154 labelclass_opt.retrieveOption(argc,argv);
155 cmformat_opt.retrieveOption(argc,argv);
156 cmoutput_opt.retrieveOption(argc,argv);
157 se95_opt.retrieveOption(argc,argv);
158 boundary_opt.retrieveOption(argc,argv);
159 homogeneous_opt.retrieveOption(argc,argv);
160 disc_opt.retrieveOption(argc,argv);
161 colorTable_opt.retrieveOption(argc,argv);
162 option_opt.retrieveOption(argc,argv);
164 valueE_opt.retrieveOption(argc,argv);
165 valueO_opt.retrieveOption(argc,argv);
166 valueC_opt.retrieveOption(argc,argv);
167 verbose_opt.retrieveOption(argc,argv);
169 catch(
string predefinedString){
170 std::cout << predefinedString << std::endl;
175 cout <<
"Usage: pkdiff -i input -ref reference" << endl;
177 std::cout <<
"short option -h shows basic options only, use long option --help to show all options" << std::endl;
185 cout <<
"flag(s) set to";
186 for(
int iflag=0;iflag<nodata_opt.size();++iflag)
187 cout <<
" " << nodata_opt[iflag];
191 if(input_opt.empty()){
192 std::cerr <<
"No input file provided (use option -i). Use --help for help information" << std::endl;
195 if(reference_opt.empty()){
196 std::cerr <<
"No reference file provided (use option -ref). Use --help for help information" << std::endl;
202 if(band_opt.size()<2)
203 band_opt.push_back(band_opt[0]);
206 while(mask_opt.size()<input_opt.size())
207 mask_opt.push_back(mask_opt[0]);
208 vector<short> inputRange;
209 vector<short> referenceRange;
212 map<string,short> classValueMap;
213 vector<std::string> nameVector(255);
214 vector<string> classNames;
216 unsigned int ntotalValidation=0;
217 unsigned int nflagged=0;
220 vector<float> producer;
221 vector<unsigned int> nvalidation;
223 if(confusion_opt[0]){
231 cout <<
"opening input image file " << input_opt[0] << endl;
232 inputReader.open(input_opt[0]);
235 cerr << error << endl;
238 inputReader.getRange(inputRange,band_opt[0]);
242 for(
int iflag=0;iflag<nodata_opt.size();++iflag){
243 vector<short>::iterator fit;
244 fit=find(inputRange.begin(),inputRange.end(),
static_cast<short>(nodata_opt[iflag]));
245 if(fit!=inputRange.end())
246 inputRange.erase(fit);
248 nclass=inputRange.size();
250 cout <<
"nclass (inputRange.size()): " << nclass << endl;
251 cout <<
"input range: " << endl;
253 if(classname_opt.size()){
254 assert(classname_opt.size()==classvalue_opt.size());
255 for(
int iclass=0;iclass<classname_opt.size();++iclass){
256 classValueMap[classname_opt[iclass]]=classvalue_opt[iclass];
257 assert(classvalue_opt[iclass]<nameVector.size());
258 nameVector[classvalue_opt[iclass]]=classname_opt[iclass];
262 for(
int rc=0;rc<inputRange.size();++rc){
263 classNames.push_back(type2string(inputRange[rc]));
265 cout << inputRange[rc] << endl;
267 cm.setClassNames(classNames);
269 cout <<
"class names: " << endl;
270 for(
int iclass=0;iclass<cm.nClasses();++iclass)
271 cout << iclass <<
" " << cm.getClass(iclass) << endl;
273 resultClass.resize(nclass,nclass);
275 producer.resize(nclass);
276 nvalidation.resize(nclass);
278 for(
int rc=0;rc<nclass;++rc){
279 for(
int ic=0;ic<nclass;++ic)
280 resultClass[rc][ic]=0;
285 bool isDifferent=
false;
286 bool refIsRaster=
false;
290 referenceReaderOgr.open(reference_opt[0]);
291 referenceReaderOgr.close();
293 catch(
string errorString){
296 const char* pszMessage;
297 void* pProgressArg=NULL;
298 GDALProgressFunc pfnProgress=GDALTermProgress;
302 for(
int iinput=0;iinput<input_opt.size();++iinput){
304 cout <<
"Processing input " << input_opt[iinput] << endl;
305 if(output_opt.size())
306 assert(reference_opt.size()==output_opt.size());
307 for(
int iref=0;iref<reference_opt.size();++iref){
308 cout <<
"reference " << reference_opt[iref] << endl;
311 inputReader.open(input_opt[iinput]);
313 maskReader.open(mask_opt[iinput]);
314 assert(inputReader.nrOfCol()==maskReader.nrOfCol());
315 assert(inputReader.nrOfRow()==maskReader.nrOfRow());
317 referenceReaderOgr.open(reference_opt[iref]);
320 cerr << error << endl;
324 referenceRange=inputRange;
327 if(output_opt.size()){
329 ogrWriter.open(output_opt[iref],ogrformat_opt[0]);
332 cerr << error << endl;
336 int nlayer=referenceReaderOgr.getDataSource()->GetLayerCount();
337 for(
int ilayer=0;ilayer<nlayer;++ilayer){
339 OGRLayer *readLayer=referenceReaderOgr.getLayer(ilayer);
341 string currentLayername=readLayer->GetName();
343 if(find(layer_opt.begin(),layer_opt.end(),currentLayername)==layer_opt.end())
346 pfnProgress(progress,pszMessage,pProgressArg);
348 cout <<
"processing layer " << readLayer->GetName() << endl;
350 readLayer->ResetReading();
351 OGRLayer *writeLayer;
352 if(output_opt.size()){
354 cout <<
"creating output vector file " << output_opt[0] << endl;
356 char **papszOptions=NULL;
358 cout <<
"creating layer: " << readLayer->GetName() << endl;
360 writeLayer=ogrWriter.createLayer(readLayer->GetName(), referenceReaderOgr.getProjection(ilayer), wkbPoint, papszOptions);
363 cout <<
"created layer" << endl;
364 cout <<
"copy fields from " << reference_opt[iref] << endl;
366 ogrWriter.copyFields(referenceReaderOgr,ilayer,ilayer);
368 short theDim=boundary_opt[0];
369 for(
int windowJ=-theDim/2;windowJ<(theDim+1)/2;++windowJ){
370 for(
int windowI=-theDim/2;windowI<(theDim+1)/2;++windowI){
371 if(disc_opt[0]&&(windowI*windowI+windowJ*windowJ>(theDim/2)*(theDim/2)))
375 fs << labelclass_opt[0] <<
"_" << windowJ <<
"_" << windowI;
377 fs << labelclass_opt[0];
379 cout <<
"creating field " << fs.str() << endl;
380 ogrWriter.createField(fs.str(),OFTInteger,ilayer);
384 OGRFeature *readFeature;
385 OGRFeature *writeFeature;
387 unsigned int nfeatureInLayer=readLayer->GetFeatureCount();
388 unsigned int ifeature=0;
389 while( (readFeature = readLayer->GetNextFeature()) != NULL ){
391 cout <<
"sample " << ++isample << endl;
394 OGRGeometry *poGeometry;
395 OGRPoint centroidPoint;
397 poGeometry = readFeature->GetGeometryRef();
401 else if(wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPolygon){
402 OGRMultiPolygon readPolygon = *((OGRMultiPolygon *) poGeometry);
403 readPolygon = *((OGRMultiPolygon *) poGeometry);
404 readPolygon.Centroid(¢roidPoint);
405 poPoint=¢roidPoint;
407 else if(wkbFlatten(poGeometry->getGeometryType()) == wkbPolygon){
408 OGRPolygon readPolygon=*((OGRPolygon *) poGeometry);
409 readPolygon.Centroid(¢roidPoint);
410 poPoint=¢roidPoint;
412 else if(wkbFlatten(poGeometry->getGeometryType()) == wkbPoint )
413 poPoint = (OGRPoint *) poGeometry;
415 std::cerr <<
"Warning: skipping feature (not of type point or polygon)" << std::endl;
421 vector<double> inputValues;
422 bool isHomogeneous=
true;
426 unsigned short referenceValue;
427 string referenceClassName;
428 if(classValueMap.size()){
429 referenceClassName=readFeature->GetFieldAsString(readFeature->GetFieldIndex(labelref_opt[0].c_str()));
430 referenceValue=classValueMap[referenceClassName];
433 referenceValue=readFeature->GetFieldAsInteger(readFeature->GetFieldIndex(labelref_opt[0].c_str()));
435 cout <<
"reference value: " << referenceValue << endl;
437 bool pixelFlagged=
false;
438 bool maskFlagged=
false;
439 for(
int iflag=0;iflag<nodata_opt.size();++iflag){
440 if(referenceValue==nodata_opt[iflag])
445 double i_centre,j_centre;
447 inputReader.geo2image(x,y,i_centre,j_centre);
453 j_centre=
static_cast<int>(j_centre);
454 i_centre=
static_cast<int>(i_centre);
456 if(static_cast<int>(j_centre)<0||
static_cast<int>(j_centre)>=inputReader.nrOfRow())
459 if(static_cast<int>(i_centre)<0||
static_cast<int>(i_centre)>=inputReader.nrOfCol())
462 if(output_opt.size()){
463 writeFeature = OGRFeature::CreateFeature(writeLayer->GetLayerDefn());
465 int nfield=readFeature->GetFieldCount();
466 writeFeature->SetGeometry(poPoint);
468 cout <<
"copying fields from " << reference_opt[0] << endl;
470 assert(writeFeature);
471 vector<int> panMap(nfield);
472 vector<int>::iterator panit=panMap.begin();
473 for(
int ifield=0;ifield<nfield;++ifield)
474 panMap[ifield]=ifield;
475 writeFeature->SetFieldsFrom(readFeature,&(panMap[0]));
481 bool windowAllFlagged=
true;
482 bool windowHasFlag=
false;
483 short theDim=boundary_opt[0];
484 for(
int windowJ=-theDim/2;windowJ<(theDim+1)/2;++windowJ){
485 for(
int windowI=-theDim/2;windowI<(theDim+1)/2;++windowI){
486 if(disc_opt[0]&&(windowI*windowI+windowJ*windowJ>(theDim/2)*(theDim/2)))
488 int j=j_centre+windowJ;
490 if(static_cast<int>(j)<0||
static_cast<int>(j)>=inputReader.nrOfRow())
492 int i=i_centre+windowI;
494 if(static_cast<int>(i)<0||
static_cast<int>(i)>=inputReader.nrOfCol())
497 cout << setprecision(12) <<
"reading image value at x,y " << x <<
"," << y <<
" (" << i <<
"," << j <<
"), ";
498 inputReader.readData(inputValue,GDT_Float64,i,j,band_opt[0]);
499 inputValues.push_back(inputValue);
500 if(inputValues.back()!=*(inputValues.begin()))
503 cout <<
"input value: " << inputValue << endl;
505 for(
int iflag=0;iflag<nodata_opt.size();++iflag){
506 if(inputValue==nodata_opt[iflag]){
513 maskReader.readData(maskValue,GDT_Float64,i,j,0);
514 for(
int ivalue=0;ivalue<msknodata_opt.size();++ivalue){
515 if(msknodata_opt[ivalue]>=0){
516 if(maskValue==msknodata_opt[ivalue]){
522 if(maskValue!=-msknodata_opt[ivalue])
531 pixelFlagged=pixelFlagged||maskFlagged;
535 windowAllFlagged=
false;
540 if(homogeneous_opt[0]){
545 if(!windowHasFlag&&isHomogeneous){
546 if(output_opt.size())
547 writeFeature->SetField(labelclass_opt[0].c_str(),
static_cast<int>(inputValue));
548 if(confusion_opt[0]){
550 if(classValueMap.size()){
551 assert(inputValue<nameVector.size());
552 string className=nameVector[
static_cast<unsigned short>(inputValue)];
553 cm.incrementResult(type2string<short>(classValueMap[referenceClassName]),type2string<short>(classValueMap[className]),1);
556 int rc=distance(referenceRange.begin(),find(referenceRange.begin(),referenceRange.end(),
static_cast<unsigned short>(referenceValue)));
557 int ic=distance(inputRange.begin(),find(inputRange.begin(),inputRange.end(),
static_cast<unsigned short>(inputValue)));
561 ++resultClass[rc][ic];
563 cout <<
"increment: " << rc <<
" " << referenceRange[rc] <<
" " << ic <<
" " << inputRange[ic] << endl;
564 cm.incrementResult(cm.getClass(rc),cm.getClass(ic),1);
567 if(inputValue==referenceValue){
568 outputValue=valueE_opt[0];
569 if(nodata_opt.size()){
570 if(valueE_opt[0]==nodata_opt[0])
571 outputValue=inputValue;
574 else if(inputValue>referenceValue)
575 outputValue=valueO_opt[0];
577 outputValue=valueC_opt[0];
581 for(
int windowJ=-theDim/2;windowJ<(theDim+1)/2;++windowJ){
582 for(
int windowI=-theDim/2;windowI<(theDim+1)/2;++windowI){
583 if(disc_opt[0]&&(windowI*windowI+windowJ*windowJ>(theDim/2)*(theDim/2)))
585 int j=j_centre+windowJ;
587 if(static_cast<int>(j)<0||
static_cast<int>(j)>=inputReader.nrOfRow())
589 int i=i_centre+windowI;
591 if(static_cast<int>(i)<0||
static_cast<int>(i)>=inputReader.nrOfCol())
593 if(!windowAllFlagged){
596 fs << labelclass_opt[0] <<
"_" << windowJ <<
"_" << windowI;
598 fs << labelclass_opt[0];
599 if(output_opt.size())
600 writeFeature->SetField(fs.str().c_str(),inputValue);
601 if(!windowJ&&!windowI){
602 if(confusion_opt[0]){
604 if(classValueMap.size()){
605 assert(inputValue<nameVector.size());
606 string className=nameVector[
static_cast<unsigned short>(inputValue)];
607 cm.incrementResult(type2string<short>(classValueMap[referenceClassName]),type2string<short>(classValueMap[className]),1);
610 int rc=distance(referenceRange.begin(),find(referenceRange.begin(),referenceRange.end(),
static_cast<unsigned short>(referenceValue)));
611 int ic=distance(inputRange.begin(),find(inputRange.begin(),inputRange.end(),
static_cast<unsigned short>(inputValue)));
619 ++resultClass[rc][ic];
621 cout <<
"increment: " << rc <<
" " << referenceRange[rc] <<
" " << ic <<
" " << inputRange[ic] << endl;
622 cm.incrementResult(cm.getClass(rc),cm.getClass(ic),1);
625 if(inputValue==referenceValue){
626 outputValue=valueE_opt[0];
627 if(nodata_opt.size()){
628 if(valueE_opt[0]==nodata_opt[0])
629 outputValue=inputValue;
632 else if(inputValue>referenceValue)
633 outputValue=valueO_opt[0];
635 outputValue=valueC_opt[0];
641 if(output_opt.size()){
642 if(!windowAllFlagged){
644 cout <<
"creating feature" << endl;
645 if(writeLayer->CreateFeature( writeFeature ) != OGRERR_NONE ){
646 string errorString=
"Failed to create feature in OGR vector file";
650 OGRFeature::DestroyFeature( writeFeature );
653 progress=
static_cast<float>(ifeature+1)/nfeatureInLayer;
654 pfnProgress(progress,pszMessage,pProgressArg);
657 if(output_opt.size())
659 referenceReaderOgr.close();
665 pfnProgress(1.0,pszMessage,pProgressArg);
670 inputReader.open(input_opt[0]);
672 maskReader.open(mask_opt[0]);
673 if(output_opt.size()){
675 cout <<
"opening output image " << output_opt[0] << endl;
676 if(option_opt.findSubstring(
"INTERLEAVE=")==option_opt.end()){
677 string theInterleave=
"INTERLEAVE=";
678 theInterleave+=inputReader.getInterleave();
679 option_opt.push_back(theInterleave);
681 gdalWriter.open(output_opt[0],inputReader.nrOfCol(),inputReader.nrOfRow(),1,inputReader.getDataType(),oformat_opt[0],option_opt);
682 if(nodata_opt.size())
683 gdalWriter.GDALSetNoDataValue(nodata_opt[0]);
684 gdalWriter.copyGeoTransform(inputReader);
685 if(colorTable_opt.size())
686 gdalWriter.setColorTable(colorTable_opt[0]);
687 else if(inputReader.getColorTable()!=NULL){
689 cout <<
"set colortable from input image" << endl;
690 gdalWriter.setColorTable(inputReader.getColorTable());
693 else if(verbose_opt[0])
694 cout <<
"no output image defined" << endl;
698 cout << error << endl;
702 vector<double> lineInput(inputReader.nrOfCol());
703 vector<double> lineMask(maskReader.nrOfCol());
704 vector<double> lineOutput;
705 vector<double> bufferInput;
706 vector<double> bufferReference;
707 if(output_opt.size())
708 lineOutput.resize(inputReader.nrOfCol());
712 double oldreferencerow=-1;
713 double oldmaskrow=-1;
716 referenceReaderGdal.open(reference_opt[0]);
719 cerr << error << endl;
722 if(inputReader.isGeoRef()){
723 assert(referenceReaderGdal.isGeoRef());
724 if(inputReader.getProjection()!=referenceReaderGdal.getProjection())
725 cerr <<
"Warning: projection of input image and reference image are different" << endl;
727 vector<double> lineReference(referenceReaderGdal.nrOfCol());
728 if(confusion_opt[0]){
729 referenceReaderGdal.getRange(referenceRange,band_opt[1]);
730 for(
int iflag=0;iflag<nodata_opt.size();++iflag){
731 vector<short>::iterator fit;
732 fit=find(referenceRange.begin(),referenceRange.end(),
static_cast<unsigned short>(nodata_opt[iflag]));
733 if(fit!=referenceRange.end())
734 referenceRange.erase(fit);
737 cout <<
"reference range: " << endl;
738 for(
int rc=0;rc<referenceRange.size();++rc)
739 cout << referenceRange[rc] << endl;
741 if(referenceRange.size()!=inputRange.size()){
742 if(confusion_opt[0]||output_opt.size()){
743 cout <<
"reference range is not equal to input range!" << endl;
744 cout <<
"Kappa: " << 0 << endl;
745 cout <<
"total weighted: " << 0 << endl;
748 cout <<
"reference range is not equal to input range!" << endl;
749 cout << input_opt[0] <<
" and " << reference_opt[0] <<
" are different" << endl;
755 for(irow=0;irow<inputReader.nrOfRow();++irow){
757 inputReader.readData(lineInput,GDT_Float64,irow,band_opt[0]);
759 double ireference,jreference;
761 for(icol=0;icol<inputReader.nrOfCol();++icol){
763 inputReader.image2geo(icol,irow,x,y);
764 referenceReaderGdal.geo2image(x,y,ireference,jreference);
765 if(ireference<0||ireference>=referenceReaderGdal.nrOfCol()){
766 if(rmse_opt[0]||regression_opt[0])
769 cerr << ireference <<
" out of reference range!" << endl;
770 cerr << x <<
" " << y <<
" " << icol <<
" " << irow << endl;
771 cerr << x <<
" " << y <<
" " << ireference <<
" " << jreference << endl;
775 if(jreference!=oldreferencerow){
776 if(jreference<0||jreference>=referenceReaderGdal.nrOfRow()){
777 if(rmse_opt[0]||regression_opt[0])
780 cerr << jreference <<
" out of reference range!" << endl;
781 cerr << x <<
" " << y <<
" " << icol <<
" " << irow << endl;
782 cerr << x <<
" " << y <<
" " << ireference <<
" " << jreference << endl;
787 referenceReaderGdal.readData(lineReference,GDT_Float64,static_cast<int>(jreference),band_opt[1]);
788 oldreferencerow=jreference;
792 for(
int iflag=0;iflag<nodata_opt.size();++iflag){
793 if((lineInput[icol]==nodata_opt[iflag])||(lineReference[ireference]==nodata_opt[iflag])){
794 if(output_opt.size())
795 lineOutput[icol]=nodata_opt[iflag];
801 maskReader.geo2image(x,y,imask,jmask);
802 if(jmask>=0&&jmask<maskReader.nrOfRow()){
803 if(jmask!=oldmaskrow)
804 maskReader.readData(lineMask,GDT_Float64,jmask);
805 for(
int ivalue=0;ivalue<msknodata_opt.size();++ivalue){
806 if(lineMask[icol]==msknodata_opt[ivalue]){
815 rmse+=
static_cast<double>(lineInput[icol]-lineReference[ireference])*(lineInput[icol]-lineReference[ireference])/inputReader.nrOfCol()/inputReader.nrOfRow();
817 else if(regression_opt[0]){
818 bufferInput.push_back(lineInput[icol]);
819 bufferReference.push_back(lineReference[ireference]);
822 if(confusion_opt[0]){
824 int rc=distance(referenceRange.begin(),find(referenceRange.begin(),referenceRange.end(),lineReference[ireference]));
825 int ic=distance(inputRange.begin(),find(inputRange.begin(),inputRange.end(),lineInput[icol]));
829 ++resultClass[rc][ic];
831 cout <<
"increment: " << rc <<
" " << referenceRange[rc] <<
" " << ic <<
" " << inputRange[ic] << endl;
832 cm.incrementResult(cm.getClass(rc),cm.getClass(ic),1);
834 if(lineInput[icol]==lineReference[ireference]){
835 if(output_opt.size()){
836 lineOutput[icol]=valueE_opt[0];
837 if(nodata_opt.size()){
838 if(valueE_opt[0]==nodata_opt[0])
839 lineOutput[icol]=lineInput[icol];
844 if(output_opt.empty()&&!confusion_opt[0]&&!rmse_opt[0]&&!regression_opt[0]){
848 if(output_opt.size()){
849 if(lineInput[icol]>lineReference[ireference])
850 lineOutput[icol]=valueO_opt[0];
852 lineOutput[icol]=valueC_opt[0];
858 if(output_opt.size()){
859 if(nodata_opt.size())
860 lineOutput[icol]=nodata_opt[0];
866 if(output_opt.size()){
868 gdalWriter.writeData(lineOutput,GDT_Float64,irow);
870 catch(
string errorstring){
871 cerr <<
"lineOutput.size(): " << lineOutput.size() << endl;
872 cerr <<
"gdalWriter.nrOfCol(): " << gdalWriter.nrOfCol() << endl;
873 cerr << errorstring << endl;
877 else if(isDifferent&&!confusion_opt[0]&&!rmse_opt[0]&&!regression_opt[0]){
879 pfnProgress(1.0,pszMessage,pProgressArg);
882 progress=
static_cast<float>(irow+1.0)/inputReader.nrOfRow();
884 pfnProgress(progress,pszMessage,pProgressArg);
886 if(output_opt.size())
888 else if(!confusion_opt[0]){
890 double normalization=1.0*inputReader.nrOfCol()*inputReader.nrOfRow()/(inputReader.nrOfCol()*inputReader.nrOfRow()-nflagged);
892 cout <<
"normalization: " << normalization << endl;
893 cout <<
"rmse before sqrt and normalization: " << rmse << endl;
895 cout <<
"--rmse " << sqrt(rmse/normalization) << endl;
897 else if(regression_opt[0]){
902 if(bufferInput.size()&&bufferReference.size()){
903 err=stat.linear_regression_err(bufferInput,bufferReference,c0,c1);
906 cout <<
"bufferInput.size(): " << bufferInput.size() << endl;
907 cout <<
"bufferReference.size(): " << bufferReference.size() << endl;
910 stat.minmax(bufferInput,bufferInput.begin(),bufferInput.end(),theMin,theMax);
911 cout <<
"min, max input: " << theMin <<
", " << theMax << endl;
914 stat.minmax(bufferReference,bufferReference.begin(),bufferReference.end(),theMin,theMax);
915 cout <<
"min, max reference: " << theMin <<
", " << theMax << endl;
917 cout <<
"--c0 " << c0 <<
"--c1 " << c1 <<
" --rmse: " << err << endl;
921 cout << input_opt[0] <<
" and " << reference_opt[0] <<
" are different" << endl;
923 cout << input_opt[0] <<
" and " << reference_opt[0] <<
" are identical" << endl;
925 referenceReaderGdal.close();
931 if(confusion_opt[0]){
932 cm.setFormat(cmformat_opt[0]);
933 cm.reportSE95(se95_opt[0]);
935 if(cmoutput_opt.size()){
936 outputFile.open(cmoutput_opt[0].c_str(),ios::out);
937 outputFile << cm << endl;