Commit 98b8a9db authored by remi cresson's avatar remi cresson
Browse files

ENH: use the new StreamingStatisticsMapFromLabelImageFilter to compute stats

No related merge requests found
Showing with 68 additions and 165 deletions
+68 -165
...@@ -17,19 +17,11 @@ ...@@ -17,19 +17,11 @@
// Application engine // Application engine
#include "otbStandardFilterWatcher.h" #include "otbStandardFilterWatcher.h"
#include "itkFixedArray.h"
// Filter // Filters
#include "otbVectorDataToLabelImageFilter.h" #include "otbVectorDataToLabelImageFilter.h"
#include "otbVectorDataIntoImageProjectionFilter.h" #include "otbVectorDataIntoImageProjectionFilter.h"
#include "otbStreamingStatisticsMapFromLabelImageFilter.h"
// Vnl vector
#include "vnl/vnl_vector.h"
// itk iterator
#include "itkImageRegionConstIterator.h"
using namespace std;
namespace otb namespace otb
{ {
...@@ -48,8 +40,8 @@ public: ...@@ -48,8 +40,8 @@ public:
/* vector data filters */ /* vector data filters */
typedef size_t LabelValueType; typedef UInt32ImageType LabelImageType;
typedef otb::Image<LabelValueType, 2> LabelImageType; typedef LabelImageType::ValueType LabelValueType;
typedef otb::VectorData<double, 2> VectorDataType; typedef otb::VectorData<double, 2> VectorDataType;
typedef otb::VectorDataIntoImageProjectionFilter<VectorDataType, typedef otb::VectorDataIntoImageProjectionFilter<VectorDataType,
FloatVectorImageType> VectorDataReprojFilterType; FloatVectorImageType> VectorDataReprojFilterType;
...@@ -61,12 +53,8 @@ public: ...@@ -61,12 +53,8 @@ public:
typedef DataNodeType::PolygonListPointerType PolygonListPointerType; typedef DataNodeType::PolygonListPointerType PolygonListPointerType;
/** Statistics */ /** Statistics */
typedef vnl_matrix<double> RealMatrix; typedef otb::StreamingStatisticsMapFromLabelImageFilter<FloatVectorImageType,
typedef vnl_vector<LabelValueType> SizeVector; LabelImageType> StatsFilterType;
/** Image iterator */
typedef itk::ImageRegionConstIterator<LabelImageType> LabelIteratorType;
typedef itk::ImageRegionConstIterator<FloatVectorImageType> ImageIteratorType;
/** Standard macro */ /** Standard macro */
itkNewMacro(Self); itkNewMacro(Self);
...@@ -123,6 +111,15 @@ public: ...@@ -123,6 +111,15 @@ public:
return ss.str(); return ss.str();
} }
FloatVectorImageType::PixelType NullPixel(FloatVectorImageType::Pointer & img)
{
const unsigned int nBands = img->GetNumberOfComponentsPerPixel();
FloatVectorImageType::PixelType pix;
pix.SetSize(nBands);
pix.Fill(0);
return pix;
}
void DoExecute() void DoExecute()
{ {
...@@ -146,193 +143,98 @@ public: ...@@ -146,193 +143,98 @@ public:
m_VectorDataReprojectionFilter->SetInputImage(img); m_VectorDataReprojectionFilter->SetInputImage(img);
AddProcess(m_VectorDataReprojectionFilter, "Reproject vector data"); AddProcess(m_VectorDataReprojectionFilter, "Reproject vector data");
m_VectorDataReprojectionFilter->Update(); m_VectorDataReprojectionFilter->Update();
vdSrc = m_VectorDataReprojectionFilter->GetOutput(); m_VectorDataSrc = m_VectorDataReprojectionFilter->GetOutput();
} }
else else
{ {
vdSrc = shp; m_VectorDataSrc = shp;
} }
// Add a FID field // Internal no-data value
LabelValueType internalFID = 1; const LabelValueType intNoData = itk::NumericTraits<LabelValueType>::max();
const string internalFIDField = "__fid___";
vdWithFid = VectorDataType::New();
DataNodeType::Pointer root1 = vdWithFid->GetDataTree()->GetRoot()->Get();
DataNodeType::Pointer document1 = DataNodeType::New();
document1->SetNodeType(otb::DOCUMENT);
vdWithFid->GetDataTree()->Add(document1, root1);
DataNodeType::Pointer folder1 = DataNodeType::New();
folder1->SetNodeType(otb::FOLDER);
vdWithFid->GetDataTree()->Add(folder1, document1);
vdWithFid->SetProjectionRef(vdSrc->GetProjectionRef());
TreeIteratorType itVector1(vdSrc->GetDataTree());
itVector1.GoToBegin();
while (!itVector1.IsAtEnd())
{
if (!itVector1.Get()->IsRoot() && !itVector1.Get()->IsDocument() && !itVector1.Get()->IsFolder())
{
DataNodeType::Pointer currentGeometry = itVector1.Get();
currentGeometry->SetFieldAsInt(internalFIDField, internalFID );
vdWithFid->GetDataTree()->Add(currentGeometry, folder1);
internalFID++;
}
++itVector1;
} // next feature
// Rasterize vector data // Rasterize vector data
m_RasterizeFilter = RasterizeFilterType::New(); m_RasterizeFilter = RasterizeFilterType::New();
m_RasterizeFilter->AddVectorData(vdWithFid); m_RasterizeFilter->AddVectorData(m_VectorDataSrc);
m_RasterizeFilter->SetOutputOrigin(img->GetOrigin()); m_RasterizeFilter->SetOutputOrigin(img->GetOrigin());
m_RasterizeFilter->SetOutputSpacing(img->GetSignedSpacing()); m_RasterizeFilter->SetOutputSpacing(img->GetSignedSpacing());
m_RasterizeFilter->SetOutputSize(img->GetLargestPossibleRegion().GetSize()); m_RasterizeFilter->SetOutputSize(img->GetLargestPossibleRegion().GetSize());
m_RasterizeFilter->SetOutputProjectionRef(img->GetProjectionRef()); m_RasterizeFilter->SetOutputProjectionRef(img->GetProjectionRef());
m_RasterizeFilter->SetBurnAttribute(internalFIDField); m_RasterizeFilter->SetBurnAttribute("________");
m_RasterizeFilter->UpdateOutputInformation(); m_RasterizeFilter->SetDefaultBurnValue(0);
m_RasterizeFilter->SetGlobalWarningDisplay(false);
m_RasterizeFilter->SetBackgroundValue(intNoData);
// Computing stats // Computing stats
otbAppLogINFO("Computing stats"); m_StatsFilter = StatsFilterType::New();
m_StatsFilter->SetInput(img);
// Explicit streaming over the input target image, based on the RAM parameter m_StatsFilter->SetInputLabelImage(m_RasterizeFilter->GetOutput());
typedef otb::RAMDrivenStrippedStreamingManager<FloatVectorImageType> StreamingManagerType; m_StatsFilter->GetStreamer()->SetAutomaticAdaptativeStreaming(GetParameterInt("ram"));
StreamingManagerType::Pointer m_StreamingManager = StreamingManagerType::New(); AddProcess(m_StatsFilter->GetStreamer(), "Computing statistics");
m_StreamingManager->SetAvailableRAMInMB(GetParameterInt("ram")); m_StatsFilter->Update();
m_StreamingManager->PrepareStreaming(img, img->GetLargestPossibleRegion() );
// Remove the no-data entry
// Init. stats containers StatsFilterType::LabelPopulationMapType countMap = m_StatsFilter->GetLabelPopulationMap();
const LabelValueType N = internalFID; StatsFilterType::PixelValueMapType meanMap = m_StatsFilter->GetMeanValueMap();
const unsigned int nBands = img->GetNumberOfComponentsPerPixel(); StatsFilterType::PixelValueMapType stdMap = m_StatsFilter->GetStandardDeviationValueMap();
RealMatrix minimums(nBands, N, itk::NumericTraits<double>::max()); StatsFilterType::PixelValueMapType minMap = m_StatsFilter->GetMinValueMap();
RealMatrix maximums(nBands, N, itk::NumericTraits<double>::min()); StatsFilterType::PixelValueMapType maxMap = m_StatsFilter->GetMaxValueMap();
RealMatrix sum (nBands, N, 0); countMap.erase(intNoData);
RealMatrix sqSum (nBands, N, 0); meanMap.erase(intNoData);
RealMatrix means (nBands, N, 0); stdMap.erase(intNoData);
RealMatrix stdevs (nBands, N, 0); minMap.erase(intNoData);
SizeVector counts(N,0); maxMap.erase(intNoData);
if (m_RasterizeFilter->GetOutput()->GetLargestPossibleRegion().GetNumberOfPixels() != img->GetLargestPossibleRegion().GetNumberOfPixels())
{
otbAppLogFATAL("Rasterized image and input image don't have the same number of pixels");
}
int m_NumberOfDivisions = m_StreamingManager->GetNumberOfSplits();
for (int m_CurrentDivision = 0; m_CurrentDivision < m_NumberOfDivisions; m_CurrentDivision++)
{
FloatVectorImageType::RegionType streamRegion = m_StreamingManager->GetSplit(m_CurrentDivision);
img->SetRequestedRegion(streamRegion);
img->PropagateRequestedRegion();
img->UpdateOutputData();
m_RasterizeFilter->GetOutput()->SetRequestedRegion(streamRegion);
m_RasterizeFilter->GetOutput()->PropagateRequestedRegion();
m_RasterizeFilter->GetOutput()->UpdateOutputData();
LabelIteratorType it(m_RasterizeFilter->GetOutput(), streamRegion);
ImageIteratorType it_in(img, streamRegion);
for (it.GoToBegin(), it_in.GoToBegin(); !it.IsAtEnd(); ++it, ++it_in)
{
const LabelValueType fid = it.Get();
const FloatVectorImageType::PixelType pix = it_in.Get();
bool valid = true;
if (has_nodata)
{
for (unsigned int band = 0 ; band < nBands ; band++)
{
const FloatVectorImageType::InternalPixelType val = pix[band];
if (val == m_InputNoData)
{
valid = false;
break;
}
}
}
if (valid)
{
for (unsigned int band = 0 ; band < nBands ; band++)
{
const FloatVectorImageType::InternalPixelType val = pix[band];
if (val < minimums[band][fid])
minimums[band][fid] = val;
if (val > maximums[band][fid])
maximums[band][fid] = val;
sum[band][fid]+=val;
sqSum[band][fid]+=val*val;
} // next band
counts[fid]++;
}
} // next pixel
}
// Summarize stats
otbAppLogINFO("Summarizing stats");
for (LabelValueType fid = 0 ; fid < N ; fid++)
{
const LabelValueType count = counts[fid];
for (unsigned int band = 0 ; band < nBands ; band++)
{
if (count>0)
{
means[band][fid] = sum[band][fid] / static_cast<FloatVectorImageType::InternalPixelType>(count);
// Unbiased estimate
FloatVectorImageType::InternalPixelType variance = 0;
if (count > 1)
{
variance =
(sqSum[band][fid] - (sum[band][fid]*sum[band][fid] / static_cast<FloatVectorImageType::InternalPixelType>(count) ) ) /
(static_cast<FloatVectorImageType::InternalPixelType>(count) - 1);
if (variance > 0)
{
stdevs[band][fid] = vcl_sqrt(variance);
}
}
}
}
}
// Add a statistics fields // Add a statistics fields
otbAppLogINFO("Writing output vector data"); otbAppLogINFO("Writing output vector data");
internalFID = 1; LabelValueType internalFID = 0;
vdWithStats = VectorDataType::New(); m_NewVectorData = VectorDataType::New();
DataNodeType::Pointer root = vdWithStats->GetDataTree()->GetRoot()->Get(); DataNodeType::Pointer root = m_NewVectorData->GetDataTree()->GetRoot()->Get();
DataNodeType::Pointer document = DataNodeType::New(); DataNodeType::Pointer document = DataNodeType::New();
document->SetNodeType(otb::DOCUMENT); document->SetNodeType(otb::DOCUMENT);
vdWithStats->GetDataTree()->Add(document, root); m_NewVectorData->GetDataTree()->Add(document, root);
DataNodeType::Pointer folder = DataNodeType::New(); DataNodeType::Pointer folder = DataNodeType::New();
folder->SetNodeType(otb::FOLDER); folder->SetNodeType(otb::FOLDER);
vdWithStats->GetDataTree()->Add(folder, document); m_NewVectorData->GetDataTree()->Add(folder, document);
vdWithStats->SetProjectionRef(vdSrc->GetProjectionRef()); m_NewVectorData->SetProjectionRef(m_VectorDataSrc->GetProjectionRef());
TreeIteratorType itVector(vdSrc->GetDataTree()); TreeIteratorType itVector(m_VectorDataSrc->GetDataTree());
itVector.GoToBegin(); itVector.GoToBegin();
while (!itVector.IsAtEnd()) while (!itVector.IsAtEnd())
{ {
if (!itVector.Get()->IsRoot() && !itVector.Get()->IsDocument() && !itVector.Get()->IsFolder()) if (!itVector.Get()->IsRoot() && !itVector.Get()->IsDocument() && !itVector.Get()->IsFolder())
{ {
DataNodeType::Pointer currentGeometry = itVector.Get(); DataNodeType::Pointer currentGeometry = itVector.Get();
for (unsigned int band = 0 ; band < nBands ; band++)
// Add the geometry with the new fields
if (countMap.count(internalFID) > 0)
{ {
currentGeometry->SetFieldAsDouble(CreateFieldName("mean", band), means [band][internalFID] ); currentGeometry->SetFieldAsDouble("count", countMap[internalFID] );
currentGeometry->SetFieldAsDouble(CreateFieldName("stdev", band), stdevs [band][internalFID] ); for (unsigned int band = 0 ; band < img->GetNumberOfComponentsPerPixel() ; band++)
currentGeometry->SetFieldAsDouble(CreateFieldName("min", band), minimums[band][internalFID] ); {
currentGeometry->SetFieldAsDouble(CreateFieldName("max", band), maximums[band][internalFID] ); currentGeometry->SetFieldAsDouble(CreateFieldName("mean", band), meanMap[internalFID][band] );
currentGeometry->SetFieldAsDouble(CreateFieldName("stdev", band), stdMap [internalFID][band] );
currentGeometry->SetFieldAsDouble(CreateFieldName("min", band), minMap [internalFID][band] );
currentGeometry->SetFieldAsDouble(CreateFieldName("max", band), maxMap [internalFID][band] );
}
m_NewVectorData->GetDataTree()->Add(currentGeometry, folder);
} }
currentGeometry->SetFieldAsDouble("count", static_cast<double>(counts[internalFID]) );
vdWithStats->GetDataTree()->Add(currentGeometry, folder);
internalFID++; internalFID++;
} }
++itVector; ++itVector;
} // next feature } // next feature
SetParameterOutputVectorData("out", vdWithStats); SetParameterOutputVectorData("out", m_NewVectorData);
} }
VectorDataType::Pointer vdSrc; VectorDataType::Pointer m_VectorDataSrc;
VectorDataType::Pointer vdWithFid; VectorDataType::Pointer m_NewVectorData;
VectorDataType::Pointer vdWithStats;
VectorDataReprojFilterType::Pointer m_VectorDataReprojectionFilter; VectorDataReprojFilterType::Pointer m_VectorDataReprojectionFilter;
RasterizeFilterType::Pointer m_RasterizeFilter; RasterizeFilterType::Pointer m_RasterizeFilter;
StatsFilterType::Pointer m_StatsFilter;
}; };
} }
......
...@@ -7,6 +7,7 @@ otb_module(SimpleExtractionTools ...@@ -7,6 +7,7 @@ otb_module(SimpleExtractionTools
OTBConversion OTBConversion
OTBImageBase OTBImageBase
OTBImageIO OTBImageIO
OTBStatistics
TEST_DEPENDS TEST_DEPENDS
OTBTestKernel OTBTestKernel
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment