Compare View

switch
from
...
to
 
Commits (267)
Showing 93 changed files   Show diff stats
app/CMakeLists.txt
... ... @@ -18,6 +18,12 @@ OTB_CREATE_APPLICATION(
18 18 LINK_LIBRARIES ${OTBCommon_LIBRARIES} ${OTBITK_LIBRARIES} ${OTBApplicationEngine_LIBRARIES} )
19 19  
20 20 OTB_CREATE_APPLICATION(
  21 + NAME iota2MasksIntersection
  22 + SOURCES iota2MasksIntersection.cxx
  23 + LINK_LIBRARIES ${OTBCommon_LIBRARIES} ${OTBITK_LIBRARIES} ${OTBApplicationEngine_LIBRARIES} )
  24 +
  25 +
  26 +OTB_CREATE_APPLICATION(
21 27 NAME extractSortedIndices
22 28 SOURCES extractSortedIndices.cxx
23 29 LINK_LIBRARIES ${OTBCommon_LIBRARIES} ${OTBITK_LIBRARIES} ${OTBApplicationEngine_LIBRARIES} ${OTBTemporalGapFilling_LIBRARIES} ${OTBBoost_LIBRARIES} ${GSL_LIBRARIES} )
... ...
app/iota2MasksIntersection.cxx 0 → 100644
... ... @@ -0,0 +1,214 @@
  1 +/*=========================================================================
  2 +
  3 + Program: iota2
  4 + Language: C++
  5 +
  6 + Copyright (c) CESBIO. All rights reserved.
  7 +
  8 + See LICENSE for details.
  9 +
  10 + This software is distributed WITHOUT ANY WARRANTY; without even
  11 + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  12 + PURPOSE. See the above copyright notices for more information.
  13 +
  14 +=========================================================================*/
  15 +
  16 +#include "otbWrapperApplication.h"
  17 +#include "otbWrapperApplicationFactory.h"
  18 +#include "itkNaryFunctorImageFilter.h"
  19 +#include "otbLabelImageToVectorDataFilter.h"
  20 +
  21 +namespace otb
  22 +{
  23 +namespace Wrapper
  24 +{
  25 +
  26 +template <typename TIn, typename TOut>
  27 +class MasksIntersectionFunctor{
  28 +
  29 +public:
  30 + enum Convention{edg, div, nodata};
  31 +
  32 + MasksIntersectionFunctor()
  33 + : m_InValue(0), m_OutValue(255), m_Conventions()
  34 + {}
  35 +
  36 + ~MasksIntersectionFunctor(){}
  37 +
  38 + inline TOut operator()(const std::vector<TIn> & in) const
  39 + {
  40 + assert(in.size() == m_Conventions.size());
  41 +
  42 + for(unsigned int i = 0; i<in.size(); ++i)
  43 + {
  44 + // This is only because applications do not handle List of UInt images
  45 + unsigned int inValue = static_cast<TOut>(in[i][0]);
  46 +
  47 + switch(m_Conventions[i])
  48 + {
  49 + case edg:
  50 + // [0] because TIn is supposed to be vector
  51 + // In S2 mask, 1 means no data
  52 + if(inValue == 1)
  53 + {
  54 + return m_OutValue;
  55 + }
  56 + break;
  57 + case div:
  58 + // In landsat X div files, odd value means no data
  59 + if(inValue%2 == 1)
  60 + {
  61 + return m_OutValue;
  62 + }
  63 + break;
  64 + case nodata:
  65 + // In landsat X nodata files, even value means no data
  66 + if(inValue%2 == 0)
  67 + {
  68 + return m_OutValue;
  69 + }
  70 + break;
  71 + }
  72 + }
  73 + return m_InValue;
  74 + }
  75 +
  76 + TOut m_InValue;
  77 + TOut m_OutValue;
  78 + std::vector<Convention> m_Conventions;
  79 +};
  80 +
  81 +class iota2MasksIntersection: public Application
  82 +{
  83 +public:
  84 + using Self = iota2MasksIntersection;
  85 + using Superclass = Application;
  86 + using Pointer = itk::SmartPointer<Self>;
  87 + using ConstPointer = itk::SmartPointer<const Self>;
  88 +
  89 + itkNewMacro(Self);
  90 + itkTypeMacro(iota2MasksIntersection, otb::Application);
  91 +
  92 + using IntersectionFunctorType = MasksIntersectionFunctor<FloatVectorImageType::PixelType,UInt8ImageType::PixelType>;
  93 + using IntersectionFilterType = itk::NaryFunctorImageFilter<FloatVectorImageType,UInt8ImageType,IntersectionFunctorType>;
  94 + using PolygonizeFilterType = otb::LabelImageToVectorDataFilter<UInt8ImageType>;
  95 +
  96 +private:
  97 + void DoInit() override
  98 + {
  99 + SetName("iota2MasksIntersection");
  100 + SetDescription("Performs intersection of several input masks");
  101 +
  102 + // Documentation
  103 + SetDocName("Masks intersection");
  104 + SetDocLongDescription("This application performs intersection of several input masks from Landsat or Sentinel2 products. Output can be retrieved as a raster or vector file.");
  105 + SetDocLimitations("None");
  106 + SetDocAuthors("Julien Michel");
  107 +
  108 + AddDocTag(Tags::Filter);
  109 + AddDocTag("MultiTemporal");
  110 +
  111 + AddParameter(ParameterType_InputImageList, "edg", "Sentinel2 edge masks (EDG files)");
  112 + SetParameterDescription("edg","List of Sentinel2 EDG files (1 means no data)");
  113 + MandatoryOff("edg");
  114 +
  115 + AddParameter(ParameterType_InputImageList, "div", "Landsat div masks (DIV files)");
  116 + SetParameterDescription("div","List of Landsat DIV files (odd value means no data)");
  117 + MandatoryOff("div");
  118 + AddParameter(ParameterType_InputImageList, "nodata", "Landsat no data masks (NODATA files)");
  119 + SetParameterDescription("nodata","List of Landsat NODATA files (even value means no data)");
  120 + MandatoryOff("nodata");
  121 +
  122 +
  123 + AddParameter(ParameterType_Choice,"mode","Output mode (vector or raster)");
  124 + AddChoice("mode.raster", "Output a raster mask");
  125 + SetParameterDescription("mode.raster","Raster output mode");
  126 + AddChoice("mode.vector", "Output a vector mask");
  127 + SetParameterDescription("mode.vector","Vector output mode. Note that this mode does not perform streaming: all input masks will be loaded into memory.");
  128 +
  129 +
  130 + AddParameter(ParameterType_OutputImage,"mode.raster.out","Output mask as a raster");
  131 + SetParameterDescription("mode.raster.out","Output raster file. Encoding should be integer.");
  132 + SetDefaultOutputPixelType("mode.raster.out",ImagePixelType_uint8);
  133 + AddParameter(ParameterType_Int,"mode.raster.inv","Value for pixel inside mask");
  134 + SetDefaultParameterInt("mode.raster.inv",255);
  135 + AddParameter(ParameterType_Int,"mode.raster.outv","Value for pixel outside mask");
  136 + SetDefaultParameterInt("mode.raster.outv",0);
  137 +
  138 + AddParameter(ParameterType_OutputVectorData,"mode.vector.out","Output mask as a vector");
  139 + SetParameterDescription("mode.vector.out","Output vector file.");
  140 +
  141 + AddParameter(ParameterType_Empty,"mode.vector.8conn","Use 8 connexity for vectorisation");
  142 + SetParameterDescription("mode.vector.8conn","If enabled, 8 connexity will be used during vectorization.");
  143 +
  144 + AddParameter(ParameterType_String,"mode.vector.field","Name of the field associated with polygons");
  145 + SetParameterDescription("mode.vector.field","The vectorization operation will create a field with an associated label (which is expected to be constant and equal to mode.raster.outv)");
  146 + SetParameterString("mode.vector.field","DN");
  147 +
  148 + AddRAMParameter();
  149 + }
  150 +
  151 + void DoUpdateParameters() override
  152 + {
  153 +
  154 +
  155 + }
  156 +
  157 + void DoExecute() override
  158 + {
  159 + m_IntersectionFilter = IntersectionFilterType::New();
  160 +
  161 + FloatVectorImageListType::Pointer edgList = this->GetParameterImageList("edg");
  162 +
  163 + for(auto it = edgList->Begin(); it!= edgList->End();++it)
  164 + {
  165 + m_IntersectionFilter->PushBackInput(it.Get());
  166 + m_IntersectionFilter->GetFunctor().m_Conventions.push_back(IntersectionFunctorType::Convention::edg);
  167 + }
  168 +
  169 + FloatVectorImageListType::Pointer divList = this->GetParameterImageList("div");
  170 +
  171 + for(auto it = divList->Begin(); it!= divList->End();++it)
  172 + {
  173 + m_IntersectionFilter->PushBackInput(it.Get());
  174 + m_IntersectionFilter->GetFunctor().m_Conventions.push_back(IntersectionFunctorType::Convention::div);
  175 + }
  176 +
  177 + FloatVectorImageListType::Pointer nodataList = this->GetParameterImageList("nodata");
  178 +
  179 + for(auto it = nodataList->Begin(); it!= nodataList->End();++it)
  180 + {
  181 + m_IntersectionFilter->PushBackInput(it.Get());
  182 + m_IntersectionFilter->GetFunctor().m_Conventions.push_back(IntersectionFunctorType::Convention::nodata);
  183 + }
  184 +
  185 +
  186 +
  187 + m_IntersectionFilter->GetFunctor().m_InValue = GetParameterInt("mode.raster.inv");
  188 + m_IntersectionFilter->GetFunctor().m_OutValue = GetParameterInt("mode.raster.outv");
  189 +
  190 +
  191 + if(GetParameterString("mode") == "raster")
  192 + {
  193 + SetParameterOutputImage("mode.raster.out",m_IntersectionFilter->GetOutput());
  194 + }
  195 + else
  196 + {
  197 + m_PolygonizeFilter = PolygonizeFilterType::New();
  198 + m_PolygonizeFilter->SetInput(m_IntersectionFilter->GetOutput());
  199 + m_PolygonizeFilter->SetInputMask(m_IntersectionFilter->GetOutput());
  200 + m_PolygonizeFilter->SetUse8Connected(IsParameterEnabled("mode.vector.8conn"));
  201 + m_PolygonizeFilter->SetFieldName(GetParameterString("mode.vector.field"));
  202 + SetParameterOutputVectorData("mode.vector.out",m_PolygonizeFilter->GetOutput());
  203 + }
  204 +
  205 + }
  206 +
  207 + IntersectionFilterType::Pointer m_IntersectionFilter;
  208 + PolygonizeFilterType::Pointer m_PolygonizeFilter;
  209 +
  210 +};
  211 +} // end namespace Wrapper
  212 +} // end namespace otb
  213 +
  214 + OTB_APPLICATION_EXPORT(otb::Wrapper::iota2MasksIntersection)
... ...
config/Config_4Tuiles_Multi_FUS_Confidence.cfg
... ... @@ -4,13 +4,15 @@
4 4  
5 5 chain:
6 6 {
7   - executionMode: 'parallel'
  7 + executionMode: 'sequential'
8 8 outputPath:'/ptmp/vincenta/tmp/4Tuiles_Multi_FUS_CONFID'
  9 + remove_outputPath:True
  10 +
9 11 jobsPath:'/home/user13/theia_oso/vincenta/codeTest/4Tuiles_Multi_FUS_CONFID'
10 12 pyAppPath:'/home/user13/theia_oso/vincenta/THEIA_OSO/oso/theia_oso/scripts/common'
11 13 chainName:'OSO_chain_CONFID'
12 14 nomenclaturePath:'/home/user13/theia_oso/vincenta/Nomenclature_SudFrance.csv'
13   - outputStatistics:'True'
  15 + outputStatistics:True
14 16  
15 17 listTile:'D0004H0004 D0005H0004 D0004H0003 D0005H0003'
16 18 featuresPath:'/ptmp/vincenta/TILES_2014_v4/'
... ... @@ -24,17 +26,22 @@ chain:
24 26 regionPath:'/ptmp/vincenta/regionShape/4Tiles.shp'
25 27 regionField:'region'
26 28 model:'/home/user13/theia_oso/vincenta/THEIA_OSO/oso/4Tiles.txt'
27   -
  29 +
28 30 groundTruth:'/ptmp/vincenta/groundTruth/FR_ALL_2014_V1_ero1cm.shp'
29 31 dataField:'CODE'
30   - runs:'1'
31   - ratio:'0.7'
32   - cloud_threshold:'1'
33   - spatialResolution:'30'
  32 + runs:1
  33 + ratio:0.7
  34 + cloud_threshold:1
  35 + spatialResolution:30
34 36  
  37 + firstStep:init
  38 + lastStep:validation#init,sampling,learning,classification,mosaic,validation
  39 +
35 40 logPath:'/home/user13/theia_oso/vincenta/codeTest/4Tuiles_Multi_FUS_CONFID/log'
  41 + logFileLevel:"INFO"
  42 +
36 43 colorTable:'/home/user13/theia_oso/vincenta/THEIA_OSO/oso/theia_oso/doc/colorFile.txt'
37   - mode_outside_RegionSplit:''#square km
  44 + mode_outside_RegionSplit:0.1#square km
38 45  
39 46 OTB_HOME:'/data/qtis/inglada/modules/repository/otb_superbuild/otb_superbuild-5.2.1-Release-install/'
40 47 }
... ... @@ -45,23 +52,25 @@ chain:
45 52  
46 53 argTrain:
47 54 {
48   - shapeMode : 'points'#polygons or points
49   - samplesOptions:'-sampler random -strategy constant -strategy.constant.nb 2 '
  55 + sampleSelection : {"sampler":random,
  56 + "strategy":percent,
  57 + "strategy.percent.p":0.2,
  58 + "ram":4000,
  59 + "per_models":[{"target_model":4,
  60 + "sampler":"periodic"}]
  61 + }
50 62  
51 63 classifier :'rf'
52   - options :' -classifier.rf.min 5 -classifier.rf.max 25 -sample.mt -1 -sample.mv 0 -sample.bm 0 -sample.vtr 0'
53   - rearrangeModelTile:False#True or False
54   - rearrangeModelTile_out:''
  64 + options :' -classifier.rf.min 5 -classifier.rf.max 25 '
55 65  
56   - cropMix:'True'
  66 + cropMix:False
57 67 prevFeatures:'/ptmp/vincenta/TestCropMix/2013/config_2013.cfg'
58 68 outputPrevFeatures:'/work/OT/theia/oso/features/L8_2014_features/'
59 69 annualCrop:['11','12']
60 70 ACropLabelReplacement:['10','annualCrop']
61   - samplesClassifMix:'True'
  71 + samplesClassifMix:False
62 72 annualClassesExtractionSource:'/path/to/theConfigurationFileWhichRuleAPreviousClassification'
63   - validityThreshold : '5'
64   - coeffSampleSelection : '1'
  73 + validityThreshold : 5
65 74 }
66 75  
67 76 ################################################################################################
... ... @@ -70,10 +79,9 @@ argTrain:
70 79  
71 80 argClassification:
72 81 {
73   - classifMode :'fusion'#fusion or seperate
  82 + classifMode :'fusion'#fusion or separate
74 83 fusionOptions :'-nodatalabel 0 -method majorityvoting'
75 84 pixType : 'uint8'
76   - confusionModel : False #True or False
77 85 noLabelManagement : 'maxConfidence'#maxConfidence or learningPriority
78 86 }
79 87  
... ... @@ -82,7 +90,7 @@ argClassification:
82 90 ################################################################################################
83 91 Landsat8:
84 92 {
85   - nodata_Mask : "False"
  93 + nodata_Mask : False
86 94 nativeRes : 30
87 95 arbo : "/*/*"
88 96 imtype : "ORTHO_SURF_CORR_PENTE*.TIF"
... ... @@ -93,13 +101,13 @@ Landsat8:
93 101 arbomask : "*/*/MASK/"
94 102 startDate:''
95 103 endDate:''
96   - temporalResolution:'16'
  104 + temporalResolution:16
97 105 additionalFeatures:"b1+b2,(b1-b2)/(b1+b2)"#comma splited
98 106 keepBands:[[1,"blue"],[2,"green"],[3,"red"],[7,"NIR"],[9,"SWIR"]]
99 107 }
100 108 Landsat5:
101 109 {
102   - nodata_Mask : "False"
  110 + nodata_Mask : False
103 111 nativeRes : 30
104 112 arbo : "/*/*"
105 113 imtype : "ORTHO_SURF_CORR_PENTE*.TIF"
... ... @@ -110,13 +118,13 @@ Landsat5:
110 118 arbomask : "*/*/MASK/"
111 119 startDate:''
112 120 endDate:''
113   - temporalResolution:'16'
  121 + temporalResolution:16
114 122 additionalFeatures:"b1+b2,(b1-b2)/(b1+b2)"#comma splited
115 123 keepBands:[[1,"blue"],[2,"green"],[3,"red"],[7,"NIR"],[9,"SWIR"]]
116 124 }
117 125 Sentinel_2:
118 126 {
119   - nodata_Mask : ""
  127 + nodata_Mask : False
120 128 nativeRes : 10
121 129 arbo : "/*/"
122 130 imtype : "*STACK.tif"
... ... @@ -130,7 +138,7 @@ Sentinel_2:
130 138 arbomask : "/*/MASKS/"
131 139 startDate:''
132 140 endDate:''
133   - temporalResolution:'10'
  141 + temporalResolution:10
134 142 additionalFeatures:"b1+b2,(b1-b2)/(b1+b2)"#comma splited
135 143 keepBands:[[1,"blue"],[2,"green"],[3,"red"],[7,"NIR"],[9,"SWIR"]]
136 144 }
... ... @@ -143,20 +151,18 @@ GlobChain:
143 151 {
144 152 proj : "EPSG:2154"
145 153 features: ["NDVI","NDWI","Brightness"]
146   - nbLook:1
147   - batchProcessing : 'False'
148   - autoDate:'True'
149   - bindingPython:'False'
150   - writeOutputs:'False'
151   - useAdditionalFeatures:'True'
152   - useGapFilling:'True'
  154 + autoDate:True
  155 + writeOutputs:False
  156 + useAdditionalFeatures:True
  157 + useGapFilling:True
153 158 }
154 159  
155 160 iota2FeatureExtraction:
156 161 {
157   - copyinput:'True'
158   - relrefl:'False'
159   - keepduplicates:'False'
160   - extractBands:'False'
  162 + copyinput:True
  163 + relrefl:False
  164 + keepduplicates:False
  165 + extractBands:False
  166 + acorfeat:False
161 167 }
162 168 ################################################################################################
... ...
data/L8_50x50/Landsat8_D0005H0002/LANDSAT8_OLITIRS_XS_20160415_N2A_France-MetropoleD0005H0002/LANDSAT8_OLITIRS_XS_20160415_N2A_ORTHO_SURF_CORR_PENTE_France-MetropoleD0005H0002.TIF.aux.xml
... ... @@ -9,12 +9,20 @@
9 9 <Approximate>0</Approximate>
10 10 <HistCounts>1|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|4|0|0|15|0|0|1|0|0|45|0|0|100|0|0|15|0|0|29|0|0|50|0|0|84|0|0|57|0|0|119|0|0|89|0|0|25|0|0|96|0|0|130|0|0|12|0|0|80|0|0|105|0|0|24|0|0|0|59|0|0|52|0|0|34|0|0|31|0|0|51|0|0|31|0|0|12|0|0|54|0|0|42|0|0|15|0|0|25|0|0|30|0|0|13|0|0|27|0|0|33|0|0|9|0|0|23|0|0|38|0|0|22|0|0|22|0|0|41|0|0|21|0|0|16|0|0|35|0|0|31|0|0|12|0|0|54|0|0|41|0|0|12|0|0|37|0|0|32|0|0|15|0|0|32|0|0|43|0|0|15|0|0|27|0|0|38|0|0|18|0|0|16|0|0|54|0|0|15|0|0|10|0|0|27|0|0|24|0|0|3|0|0|13|0|0|6|0|0|4|0|0|12|0|0|8|0|0|2|0|0|4|0|0|4|0|0|1|0|0|3|0|0|0|8|0|0|1|0|0|2|0|0|2|0|0|3|0|0|2|0|0|3|0|0|2|0|0|0|0|0|1|0|0|3|0|0|3|0|0|0|0|0|0|0|0|4|0|0|3|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|1|0|0|1|0|0|0|0|0|1|0|0|0|0|0|1|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|1|0|0|1|0|0|1|0|0|0|0|0|1|0|0|1|0|0|1|0|0|0|0|0|0|0|0|0|0|0|1|0|0|1|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1</HistCounts>
11 11 </HistItem>
  12 + <HistItem>
  13 + <HistMin>3.8345</HistMin>
  14 + <HistMax>335.1655</HistMax>
  15 + <BucketCount>1000</BucketCount>
  16 + <IncludeOutOfRange>0</IncludeOutOfRange>
  17 + <Approximate>0</Approximate>
  18 + <HistCounts>1|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|4|0|0|15|0|0|1|0|0|45|0|0|100|0|0|15|0|0|29|0|0|50|0|0|84|0|0|57|0|0|119|0|0|89|0|0|25|0|0|96|0|0|130|0|0|12|0|0|80|0|0|105|0|0|24|0|0|0|59|0|0|52|0|0|34|0|0|31|0|0|51|0|0|31|0|0|12|0|0|54|0|0|42|0|0|15|0|0|25|0|0|30|0|0|13|0|0|27|0|0|33|0|0|9|0|0|23|0|0|38|0|0|22|0|0|22|0|0|41|0|0|21|0|0|16|0|0|35|0|0|31|0|0|12|0|0|54|0|0|41|0|0|12|0|0|37|0|0|32|0|0|15|0|0|32|0|0|43|0|0|15|0|0|27|0|0|38|0|0|18|0|0|16|0|0|54|0|0|15|0|0|10|0|0|27|0|0|24|0|0|3|0|0|13|0|0|6|0|0|4|0|0|12|0|0|8|0|0|2|0|0|4|0|0|4|0|0|1|0|0|3|0|0|0|8|0|0|1|0|0|2|0|0|2|0|0|3|0|0|2|0|0|3|0|0|2|0|0|0|0|0|1|0|0|3|0|0|3|0|0|0|0|0|0|0|0|4|0|0|3|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|1|0|0|1|0|0|0|0|0|1|0|0|0|0|0|1|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|1|0|0|1|0|0|1|0|0|0|0|0|1|0|0|1|0|0|1|0|0|0|0|0|0|0|0|0|0|0|1|0|0|1|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1</HistCounts>
  19 + </HistItem>
12 20 </Histograms>
13 21 <Metadata>
14 22 <MDI key="STATISTICS_MAXIMUM">335</MDI>
15   - <MDI key="STATISTICS_MEAN">42,3852</MDI>
  23 + <MDI key="STATISTICS_MEAN">42.3852</MDI>
16 24 <MDI key="STATISTICS_MINIMUM">4</MDI>
17   - <MDI key="STATISTICS_STDDEV">24,80206485275</MDI>
  25 + <MDI key="STATISTICS_STDDEV">24.80206485275</MDI>
18 26 </Metadata>
19 27 </PAMRasterBand>
20 28 <PAMRasterBand band="2">
... ... @@ -27,12 +35,20 @@
27 35 <Approximate>0</Approximate>
28 36 <HistCounts>1|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|2|0|0|7|0|0|13|0|0|30|0|5|0|0|74|0|0|66|0|11|0|0|1|0|0|7|0|0|12|0|15|0|0|1|0|0|24|0|0|32|0|51|0|0|22|0|0|37|0|0|53|0|79|0|0|62|0|0|114|0|161|0|0|123|0|0|50|0|0|55|0|74|0|0|44|0|0|33|0|0|27|0|37|0|0|48|0|0|29|0|21|0|0|29|0|0|25|0|0|28|0|11|0|0|34|0|0|20|0|0|30|0|9|0|0|25|0|0|31|0|28|0|0|21|0|0|17|0|0|30|0|28|0|0|18|0|0|18|0|0|38|0|29|0|0|24|0|0|25|0|28|0|0|28|0|0|21|0|0|22|0|24|0|0|31|0|0|24|0|0|21|0|21|0|0|15|0|0|19|0|0|14|0|21|0|0|20|0|0|15|0|11|0|0|8|0|0|17|0|0|21|0|13|0|0|27|0|0|18|0|0|10|0|4|0|0|15|0|0|12|0|5|0|0|3|0|0|3|0|0|3|0|6|0|0|2|0|0|0|0|0|3|0|2|0|0|0|0|0|1|0|3|0|0|4|0|0|1|0|0|1|0|3|0|0|2|0|0|0|0|0|2|0|2|0|0|1|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|1|0|0|0|0|0|1|0|0|0|0|2|0|0|1|0|0|2|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|1|0|0|1|0|0|1|0|2|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|1|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1</HistCounts>
29 37 </HistItem>
  38 + <HistItem>
  39 + <HistMin>7.817</HistMin>
  40 + <HistMax>374.183</HistMax>
  41 + <BucketCount>1000</BucketCount>
  42 + <IncludeOutOfRange>0</IncludeOutOfRange>
  43 + <Approximate>0</Approximate>
  44 + <HistCounts>1|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|2|0|0|7|0|0|13|0|0|30|0|5|0|0|74|0|0|66|0|11|0|0|1|0|0|7|0|0|12|0|15|0|0|1|0|0|24|0|0|32|0|51|0|0|22|0|0|37|0|0|53|0|79|0|0|62|0|0|114|0|161|0|0|123|0|0|50|0|0|55|0|74|0|0|44|0|0|33|0|0|27|0|37|0|0|48|0|0|29|0|21|0|0|29|0|0|25|0|0|28|0|11|0|0|34|0|0|20|0|0|30|0|9|0|0|25|0|0|31|0|28|0|0|21|0|0|17|0|0|30|0|28|0|0|18|0|0|18|0|0|38|0|29|0|0|24|0|0|25|0|28|0|0|28|0|0|21|0|0|22|0|24|0|0|31|0|0|24|0|0|21|0|21|0|0|15|0|0|19|0|0|14|0|21|0|0|20|0|0|15|0|11|0|0|8|0|0|17|0|0|21|0|13|0|0|27|0|0|18|0|0|10|0|4|0|0|15|0|0|12|0|5|0|0|3|0|0|3|0|0|3|0|6|0|0|2|0|0|0|0|0|3|0|2|0|0|0|0|0|1|0|3|0|0|4|0|0|1|0|0|1|0|3|0|0|2|0|0|0|0|0|2|0|2|0|0|1|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|1|0|0|0|0|0|1|0|0|0|0|2|0|0|1|0|0|2|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|1|0|0|1|0|0|1|0|2|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|1|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1</HistCounts>
  45 + </HistItem>
30 46 </Histograms>
31 47 <Metadata>
32 48 <MDI key="STATISTICS_MAXIMUM">374</MDI>
33   - <MDI key="STATISTICS_MEAN">50,8404</MDI>
  49 + <MDI key="STATISTICS_MEAN">50.8404</MDI>
34 50 <MDI key="STATISTICS_MINIMUM">8</MDI>
35   - <MDI key="STATISTICS_STDDEV">27,191626060977</MDI>
  51 + <MDI key="STATISTICS_STDDEV">27.191626060977</MDI>
36 52 </Metadata>
37 53 </PAMRasterBand>
38 54 <PAMRasterBand band="3">
... ... @@ -45,12 +61,20 @@
45 61 <Approximate>0</Approximate>
46 62 <HistCounts>1|0|0|0|0|5|0|15|0|0|21|0|36|0|21|0|0|52|0|30|0|6|0|0|2|0|2|0|0|5|0|9|0|4|0|0|1|0|1|0|0|5|0|1|0|2|0|0|4|0|5|0|6|0|0|2|0|4|0|0|6|0|7|0|10|0|0|14|0|11|0|0|17|0|13|0|23|0|0|23|0|13|0|20|0|0|19|0|25|0|0|27|0|26|0|25|0|0|20|0|31|0|0|34|0|30|0|35|0|0|24|0|37|0|28|0|0|35|0|28|0|0|16|0|25|0|31|0|0|37|0|34|0|0|23|0|27|0|37|0|0|30|0|21|0|21|0|0|23|0|31|0|0|25|0|20|0|20|0|0|28|0|36|0|0|35|0|22|0|14|0|0|31|0|35|0|21|0|0|28|0|22|0|0|25|0|35|0|43|0|0|22|0|26|0|0|18|0|27|0|28|0|0|22|0|15|0|16|0|0|13|0|20|0|0|14|0|11|0|13|0|0|13|0|16|0|0|12|0|11|0|15|0|0|13|0|6|0|11|0|0|13|0|10|0|0|8|0|15|0|10|0|0|16|0|11|0|14|0|0|13|0|8|0|0|15|0|16|0|16|0|0|18|0|20|0|0|20|0|22|0|20|0|0|24|0|16|0|13|0|0|20|0|12|0|0|32|0|21|0|13|0|0|14|0|11|0|0|13|0|10|0|5|0|0|6|0|3|0|4|0|0|1|0|3|0|0|3|0|5|0|5|0|0|1|0|5|0|0|5|0|2|0|1|0|0|2|0|1|0|1|0|0|0|0|0|0|0|1|0|0|0|1|0|0|0|0|0|0|0|1|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|2|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|2|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1</HistCounts>
47 63 </HistItem>
  64 + <HistItem>
  65 + <HistMin>21.7905</HistMin>
  66 + <HistMax>441.2095</HistMax>
  67 + <BucketCount>1000</BucketCount>
  68 + <IncludeOutOfRange>0</IncludeOutOfRange>
  69 + <Approximate>0</Approximate>
  70 + <HistCounts>1|0|0|0|0|5|0|15|0|0|21|0|36|0|21|0|0|52|0|30|0|6|0|0|2|0|2|0|0|5|0|9|0|4|0|0|1|0|1|0|0|5|0|1|0|2|0|0|4|0|5|0|6|0|0|2|0|4|0|0|6|0|7|0|10|0|0|14|0|11|0|0|17|0|13|0|23|0|0|23|0|13|0|20|0|0|19|0|25|0|0|27|0|26|0|25|0|0|20|0|31|0|0|34|0|30|0|35|0|0|24|0|37|0|28|0|0|35|0|28|0|0|16|0|25|0|31|0|0|37|0|34|0|0|23|0|27|0|37|0|0|30|0|21|0|21|0|0|23|0|31|0|0|25|0|20|0|20|0|0|28|0|36|0|0|35|0|22|0|14|0|0|31|0|35|0|21|0|0|28|0|22|0|0|25|0|35|0|43|0|0|22|0|26|0|0|18|0|27|0|28|0|0|22|0|15|0|16|0|0|13|0|20|0|0|14|0|11|0|13|0|0|13|0|16|0|0|12|0|11|0|15|0|0|13|0|6|0|11|0|0|13|0|10|0|0|8|0|15|0|10|0|0|16|0|11|0|14|0|0|13|0|8|0|0|15|0|16|0|16|0|0|18|0|20|0|0|20|0|22|0|20|0|0|24|0|16|0|13|0|0|20|0|12|0|0|32|0|21|0|13|0|0|14|0|11|0|0|13|0|10|0|5|0|0|6|0|3|0|4|0|0|1|0|3|0|0|3|0|5|0|5|0|0|1|0|5|0|0|5|0|2|0|1|0|0|2|0|1|0|1|0|0|0|0|0|0|0|1|0|0|0|1|0|0|0|0|0|0|0|1|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|2|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|2|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1</HistCounts>
  71 + </HistItem>
48 72 </Histograms>
49 73 <Metadata>
50 74 <MDI key="STATISTICS_MAXIMUM">441</MDI>
51   - <MDI key="STATISTICS_MEAN">91,5736</MDI>
  75 + <MDI key="STATISTICS_MEAN">91.5736</MDI>
52 76 <MDI key="STATISTICS_MINIMUM">22</MDI>
53   - <MDI key="STATISTICS_STDDEV">37,794134241176</MDI>
  77 + <MDI key="STATISTICS_STDDEV">37.794134241176</MDI>
54 78 </Metadata>
55 79 </PAMRasterBand>
56 80 </PAMDataset>
... ...
data/config/test_config_classifCropMix_bindings.cfg
... ... @@ -6,6 +6,7 @@ chain:
6 6 {
7 7 executionMode: 'sequential'#parallel/sequential
8 8 outputPath:'/mnt/data/home/vincenta/IOTA2/test_data/resTest/'
  9 + remove_outputPath:False
9 10 jobsPath:''
10 11 pyAppPath:'/mnt/data/home/vincenta/IOTA2/theia_oso/scripts/common'
11 12 chainName:'OSO_chain_test'
... ... @@ -29,6 +30,8 @@ chain:
29 30 dataField:'CODE'
30 31 runs:'1'
31 32 ratio:'0.5'
  33 + firstStep:init
  34 + lastStep:validation
32 35 cloud_threshold:'1'
33 36 spatialResolution:'30'
34 37  
... ... @@ -59,6 +62,7 @@ argTrain:
59 62 outputPrevFeatures:'/work/OT/theia/oso/features/L8_2014_features/'
60 63 annualCrop:['11','12']
61 64 ACropLabelReplacement:['10','annualCrop']
  65 + annualClassesExtractionSource:'None'
62 66 samplesClassifMix:'True'
63 67 configClassif:''
64 68 validityThreshold : '5'
... ...
data/config/test_config_cropMix_bindings.cfg
... ... @@ -5,6 +5,7 @@
5 5 chain:
6 6 {
7 7 executionMode: 'sequential'#parallel/sequential
  8 + remove_outputPath:False
8 9 outputPath:''
9 10 jobsPath:''
10 11 pyAppPath:''
... ... @@ -32,6 +33,9 @@ chain:
32 33 cloud_threshold:'1'
33 34 spatialResolution:'30'
34 35  
  36 + firstStep:init
  37 + lastStep:validation
  38 +
35 39 logPath:''
36 40 colorTable:'/mnt/data/home/vincenta/IOTA2/test_data/color.txt'
37 41 mode_outside_RegionSplit:'6900'#square km
... ... @@ -60,6 +64,7 @@ argTrain:
60 64 annualCrop:['11','12']
61 65 ACropLabelReplacement:['10','annualCrop']
62 66 samplesClassifMix:'False'
  67 + annualClassesExtractionSource:'None'
63 68 configClassif:''
64 69 validityThreshold : '5'
65 70 coeffSampleSelection : '0.1'
... ...
data/test_scripts/test_genGrid.py
... ... @@ -54,34 +54,35 @@ def generateTif(vectorFile,pixSize):
54 54  
55 55 def genGrid(outputDirectory,X=10,Y=10,overlap=10,size=100,raster = "True",pixSize = 100):
56 56  
57   - origin = (500100,6211230)#lower left
58   - geom_grid = genGeometries(origin,size,X,Y,overlap)
59   - driver = ogr.GetDriverByName("ESRI Shapefile")
60   - srs = osr.SpatialReference()
61   - srs.ImportFromEPSG(2154)
62   -
63   - tile = 1
64   - for raw in geom_grid:
65   - for col in raw:
66   - outTile = outputDirectory+"/Tile_"+str(tile)+".shp"
67   - if os.path.exists(outTile): driver.DeleteDataSource(outTile)
68   - data_source = driver.CreateDataSource(outTile)
69   - layerName = outTile.split("/")[-1].split(".")[0]
70   - layer = data_source.CreateLayer(layerName, srs, geom_type=ogr.wkbPolygon)
71   - field_tile = ogr.FieldDefn("Tile", ogr.OFTInteger)
72   - field_tile.SetWidth(5)
73   - layer.CreateField(field_tile)
74   - feature = ogr.Feature(layer.GetLayerDefn())
75   - feature.SetField("Tile", tile)
76   - feature.SetGeometry(col)
77   - layer.CreateFeature(feature)
78   - tile+=1
79   - feature = None
80   - data_source = None
81   -
82   - if raster == "True":
83   - generateTif(outTile,pixSize)
84   - if os.path.exists(outTile): driver.DeleteDataSource(outTile)
  57 + origin = (500100,6211230)#lower left
  58 + geom_grid = genGeometries(origin,size,X,Y,overlap)
  59 + driver = ogr.GetDriverByName("ESRI Shapefile")
  60 + srs = osr.SpatialReference()
  61 + srs.ImportFromEPSG(2154)
  62 +
  63 + tile = 1
  64 + for raw in geom_grid:
  65 + for col in raw:
  66 + outTile = outputDirectory+"/Tile"+str(tile)+".shp"
  67 + if os.path.exists(outTile): driver.DeleteDataSource(outTile)
  68 + data_source = driver.CreateDataSource(outTile)
  69 + layerName = outTile.split("/")[-1].split(".")[0]
  70 + layer = data_source.CreateLayer(layerName, srs, geom_type=ogr.wkbPolygon)
  71 + field_tile = ogr.FieldDefn("Tile", ogr.OFTInteger)
  72 + field_tile.SetWidth(5)
  73 + layer.CreateField(field_tile)
  74 + feature = ogr.Feature(layer.GetLayerDefn())
  75 + feature.SetField("Tile", tile)
  76 + feature.SetGeometry(col)
  77 + layer.CreateFeature(feature)
  78 + tile+=1
  79 + feature = None
  80 + data_source = None
  81 +
  82 + if raster == "True":
  83 + generateTif(outTile,pixSize)
  84 + #if os.path.exists(outTile):
  85 + # driver.DeleteDataSource(outTile)
85 86  
86 87  
87 88 if __name__ == "__main__":
... ...
doc/running_iota.org
... ... @@ -51,6 +51,7 @@ This part corresponds to the general description of the test.
51 51 |--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------+--------------------------------------------------------------------------------------------|
52 52 | exectutionMode | this argument determine the chain's launching mode (sequential or parallel) | must be 'parallel' or 'sequential' | type : 'sequential' |
53 53 | outputPath | root path to the test folder. It is recommended to have one folder by test | - | testPath : '/root/path/to/Test/' |
  54 +| remove_outputPath | remove 'outputPath' if set to True | must be a bool, True or False | remove_outputPath:True |
54 55 | jobsPath | root path to the job folder. If the folder does not exist, he will be created. If jobs already exist inside the folder, they will be overwritten | only for parallel mode | jobsPath : '/root/path/to/Jobs/' |
55 56 | pyAppPath | root path to the Iota python's script | - | pyAppPath : '/root/path/to/PyApp/' |
56 57 | chainName | the name of the file which will contain the chain | if the name already exist, he will be overwritten. | chainName : 'MyFirstChain' |
... ... @@ -65,16 +66,20 @@ This part corresponds to the general description of the test.
65 66 | dataField | field that discriminates datas into the ground truth shapeFile | that field must contain integer | dataField : 'My_int_Data' |
66 67 | mode | models repartition mode among tiles | must be 'multi_regions','one_region' or 'outside'(2) | mode : 'multi_regions' |
67 68 | regionPath | root path to the shapeFile which contains regions. This file will be created if the field 'mode' is different from 'outside' | must be a shapeFile | regionPath : '/to/my/region.shp' |
68   -| regionField | field that discriminates regions into the region shapeFile | that field must contain integer | regionField : 'My_int_region' |
  69 +| regionField | field that discriminates regions into the region shapeFile | that field must contain string representing integers | regionField : 'My_int_region' |
69 70 | model | root path to the file which link tiles and their belonging model | that file must respect a syntax as explain in (3) | model : '/to/my/modelDescription.txt' |
70   -| runs | number of random sample for training and validation | must be a string different from 0 | sample : '1' |
  71 +| runs | number of random sample for training and validation | must be an integer different from 0 | runs : 1 |
71 72 | logPath | root path to the folder which will contains log files | only for parallel mode | logPath : '/to/my/log/folder/' |
  73 +| logFileLevel | logging level, 5 levels are available : "CRITICAL"<"ERROR"<"WARNING"<"INFO"<"DEBUG" | | logFileLevel:"INFO" |
  74 +| enableConsole | enable console logging (False par default) | must be a bool | enableConsole:False |
72 75 | OTB_HOME | root path to the OTB installation directory | must be a string (4) | OTB_HOME:'/path/to/otb' |
73 76 | colorTable | root path to the file wich link classes and their color | must respect (5) | colorTable:'/path/to/MyColorFile.txt' |
74 77 | mode_outside_RegionSplit | (enable when the fusion of classification is on) with the outside mode, define the threshold beyond the biggest region will be split | a float in km^2 | mode_outside_RegionSplit:'1000' |
75   -| ratio | Training and validation sample ratio | must be between [0;1] | ratio:'0.5' |
76   -| cloud_treshold | a valid pixel is a pixel which is less "cloud_treshold" under clouds | >=0 | cloud_treshold:'1' |
77   -| spatialResolution | output pixel's spatial resolution | - | spatialResolution:'30' |
  78 +| ratio | Training and validation sample ratio | must be a float between [0;1] | ratio:0.5 |
  79 +| cloud_treshold | a valid pixel is a pixel which is less "cloud_treshold" under clouds | must be an integer >= 0 | cloud_threshold:1 |
  80 +| spatialResolution | output pixel's spatial resolution | - | spatialResolution:30 |
  81 +| firstStep | parameter use to restart chain from a specific step. Available choices are init,sampling,learning,classification,mosaic or validation | must be chosen into the list of available steps | firstStep:"init" |
  82 +| lastStep | parameter use to stop chain from a specific step. Available choices are init,sampling,learning,classification,mosaic or validation | must be chosen into the list of available steps | lastStep:"validation" |
78 83  
79 84 (1) Example of file describing nomenclature
80 85  
... ... @@ -131,23 +136,38 @@ Each line describre a label and it&#39;s color (no empty line).The first number is t
131 136  
132 137 This part is dedicated to the learning mode.
133 138  
134   -| field | Description | Conditions | Example |
135   -|-------------------------------+------------------------------------------------------------------------------------------+---------------------------------------------------+-----------------------------------------------------------------------------|
136   -| classifier | the classifier asks | should exist in OTB | classifier : 'rf' |
137   -| options | classifier options | should exist in OTB | options : '-classifier.rf.min 5' |
138   -| rearrangeModelTile | rearrange model's repartition by tile, considering class | must be False or True | rearrangeModelTile : False |
139   -| rearrangeModelTile_out | path to the new repartiton file | - | rearrangeModelTile_out : '/home/Rearrange.txt' |
140   -| shapeMode | define the way to use groundTruth, sampled (points) or not (polygons) | must be 'points' or 'polygons' | shapeMode:'points' |
141   -| samplesOptions | if shapeMode options is use, define sampler parameters (SampleSelection OTB application) | parameters as describe in OTB cookbook (> v5.6) | samplesOptions:'-sampler random -strategy constant -strategy.constant.nb 2' |
142   -| cropMix | flag to use previous crop datas | must be 'True' or 'False' | cropMix:'True' |
143   -| prevFeatures | path to a configuration file which is able to produce annual features | must be a string | prevFeatures:'/../2013/config_2013.cfg' |
144   -| outputPrevFeatures | path to store features extract from prevFeatures | must be a string | outputPrevFeatures:'../2013/' |
145   -| annualCrop | crop's class number | must be a list of string and exist in groundTruth | annualCrop:['11','12'] |
146   -| ACropLabelReplacement | list which contains a label and a name to replace annual crop | must be a list | ACropLabelReplacement:['10','annualCrop'] |
147   -| samplesClassifMix | flag to pick annual crop in a previous classificaiton | must be 'True' or 'Flase' | samplesClassifMix:'True' |
148   -| annualClassesExtractionSource | path to a previous run of IOTA2 (use if samplesClassif is set to True) | must be a string | configClassif:'/path/to/aPreviousIOTA2_run' |
149   -| validityTreshold | chose pixels only if validity > threshold | must be a int string | validityThreshold:'5' |
150   -| coeffSampleSelection | in samplesClassifMix, percentage of annualCrop to pick up | string between [0,1] | coeffSampleSelection:'1' |
  139 +| field | Description | Conditions | Example |
  140 +|-------------------------------+------------------------------------------------------------------------+---------------------------------------------------+---------------------------------------------|
  141 +| classifier | the classifier asks | should exist in OTB | classifier : 'rf' |
  142 +| options | classifier options | should exist in OTB | options : '-classifier.rf.min 5' |
  143 +| cropMix | flag to use previous crop datas | must be True or False | cropMix:True |
  144 +| prevFeatures | path to a configuration file which is able to produce annual features | must be a string | prevFeatures:'/../2013/config_2013.cfg' |
  145 +| outputPrevFeatures | path to store features extract from prevFeatures | must be a string | outputPrevFeatures:'../2013/' |
  146 +| annualCrop | crop's class number | must be a list of string and exist in groundTruth | annualCrop:['11','12'] |
  147 +| ACropLabelReplacement | list which contains a label and a name to replace annual crop | must be a list | ACropLabelReplacement:['10','annualCrop'] |
  148 +| samplesClassifMix | flag to pick annual crop in a previous classificaiton | must be True or False | samplesClassifMix:True |
  149 +| annualClassesExtractionSource | path to a previous run of IOTA2 (use if samplesClassif is set to True) | must be a string | configClassif:'/path/to/aPreviousIOTA2_run' |
  150 +| validityTreshold | chose pixels only if validity > threshold | must be an integer | validityThreshold:5 |
  151 +| sampleSelection | parameter to set sample selection strategies | python dictionnary format | (1) |
  152 +
  153 +(1)
  154 +#+BEGIN_EXAMPLE python
  155 +sampleSelection : {"sampler":"random",
  156 + "strategy":"percent",
  157 + "strategy.percent.p":0.2,
  158 + "ram":4000,
  159 + "per_model":[{"target_model":4,
  160 + "sampler":"periodic"},
  161 + {"target_model":"2",
  162 + "sampler":"periodic",
  163 + "ram":"10000"}]
  164 + }
  165 +#+END_EXAMPLE
  166 +The purpose of this parameter is to set a strategy to select samples inside learning polygons (which are compute by iota2). The strategy is apply on each different regions.
  167 +It's also possible to set a specific strategy for a given learning region throught the "per_model" key parameter.
  168 +
  169 +In the example above, if the regions shape contains 5 differents regions : "1", "2", "3", "4" the regions "4"
  170 +every keys except "per_models" and "target_model" are OTB's sampleSelection parameters. You can add/remove sampleSelection parameter key depending of your sampling methode choice.
151 171  
152 172 ** Classifications
153 173  
... ... @@ -157,8 +177,7 @@ Classification&#39;s options
157 177 |-------------------+---------------------------------------------------------------------------------+---------------------------------------------+---------------------------------------------------------|
158 178 | classifMode | argument uses in order to indicate if fusion of classification will be used (1) | must be 'fusion' or 'seperate' | classifMode : 'fusion' |
159 179 | fusionOptions | parameters for fusion of classification | these parameters must exist in OTB | fusionOptions : '-nodatalabel 0 -method majorityvoting' |
160   -| pixType | the type of the output pixel in classification | - | pixType : 'int8' |
161   -| confusionModel | argument use to indicate if you also want a confusion matrix by model | must be False or True | confusionModel:False |
  180 +| pixType | output classification's pixel format | - | pixType : 'uint8' |
162 181 | noLabelManagement | use to indice how to manage Nolabels (in fusion mode) (2) | must be 'maxConfidence' or learningPriority | noLabelManagement:'maxConfidence' |
163 182  
164 183 (1) Explanation about classifMode's options
... ... @@ -181,36 +200,34 @@ Classification&#39;s options
181 200  
182 201 Today, features computable are : NDVI, NDWI and the brightness. Only two sensors are supported, Landsat_8 and Landsat_5, but some others are coming soon. So you only have to fill out the Landsat_8 block composed by many fields.
183 202  
184   -| field | Description | Conditions | Example |
185   -|-----------------------+--------------------------------------------------------------------------------------------------------------+----------------------------------------------------+------------------------------------------------------------------------------|
186   -| nodata_Mask | argument used to indicate if a NoData mask exists | must be 'False' or 'True' | nodata_Mask : 'False' |
187   -| nativeRes | native resolution of images | must be an integer | nativeRes : 30 |
188   -| arbo | inform the image's path, according to L8Path (1) | - | arbo : /*/* |
189   -| imtype | allow you to target a specific images in arbo | - | imtype : "ORTHO_SURF_CORR_PENTE*.TIF" |
190   -| arbomask | inform the path of the mask link to the image, according to L8Path | - | arbomask : "*/*/MASK/" |
191   -| nuages | target the mask of cloud in arbomask | - | nuages : "NUA.TIF" |
192   -| saturation | target the mask of saturation in arbomask | - | saturation : "SAT.TIF" |
193   -| div | target the mask of diverse in arbomask | - | div : "DIV.TIF" |
194   -| nodata | target the nodata mask in arbomask | - | nodata : "NODATA.TIF" if nodata_Mask is set to 'False', nodata could be : "" |
195   -| features | describre which features uses | must be a list of strings (2) | features: ["NDVI","NDWI","Brightness"] |
196   -| nbLook | number of data available needed to consider a pixel to produce features | must be an integer >= 1 | nbLook:1 |
197   -| proj | output projection | must be an EPSG code | proj:"EPSG:2154" |
198   -| temporalResolution | temporal resolution in order to manage gapfilling (cloud management) | - | temporalResolution:'16'#Landsat8 case |
199   -| batchProcessing | mode to produce features (3) | must be 'True' or 'False' | batchProcessing:'True' |
200   -| autoDate | force gapfilling's output date or not | must be 'True' or 'False' | autoDate:'True' |
201   -| bindingPython | flag to use or not use binding python | must be 'True' or 'False' | bindingPython:'True' |
202   -| startDate | starting date to use in gapfilling ouput | must be 'YYYYMMDD' | startDate:'20150121' |
203   -| endDate | ending date to use in gapfilling ouput | must be 'YYYYMMDD' | endDate:'20151205' |
204   -| patterns | in user's features, pattern to chose features | - | patterns:'ALT,MNT' |
205   -| extractBands | flag to use targeted bands if not use (False) -> all bands are used | must be 'True' or 'False' | extractBands:'False' |
206   -| keepBands | bands to keep to produce features | must respect Sensors.py definition (4) | keepBands:[[1,"blue"],[2,"green"],[3,"red"],[7,"NIR"],[9,"SWIR"]] |
207   -| copyinput | if bindingPython is set to 'True', use sensor's data and derivated ceofficient | must be 'True' or 'False' | copyinput:'True' |
208   -| relrefl | normalize bands by the red band SWIR_norm = (SWIR-RED)/(SWIR+RED) | must be 'True' or 'False' | relrefl:'False' |
209   -| keepduplicates | using red normalization could introduce duplicate data, set keepduplicate to 'False' remove duplicates bands | must be 'True' or 'False' | keepduplicates:'False' |
210   -| additionalFeatures | user features definition | must be a bandMath (OTB) expression, comma splited | additionalFeatures:"b1+b2,(b1-b2)/(b1+b2)" |
211   -| useAdditionalFeatures | flag to indicate if the chain must use 'additionalFeatures' | must be 'True' or 'False' | useAdditionalFeatures:'False' |
212   -| writeOutputs | flag to indicate if temporary files musk be written on disk (faster if set to 'False') | must be 'True' or 'False' | writeOutputs:'False' |
213   -| useGapFilling | flag to use temporal interpolation | must be 'True' or 'False' | useGapFilling : 'True' |
  203 +| field | Description | Conditions | Example |
  204 +|-----------------------+----------------------------------------------------------------------------------------------------------------+----------------------------------------------------+----------------------------------------------------------------------------|
  205 +| nodata_Mask | argument used to indicate if a NoData mask exists | must be False or True | nodata_Mask : False |
  206 +| nativeRes | native resolution of images | must be an integer | nativeRes : 30 |
  207 +| arbo | inform the image's path, according to L8Path (1) | - | arbo : /*/* |
  208 +| imtype | allow you to target a specific images in arbo | - | imtype : "ORTHO_SURF_CORR_PENTE*.TIF" |
  209 +| arbomask | inform the path of the mask link to the image, according to L8Path | - | arbomask : "*/*/MASK/" |
  210 +| nuages | target the mask of cloud in arbomask | - | nuages : "NUA.TIF" |
  211 +| saturation | target the mask of saturation in arbomask | - | saturation : "SAT.TIF" |
  212 +| div | target the mask of diverse in arbomask | - | div : "DIV.TIF" |
  213 +| nodata | target the nodata mask in arbomask | - | nodata : "NODATA.TIF" if nodata_Mask is set to False, nodata could be : "" |
  214 +| features | describre which features uses | must be a list of strings (2) | features: ["NDVI","NDWI","Brightness"] |
  215 +| proj | output projection | must be an EPSG code | proj:"EPSG:2154" |
  216 +| temporalResolution | temporal resolution in order to manage gapfilling (cloud management) | - | temporalResolution:16 |
  217 +| autoDate | force gapfilling's output date or not | must be True or False | autoDate:True |
  218 +| startDate | starting date to use in gapfilling ouput | must be 'YYYYMMDD' | startDate:'20150121' |
  219 +| endDate | ending date to use in gapfilling ouput | must be 'YYYYMMDD' | endDate:'20151205' |
  220 +| patterns | in user's features, pattern to chose features | - | patterns:'ALT,MNT' |
  221 +| extractBands | flag to use targeted bands if not use (False) -> all bands are used | must be True or False | extractBands:False |
  222 +| keepBands | bands to keep to produce features | must respect Sensors.py definition (4) | keepBands:[[1,"blue"],[2,"green"],[3,"red"],[7,"NIR"],[9,"SWIR"]] |
  223 +| copyinput | if bindingPython is set to 'True', use sensor's data and derivated ceofficient | must be True or False | copyinput:True |
  224 +| relrefl | normalize bands by the red band SWIR_norm = (SWIR-RED)/(SWIR+RED) | must be True or False | relrefl:False |
  225 +| acorfeat | use atmospherically corrected normalized indices according to http://www.cesbio.ups-tlse.fr/multitemp/?p=12746 | must be True or False | acorfeat:False |
  226 +| keepduplicates | using red normalization could introduce duplicate data, set keepduplicate to 'False' remove duplicates bands | must be True or False | keepduplicates:False |
  227 +| additionalFeatures | user features definition | must be a bandMath (OTB) expression, comma splited | additionalFeatures:"b1+b2,(b1-b2)/(b1+b2)" |
  228 +| useAdditionalFeatures | flag to indicate if the chain must use 'additionalFeatures' | must be True or False | useAdditionalFeatures:False |
  229 +| writeOutputs | flag to indicate if temporary files musk be written on disk (faster if set to 'False') | must be True or False | writeOutputs:False |
  230 +| useGapFilling | flag to use temporal interpolation | must be True or False | useGapFilling : True |
214 231  
215 232  
216 233  
... ... @@ -240,11 +257,30 @@ Once the configuration file fill out, the chain can be launch.
240 257  
241 258 * How to launch Iota²
242 259  
243   -you only have to launch the launcher:
  260 +you only have to launch the python script as describe below:
244 261  
245   -cd /path/to/the/python/scripts
246   -. launchChain.sh /path/to/the/configuration/file.cfg
  262 +#+RESNAME:
  263 +#+BEGIN_EXAMPLE
  264 +python /script/common/iota2.py -config /path/to/theConfigurationFile.cfg
  265 +#+END_EXAMPLE
  266 +
  267 +or thanks to MPI :
  268 +
  269 +#+RESNAME:
  270 +#+BEGIN_EXAMPLE
  271 +mpirun -np XX python /script/common/iota2.py -config /path/to/theConfigurationFile.cfg
  272 +#+END_EXAMPLE
  273 +
  274 +where XX is the number of MPI processes.
  275 +
  276 +in order to accelerate computations, you can set the environnement variable 'ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS'
  277 +
  278 +#+RESNAME:
  279 +#+BEGIN_EXAMPLE
  280 +mpirun -x ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS=10 -np 4 python /script/common/iota2.py -config /path/to/theConfigurationFile.cfg
  281 +#+END_EXAMPLE
247 282  
  283 +This last exemple mean that iota² will launch 4 MPI process (3 workers and 1 master) and each process will use 10 threads
248 284 * Products
249 285  
250 286 Each chain creates a tree folder, from the path given in field output, as describe below
... ... @@ -271,6 +307,8 @@ Each chain creates a tree folder, from the path given in field output, as descri
271 307 │   └── commands uses in order to generate models
272 308 ├── dataAppVal
273 309 │   └── ground truth uses to learn models and during validation phase
  310 +├── SampleSelection
  311 +│   └── samples use to learn models (withou features)
274 312 ├── dataRegion
275 313 │   └── ground truth before the split learn-val
276 314 ├── envelope
... ... @@ -279,7 +317,7 @@ Each chain creates a tree folder, from the path given in field output, as descri
279 317 │   ├── final classification with and without color indexation
280 318 │   ├── RESULTS.txt
281 319 │   └── TMP
282   -│   └── some tmp results
  320 +│   └── some tmp data
283 321 ├── model
284 322 │   └── models generate during learning phase
285 323 ├── shapeRegion
... ...
otb-module.cmake
... ... @@ -18,6 +18,7 @@ otb_module(IOTA2
18 18 OTBApplicationEngine
19 19 OTBBoost
20 20 OTBTemporalGapFilling
  21 + OTBConversion
21 22 TEST_DEPENDS
22 23 OTBTestKernel
23 24 OTBCommandLine
... ...
scripts/common/ClassificationShaping.py
... ... @@ -15,14 +15,17 @@
15 15 # =========================================================================
16 16  
17 17 import argparse,os,re,shutil
  18 +import ast
18 19 from osgeo import gdal, ogr,osr
19 20 from config import Config
20 21 from osgeo.gdalconst import *
21 22 import fileUtils as fu
22 23 import CreateIndexedColorImage as color
23 24 import numpy as np
  25 +import serviceConfigFile as SCF
24 26 from Utils import run
25 27  
  28 +
26 29 def BuildNbVoteCmd(classifTile,VoteMap):
27 30  
28 31 exp = []
... ... @@ -170,7 +173,12 @@ def genGlobalConfidence(N, pathWd, cfg):
170 173 shutil.copyfile(globalConf, globalConf_f)
171 174 os.remove(globalConf)
172 175  
173   -def ClassificationShaping(pathClassif, pathEnvelope, pathImg, fieldEnv, N, pathOut, pathWd, cfg, colorpath):
  176 +
  177 +def ClassificationShaping(pathClassif, pathEnvelope, pathImg, fieldEnv, N,
  178 + pathOut, pathWd, cfg, colorpath):
  179 +
  180 + if not isinstance(cfg,SCF.serviceConfigFile):
  181 + cfg = SCF.serviceConfigFile(cfg)
174 182  
175 183 if pathWd == None:
176 184 TMP = pathOut+"/TMP"
... ... @@ -184,7 +192,6 @@ def ClassificationShaping(pathClassif, pathEnvelope, pathImg, fieldEnv, N, pathO
184 192 classifMode = cfg.getParam('argClassification', 'classifMode')
185 193 pathTest = cfg.getParam('chain', 'outputPath')
186 194 proj = cfg.getParam('GlobChain', 'proj').split(":")[-1]
187   - #AllTile = cfg.getParam('chain', 'listTile').split(" ")
188 195 AllTile = list(set([classif.split("_")[1] for classif in fu.FileSearch_AND(pathTest+"/classif",True,"Classif",".tif")]))
189 196 mode = cfg.getParam('chain', 'mode')
190 197 pixType = cfg.getParam('argClassification', 'pixType')
... ... @@ -253,7 +260,7 @@ def ClassificationShaping(pathClassif, pathEnvelope, pathImg, fieldEnv, N, pathO
253 260 if not os.path.exists(cloudTilePriority):
254 261 cmd_cloud = 'otbcli_BandMath -il '+cloudTile+' '+ClassifTile+' -out '+cloudTilePriority_tmp+' int16 -exp "im2b1>0?im1b1:0"'
255 262 run(cmd_cloud)
256   - if outputStatistics == "True":
  263 + if outputStatistics:
257 264 cmd_cloud = 'otbcli_BandMath -il '+cloudTile+' '+ClassifTile+' -out '+cloudTilePriority_tmp_StatsOK+' int16 -exp "im2b1>0?im1b1:-1"'
258 265 run(cmd_cloud)
259 266 if pathWd:
... ... @@ -263,7 +270,7 @@ def ClassificationShaping(pathClassif, pathEnvelope, pathImg, fieldEnv, N, pathO
263 270 if pathWd:
264 271 shutil.copy(cloudTilePriority_tmp,cloudTilePriority)
265 272 os.remove(cloudTilePriority_tmp)
266   -
  273 +
267 274 if pathWd != None:
268 275 run("cp -a "+TMP+"/* "+pathOut+"/TMP")
269 276  
... ... @@ -289,7 +296,6 @@ def ClassificationShaping(pathClassif, pathEnvelope, pathImg, fieldEnv, N, pathO
289 296  
290 297 if __name__ == "__main__":
291 298  
292   - import serviceConfigFile as SCF
293 299 parser = argparse.ArgumentParser(description = "This function shape classifications (fake fusion and tiles priority)")
294 300 parser.add_argument("-path.classif",help ="path to the folder which ONLY contains classification images (mandatory)",dest = "pathClassif",required=True)
295 301 parser.add_argument("-path.envelope",help ="path to the folder which contains tile's envelope (with priority) (mandatory)",dest = "pathEnvelope",required=True)
... ...
scripts/common/CreateDateFile.py
... ... @@ -12,9 +12,9 @@
12 12 # =========================================================================
13 13  
14 14 import datetime
  15 +import os
15 16  
16   -
17   -def CreateFichierDatesReg(debut,fin,gap,opath,sensorName):
  17 +def CreateFichierDatesReg(debut, fin, gap, opath, sensorName):
18 18 """
19 19 debut : liste [year,month,day]
20 20 end : idem
... ... @@ -22,30 +22,33 @@ def CreateFichierDatesReg(debut,fin,gap,opath,sensorName):
22 22 """
23 23 date_init = datetime.date(int(debut[0:4]),int(debut[4:6]),int(debut[6:8]))
24 24 date_end = datetime.date(int(fin[0:4]),int(fin[4:6]),int(fin[6:8]))
25   - fich = open(opath+"/DatesInterpReg"+sensorName+".txt","w")
26   - gap = int(gap)
27   - ndate = date_init.isoformat()
28   - ndate = ndate.split("-")
29   - ndate = ndate[0]+ndate[1]+ndate[2]
  25 +
  26 + outputDateFile = opath+"/DatesInterpReg"+sensorName+".txt"
  27 + if not os.path.exists(outputDateFile):
  28 + fich = open(outputDateFile,"w")
  29 + gap = int(gap)
  30 + ndate = date_init.isoformat()
  31 + ndate = ndate.split("-")
  32 + ndate = ndate[0]+ndate[1]+ndate[2]
30 33  
31   - fich.write(ndate+"\n")
  34 + fich.write(ndate+"\n")
32 35  
33   - date = date_init+datetime.timedelta(days=gap)
34   - #print date.isoformat()
35   - date = date_init
36   - date_end_1 = date_end-datetime.timedelta(days=1)
37   - while(date+datetime.timedelta(days=gap) < date_end_1):
38   - new_date = date+datetime.timedelta(days=gap)
  36 + date = date_init+datetime.timedelta(days=gap)
  37 + #print date.isoformat()
  38 + date = date_init
  39 + date_end_1 = date_end-datetime.timedelta(days=1)
  40 + while(date+datetime.timedelta(days=gap) < date_end_1):
  41 + new_date = date+datetime.timedelta(days=gap)
39 42  
40   - ndate = new_date.isoformat()
  43 + ndate = new_date.isoformat()
  44 + ndate = ndate.split("-")
  45 + ndate = ndate[0]+ndate[1]+ndate[2]
  46 + date = new_date
  47 + fich.write(ndate+"\n")
  48 +
  49 + ndate = date_end.isoformat()
41 50 ndate = ndate.split("-")
42 51 ndate = ndate[0]+ndate[1]+ndate[2]
43   - date = new_date
44   - fich.write(ndate+"\n")
45   -
46   - ndate = date_end.isoformat()
47   - ndate = ndate.split("-")
48   - ndate = ndate[0]+ndate[1]+ndate[2]
49   - fich.write(ndate)
50   - fich.close()
  52 + fich.write(ndate)
  53 + fich.close()
51 54 return opath+"/DatesInterpReg"+sensorName+".txt"
... ...
scripts/common/ExtractDataByRegion.py
... ... @@ -20,11 +20,19 @@ from osgeo import gdal, ogr,osr
20 20 import fileUtils as fu
21 21 import NbView
22 22 from config import Config
  23 +import serviceConfigFile as SCF
  24 +import random
  25 +import logging
23 26  
24   -def ExtractData(pathToClip, shapeData, pathOut, pathFeat, cfg, pathWd):
  27 +logger = logging.getLogger(__name__)
  28 +
  29 +def ExtractData(pathToClip, shapeData, pathOut, pathFeat, cfg, pathWd, logger=logger):
25 30 """
26 31 Clip the shapeFile pathToClip with the shapeFile shapeData and store it in pathOut
27 32 """
  33 + logger.info("Clip %s and %s"%(shapeData, pathToClip))
  34 + if not isinstance(cfg,SCF.serviceConfigFile):
  35 + cfg = SCF.serviceConfigFile(cfg)
28 36  
29 37 cloud_threshold = str(cfg.getParam('chain', 'cloud_threshold'))
30 38 featuresPath = cfg.getParam('chain', 'featuresPath')
... ... @@ -36,7 +44,8 @@ def ExtractData(pathToClip, shapeData, pathOut, pathFeat, cfg, pathWd):
36 44 dataSource = driver.Open(pathToClip, 0) # 0 means read-only. 1 means writeable.
37 45 # Check to see if shapefile is found.
38 46 if dataSource is None:
39   - print 'Could not open %s' % (pathToClip)
  47 + raise Exception("Could not open vector file")
  48 + logger.error('Could not open %s'%(pathToClip))
40 49 else:
41 50 layer = dataSource.GetLayer()
42 51 featureCount = layer.GetFeatureCount()
... ... @@ -46,11 +55,15 @@ def ExtractData(pathToClip, shapeData, pathOut, pathFeat, cfg, pathWd):
46 55 if pathWd == None:
47 56 pathName = pathOut
48 57 CloudMask = featuresPath+"/"+currentTile+"/CloudThreshold_"+cloud_threshold+".shp"
49   - NbView.genNbView(featuresPath+"/"+currentTile,CloudMask,cloud_threshold,cfg,pathWd)
50   -
51   - path_tmp = fu.ClipVectorData(shapeData,pathFeat+"/"+currentTile+"/tmp/"+fu.getCommonMaskName(cfg)+".shp", pathName)
  58 + shapeName = os.path.splitext(os.path.split(shapeData)[-1])[0]
  59 + randomSeed = "_r" + str(random.randint(1, 1000)) + "_"
  60 + clip1_Name = shapeName+"_"+currentTile+"_"+randomSeed+fu.getCommonMaskName(cfg)
  61 + path_tmp = fu.ClipVectorData(shapeData,pathFeat+"/"+currentTile+"/tmp/"+fu.getCommonMaskName(cfg)+".shp", pathName, nameOut=clip1_Name)
52 62 path_tmp2 = fu.ClipVectorData(path_tmp, pathToClip, pathName)
53 63 path = fu.ClipVectorData(path_tmp2, CloudMask, pathName)
  64 + fu.cpShapeFile(path.replace(".shp",""),path.replace(".shp","").replace(randomSeed,""),[".prj",".shp",".dbf",".shx"])
  65 + fu.removeShape(path.replace(".shp",""),[".prj",".shp",".dbf",".shx"])
  66 + path = path.replace(randomSeed,"")
54 67 if fu.multiSearch(path):
55 68 NoMulti = path.replace(".shp","_NoMulti.shp")
56 69 fu.multiPolyToPoly(path,NoMulti)
... ... @@ -62,11 +75,12 @@ def ExtractData(pathToClip, shapeData, pathOut, pathFeat, cfg, pathWd):
62 75 else:
63 76 fu.removeShape(path_tmp.replace(".shp",""),[".prj",".shp",".dbf",".shx"])
64 77 fu.removeShape(path_tmp2.replace(".shp",""),[".prj",".shp",".dbf",".shx"])
  78 + else:
  79 + logger.warning("No features in %s"%(pathToClip))
65 80  
66 81 if __name__ == "__main__":
67 82  
68   - import serviceConfigFile as SCF
69   - parser = argparse.ArgumentParser(description = "This function allow you to create N training and N validation shapes by regions cut by tiles")
  83 + parser = argparse.ArgumentParser(description = "This function allow you to create shapes by regions cut by tiles")
70 84 parser.add_argument("-shape.region",help ="path to a shapeFile representing the region in one tile (mandatory)",dest = "clip",required=True)
71 85 parser.add_argument("-shape.data",dest = "dataShape",help ="path to the shapeFile containing datas (mandatory)",required=True)
72 86 parser.add_argument("-out",dest = "pathOut",help ="path where to store all shapes by tiles (mandatory)",required=True)
... ...
scripts/common/GenSensors.py
... ... @@ -20,13 +20,16 @@ Define each sensor for generic processing
20 20  
21 21 """
22 22 import glob
  23 +import logging
23 24 from osgeo import gdal,osr,ogr
24 25 import os
25 26 import New_DataProcessing as DP
26 27 import otbApplication as otb
27 28 import otbAppli
28 29 from Utils import run
29   -#import fileUtils as fut
  30 +import logging
  31 +
  32 +logger = logging.getLogger(__name__)
30 33  
31 34 pixelo = 'int16'
32 35  
... ... @@ -81,10 +84,39 @@ class Sensor(object):
81 84 def getDatesVoulues(self):
82 85 return self.DatesVoulues
83 86  
84   - def getImages(self,opath):
  87 + def setInputDatesFile(self, opath=None):
  88 +
  89 + count = 0
  90 + imageList = []
  91 +
  92 + fList = []
  93 +
  94 + for image in glob.glob(self.path+self.struct_path+self.imType):
  95 + imagePath = image.split("/")
  96 + imageName = imagePath[-1].split("_")
  97 + imageList.append(imageName)
  98 +
  99 + #Organize the names by date
  100 + imageList.sort(key=lambda x: x[self.posDate])
  101 +
  102 + dates = []
  103 + for imSorted in imageList:
  104 + date = imSorted[self.posDate].split("-")[0]
  105 + dates.append(date)
  106 +
  107 + outputDateFile = self.fdates
  108 + if opath:
  109 + outputDateFile = os.path.join(opath, os.path.split(self.fdates)[-1])
  110 + if not os.path.exists(outputDateFile):
  111 + with open(outputDateFile, "w") as filedate:
  112 + filedate.write("\n".join(dates))
  113 + return outputDateFile
  114 +
  115 + def getImages(self, opath):
85 116  
86 117 file = open(self.fimages, "w")
87   - filedate = open(self.fdates, "w")
  118 + #filedate = open(self.fdates, "w")
  119 +
88 120 count = 0
89 121 imageList = []
90 122  
... ... @@ -100,10 +132,9 @@ class Sensor(object):
100 132 imageList.sort(key=lambda x: x[self.posDate])
101 133 #Write all the images in chronological order in a text file
102 134 for imSorted in imageList:
103   - date = imSorted[self.posDate].split("-")[0]
104   - filedate.write(date)
105   - #filedate.write(self.getDateFromName(imSorted))
106   - filedate.write('\n')
  135 + #date = imSorted[self.posDate].split("-")[0]
  136 + #filedate.write(date)
  137 + #filedate.write('\n')
107 138 s = "_"
108 139 nameIm = s.join(imSorted)
109 140 name = self.struct_path+nameIm#imSorted
... ... @@ -112,7 +143,7 @@ class Sensor(object):
112 143 file.write('\n')
113 144 fList.append(im)
114 145 count = count + 1
115   - filedate.close()
  146 + #filedate.close()
116 147 file.close()
117 148  
118 149 return fList
... ... @@ -131,7 +162,6 @@ class Sensor(object):
131 162  
132 163 #Organize the names by date
133 164 imageList.sort(key=lambda x: x[self.posDate])
134   - print imageList
135 165 #Write all the images in chronological order in a text file
136 166 for imSorted in imageList:
137 167 filedate.write(imSorted[self.posDate])
... ... @@ -161,9 +191,9 @@ class Sensor(object):
161 191 for imSorted in imageList:
162 192 s = "_"
163 193 nameIm = s.join(imSorted)
164   - print self.pathmask+nameIm
165 194 liste_Sort.append(glob.glob((self.pathmask+nameIm).replace("[","[[]"))[0])
166 195  
  196 +
167 197 return liste_Sort
168 198  
169 199 def getList_NoDataMask(self):
... ... @@ -183,8 +213,10 @@ class Sensor(object):
183 213 liste = self.sortMask(liste_sat)
184 214 return liste
185 215  
186   - def getList_DivMask(self):
187   - print "pathsearchmask",self.pathmask+"/*"+self.div
  216 +
  217 + def getList_DivMask(self, logger=logger):
  218 + logger = logging.getLogger(__name__)
  219 + logger.debug("Search path for masks: {}".format(self.pathmask+"/*"+self.div))
188 220 liste_div = glob.glob((self.pathmask+"/*"+self.div).replace("[","[[]"))
189 221 liste = self.sortMask(liste_div)
190 222 return liste
... ... @@ -204,7 +236,7 @@ class Sensor(object):
204 236 liste = self.sortMask(liste_div)
205 237 return liste
206 238  
207   - def GetBorderProp(self,mask):
  239 + def GetBorderProp(self, mask, logger=logger):
208 240 """
209 241 Calculates the proportion of valid pixels in a mask. Is used to calculate
210 242 the number of images to be used to build the mask
... ... @@ -228,7 +260,7 @@ class Sensor(object):
228 260  
229 261 return p
230 262  
231   - def CreateBorderMask_bindings(self,opath,imref,nbLook,wMode=False):
  263 + def CreateBorderMask_bindings(self, opath, imref, wMode=False):
232 264  
233 265 imlist = self.getImages(opath.opathT)
234 266  
... ... @@ -269,7 +301,8 @@ class Sensor(object):
269 301 expr = "+".join([ "(1-im"+str(i+1)+"b1)" for i in range(len(mlist))])
270 302  
271 303 listMask_s = indBinary
272   - if self.name == 'Sentinel2':listMask_s = mlist
  304 + if self.name == 'Sentinel2':
  305 + listMask_s = mlist
273 306 maskSum = otbAppli.CreateBandMathApplication({"il": listMask_s,
274 307 "exp": expr,
275 308 "pixType": 'uint8',
... ... @@ -283,124 +316,9 @@ class Sensor(object):
283 316 "exp": expr,
284 317 "pixType": 'uint8',
285 318 "out": self.borderMaskN})
286   - print "fin masque binaire"
287   - if (self.work_res == self.native_res):self.borderMask = self.borderMaskN
288   - return maskBin,indBinary,maskSum
289   -
290   - def CreateBorderMask(self,opath,imref,nbLook):
291   -
292   - imlist = self.getImages(opath.opathT)
293   -
294   - if self.nodata_MASK:
295   - mlist = self.getList_NoDataMask()
296   - else:
297   - mlist = self.getList_DivMask()
298   -
299   - ds = gdal.Open(imref, gdal.GA_ReadOnly)
300   - nb_col=ds.RasterXSize
301   - nb_lig=ds.RasterYSize
302   - proj=ds.GetProjection()
303   - gt=ds.GetGeoTransform()
304   - ulx = gt[0]
305   - uly = gt[3]
306   - lrx = gt[0] + nb_col*gt[1] + nb_lig*gt[2]
307   - lry = gt[3] + nb_col*gt[4] + nb_lig*gt[5]
308   - propBorder = []
309   -
310   - srs=osr.SpatialReference(proj)
311   - #chain_proj = srs.GetAuthorityName('PROJCS')+':'+srs.GetAuthorityCode('PROJCS')
312   - chain_proj = self.proj
313   - print "INFO ++++++++++++++++++++"
314   - print "imref "+imref
315   - print "proj "+str(proj)
316   - print "chain_proj "+str(proj)
317   - print "+++++++++++++++++++++++++"
318   - resolX = abs(gt[1]) # resolution en metres de l'image d'arrivee
319   - resolY = abs(gt[5]) # resolution en metres de l'image d'arrivee
320   - chain_extend = str(ulx)+' '+str(lry)+' '+str(lrx)+' '+str(uly)
321   -
322   - #Builds the individual binary masks
323   - listMaskch = ""
324   - listMask = []
325   - #Verification presence -10000 dans image
326   -
327   - #imlist.sort(key=lambda x: x[self.posDate])
328   -
329   - #mlist.sort()
330   -
331   - if otbVersion >= 5.0:
332   - if self.nodata_MASK:
333   - #expr = "\"im1b1==1?1:0\""
334   - expr = "\"(im1b1/2)==rint(im1b1/2)?0:1\""
335   - else:
336   - #expr = "\"im1b1==1?0:1\""
337   - expr = "\"(im1b1/2)==rint(im1b1/2)?1:0\""
338   - else:
339   - if self.nodata_MASK:
340   - expr = "\"if(im1b1,1,0)\""
341   - else:
342   - expr = "\"if(im1b1 and 00000001,0,1)\""
343   -
344   - if not self.name == 'Sentinel2':
345   - for i in range(len(mlist)):
346   - name = mlist[i].split("/")
347   - #print mlist[i]+" "+imlist[i]
348   - run("otbcli_BandMath -il "+mlist[i]\
349   - +" -out "+opath.opathT+"/"+name[-1]+" -exp "\
350   - +expr)
351   - listMaskch = listMaskch+opath.opathT+"/"+name[-1]+" "
352   - listMask.append(opath.opathT+"/"+name[-1])
353   -
354   - #Builds the complete binary mask
355   - if not self.name == 'Sentinel2':
356   - expr = "0"
357   - for i in range(len(mlist)):
358   - expr += "+im"+str(i+1)+"b1"
359   - else:
360   - #expr = "+".join([ "im"+str(i+1)+"b1" for i in range(len(mlist))])
361   - expr = "+".join([ "(1-im"+str(i+1)+"b1)" for i in range(len(mlist))])
362   -
363   - listMask_s = listMaskch
364   - if self.name == 'Sentinel2':
365   - listMask_s = " ".join(mlist)
366   - BuildMaskSum = 'otbcli_BandMath -il '+listMask_s+' -out '+self.sumMask+' -exp "'+expr+'"'
367   - print "BuildMaskSum"
368   - print BuildMaskSum
369   - run(BuildMaskSum)
370   -
371   - #Calculate how many bands will be used for building the common mask
372   - """
373   - for mask in listMask:
374   - p = self.GetBorderProp(mask)
375   - propBorder.append(p)
376   - sumMean = 0
377   - for value in propBorder:
378   - sumMean = sumMean+value
379   - meanMean = sumMean/len(propBorder)
380   - usebands = 0
381   - for value in propBorder:
382   - if value>=meanMean:
383   - usebands = usebands +1
384   - """
385   - usebands = nbLook
386   -
387   - if otbVersion >= 5.0:
388   - expr = "\"im1b1>=%s?1:0\""%(usebands)
389   - else:
390   - expr = "\"if(im1b1>="+str(usebands)+",1,0)\""
391   - BuildMaskBin = "otbcli_BandMath -il "+self.sumMask+" -out "+self.borderMaskN+" -exp "+expr
392   - print "Masque binaire ",BuildMaskBin
393   -
394   - run(BuildMaskBin)
395   -
396   - print "fin masque binaire"
397   - if (self.work_res == self.native_res) :
  319 + if (self.work_res == self.native_res):
398 320 self.borderMask = self.borderMaskN
399   - else:
400   -
401   - ResizeMaskBin = 'gdalwarp -of GTiff -r %s -tr %d %d -te %s -t_srs %s %s %s \n'% ('near', resolX,resolY,chain_extend,chain_proj, self.borderMaskN,self.borderMaskR)
402   - run(ResizeMaskBin)
403   - self.borderMask = self.borderMaskR
  321 + return maskBin,indBinary,maskSum
404 322  
405 323  
406 324 def ResizeImages(self, opath, imref):
... ... @@ -443,7 +361,6 @@ class Sensor(object):
443 361 imout = self.pathRes+"/"+name
444 362  
445 363 Resize = 'gdalwarp -of GTiff -r %s -tr %d %d -te %s -t_srs %s %s %s \n'% ('cubic', resolX,resolY,chain_extend,chain_proj, image, imout)
446   - print Resize
447 364 run(Resize)
448 365  
449 366 fileim.write(imout)
... ... @@ -515,13 +432,11 @@ class Sensor(object):
515 432 elif typeMask == 'DIV':
516 433 exp = expMask['DIV']
517 434 binary = "otbcli_BandMath -il "+mask+" -exp \""+exp+"\" -out "+imout
518   - print binary
519 435 run(binary)
520 436 Resize = 'gdalwarp -of GTiff -r %s -tr %d %d -te %s -t_srs %s %s %s \n'% ('near', resolX,resolY,chain_extend,chain_proj, imout, imoutr)
521   - print Resize
522 437 run(Resize)
523 438  
524   - def createMaskSeries_bindings(self, opath,wMode=False):
  439 + def createMaskSeries_bindings(self, opath, maskC, wMode=False, logger=logger):
525 440 """
526 441 Builds one multitemporal binary mask of SPOT images
527 442  
... ... @@ -532,8 +447,9 @@ class Sensor(object):
532 447 OUTPUT:
533 448 -Multitemporal binary mask .tif
534 449 """
535   - maskC = opath+"/MaskCommunSL.tif" # image ecrite par createcommonzone
536   - maskCshp = opath+"/MaskCommunSL.shp"
  450 +
  451 + logger.info("using common mask : " + maskC)
  452 +
537 453 imlist = self.getImages(opath)
538 454 clist = self.getList_CloudMask()
539 455 slist = self.getList_SatMask()
... ... @@ -547,90 +463,23 @@ class Sensor(object):
547 463 impath = imlist[im].split('/')
548 464 imname = impath[-1].split('.')
549 465 name = opath+'/'+imname[0]+'_MASK.TIF'
550   - chain = [maskC,clist[im],slist[im],dlist[im]]
551   - dateMask = otbAppli.CreateBandMathApplication({"il": chain,
  466 + #chain = [maskC,clist[im],slist[im],dlist[im]]
  467 + chain = " ".join([maskC,clist[im],slist[im],dlist[im]])
  468 + dateMask = otbAppli.CreateBandMathApplication({"il": [maskC,clist[im],slist[im],dlist[im]],
552 469 "exp": expr,
553 470 "pixType": 'uint8',
554 471 "out": name})
555 472 datesMasks.append(dateMask)
556   - if wMode : dateMask.ExecuteAndWriteOutput()
557   - else : dateMask.Execute()
  473 + if wMode:
  474 + dateMask.ExecuteAndWriteOutput()
  475 + else:
  476 + dateMask.Execute()
558 477 masksSeries = otbAppli.CreateConcatenateImagesApplication({"il" : datesMasks,
559 478 "pixType" : 'uint8',
560 479 "out" : self.serieTempMask})
561 480 return masksSeries,datesMasks
562 481  
563   - def createMaskSeries(self, opath):
564   - """
565   - Builds one multitemporal binary mask of SPOT images
566   -
567   - ARGs
568   - INPUT:
569   - -ipath: absolute path of the resized masks
570   - -opath: path were the multitemporal mask will be created
571   - OUTPUT:
572   - -Multitemporal binary mask .tif
573   - """
574   - if self.work_res == self.native_res:
575   - print "res native"
576   - imlist = self.getImages(opath)
577   - clist = self.getList_CloudMask()
578   - slist = self.getList_SatMask()
579   - dlist = self.getList_DivMask()
580   - else:
581   - imlist = self.getResizedImages(opath)
582   - clist = self.getList_ResCloudMask()
583   - slist = self.getList_ResSatMask()
584   - dlist = self.getList_ResDivMask()
585   - maskC = opath+"/MaskCommunSL.tif" # image ecrite par createcommonzone
586   - maskCshp = opath+"/MaskCommunSL.shp"
587   -
588   - #print clist
589   - #clist.sort(key=lambda x: x[self.posDate])
590   - #slist.sort(key=lambda x: x[self.posDate])
591   - #dlist.sort(key=lambda x: x[self.posDate])
592   - #print clist
593   - chain = ""
594   - allNames = ""
595   - listallNames = []
596   - bandclipped = []
597   - bandChain = ""
598   - if otbVersion >= 5.0:
599   - #expr = "\"im1b1 * ( im2b1>0?1:0 or im3b1>0?1:0 or im4b1>0?1:0)\""
600   - expr = "\" im1b1 * ( im2b1>0?1:0 or im3b1>0?1:0 or ((((im4b1/2)==rint(im4b1/2))?0:1))) \""
601   - if self.name == 'Sentinel2':
602   - #expr = "\" im1b1 * ( im2b1>0?1:0 or im3b1>0?1:0 or im4b1>0?0:1) \""#im1 = maskCommun, im2 = cloud, im3 = sat, im4 = div (bord)
603   - expr = "\" im1b1 * ( im2b1>0?1:0 or im3b1>0?1:0 or im4b1>0?1:0) \""
604   - else:
605   - expr = "\"im1b1 * (if(im2b1>0,1,0) or if(im3b1>0,1,0) or ((((im4b1/2)==rint(im4b1/2))?0:1))))\""
606   - print "imlist", imlist
607   - print len(imlist)
608   - print len(slist)
609   - print len(dlist)
610   - print len(clist)
611   - for im in range(0,len(imlist)):
612   - impath = imlist[im].split('/')
613   - imname = impath[-1].split('.')
614   - name = opath+'/'+imname[0]+'_MASK.TIF'
615   - chain = clist[im]+' '+slist[im]+' '+dlist[im]
616   - Binary = "otbcli_BandMath -il "+maskC+" "+chain+" -exp "+expr+" -out "+name+" uint16"
617   - print Binary
618   - run(Binary)
619   - #bandclipped.append(DP.ClipRasterToShp(name, maskCshp, opath))
620   - listallNames.append(name)
621   -
622   - #for bandclip in bandclipped:
623   - # bandChain = bandChain + bandclip + " "
624   - #Concatenate = "otbcli_ConcatenateImages -il "+bandChain+" -out "+self.serieTempMask+" "+pixelo
625   - bandChain = " ".join(listallNames)
626   - Concatenate = "otbcli_ConcatenateImages -il "+bandChain+" -out "+self.serieTempMask+" "+pixelo
627   - print Concatenate
628   - run(Concatenate)
629   -
630   -
631   - return 0
632   -
633   - def createSerie_bindings(self, opath):
  482 + def createSerie_bindings(self, opath, logger=logger):
634 483 """
635 484 Concatenation of all the images Landsat to create one multitemporal multibands image
636 485 ARGs
... ... @@ -640,80 +489,14 @@ class Sensor(object):
640 489 OUTPUT:
641 490 -Multitemporal, multiband serie
642 491 """
643   -
  492 + logger.info("temporal series generation : " + self.serieTemp)
644 493 imlist = self.getImages(opath)
  494 + sep = " "*47
  495 + logger.debug("temporal series generation using dates (chrono sorted): \n"+ sep + ("\n"+sep).join(imlist))
645 496 temporalSerie = otbAppli.CreateConcatenateImagesApplication({"il" : imlist,
646 497 "pixType" : 'int16',
647 498 "out" : self.serieTemp})
648   - return temporalSerie
649   -
650   -
651   - def createSerie(self, opath):
652   - """
653   - Concatenation of all the images Landsat to create one multitemporal multibands image
654