Commit 85853d11 authored by Cédric Traizet's avatar Cédric Traizet
Browse files

ENH : code cleaning

parent 38fb2f95
......@@ -85,9 +85,8 @@ private:
SetName("SmallRegionsMerging");
SetDescription("This application performs the third (optional) step of the exact Large-Scale Mean-Shift segmentation workflow [1].");
SetDocName("Exact Large-Scale Mean-Shift segmentation, step 3 (optional)");
SetDocLongDescription("Given a segmentation result (can be the out output parameter of the"
" LSMSSegmentation application [2]) and the original image, it will"
SetDocName("Small Region Merging");
SetDocLongDescription("Given a segmentation result and the original image, it will"
" merge segments whose size in pixels is lower than minsize parameter"
" with the adjacent segments with the adjacent segment with closest"
" radiometry and acceptable size.\n\n"
......@@ -96,22 +95,11 @@ private:
" segments, then all segments of area equal to 2 pixels will be processed,"
" until segments of area minsize. For large images one can use the"
" tilesizex and tilesizey parameters for tile-wise processing, with the"
" guarantees of identical results.\n\n"
"The output of this application can be passed to the"
" LSMSVectorization application [3] to complete the LSMS workflow.");
SetDocLimitations("This application is part of the Large-Scale Mean-Shift segmentation"
" workflow (LSMS) and may not be suited for any other purpose. This"
" application is not compatible with in-memory connection since it does"
" its own internal streaming.");
SetDocAuthors("David Youssefi");
SetDocSeeAlso( "[1] Michel, J., Youssefi, D., & Grizonnet, M. (2015). Stable"
" mean-shift algorithm and its application to the segmentation of"
" arbitrarily large remote sensing images. IEEE Transactions on"
" Geoscience and Remote Sensing, 53(2), 952-964.\n"
"[2] LSMSegmentation\n"
"[3] LSMSVectorization");
" guarantees of identical results.\n\n");
SetDocLimitations("This application is more efficient if the labels are contiguous, starting from 0.");
SetDocAuthors("OTB-Team");
SetDocSeeAlso( "Segmentation");
AddDocTag(Tags::Segmentation);
AddDocTag("LSMS");
AddParameter(ParameterType_InputImage, "in", "Input image");
SetParameterDescription( "in", "The input image, containing initial spectral signatures corresponding to the segmented image (inseg)." );
......@@ -123,9 +111,9 @@ private:
SetDefaultOutputPixelType("out",ImagePixelType_uint32);
AddParameter(ParameterType_Int, "minsize", "Minimum Segment Size");
SetParameterDescription("minsize", "Minimum Segment Size. If, after the segmentation, a segment is of size lower than this criterion, the segment is merged with the segment that has the closest sepctral signature.");
SetParameterDescription("minsize", "Minimum Segment Size. If, after the segmentation, a segment is of size strictly lower than this criterion, the segment is merged with the segment that has the closest sepctral signature.");
SetDefaultParameterInt("minsize", 50);
SetMinimumParameterIntValue("minsize", 0);
SetMinimumParameterIntValue("minsize", 1);
MandatoryOff("minsize");
AddRAMParameter();
......@@ -135,8 +123,6 @@ private:
SetDocExampleParameterValue("inseg","segmentation.tif");
SetDocExampleParameterValue("out","merged.tif");
SetDocExampleParameterValue("minsize","20");
SetDocExampleParameterValue("tilesizex","256");
SetDocExampleParameterValue("tilesizey","256");
SetOfficialDocLink();
}
......@@ -163,52 +149,43 @@ private:
AddProcess(labelStatsFilter->GetStreamer() , "Computing stats on input image ...");
labelStatsFilter->Update();
// Merge small segments
auto regionMergingFilter = LabelImageSmallRegionMergingFilterType::New();
regionMergingFilter->SetInputLabelImage( labelIn );
regionMergingFilter->SetInputSpectralImage( imageIn );
// Convert Map to Vector
auto labelPopulationMap = labelStatsFilter->GetLabelPopulationMap();
std::vector<double> labelPopulation;
for (int i =0; i <= labelPopulationMap.rbegin()->first; i++)
for (unsigned int i =0; i <= labelPopulationMap.rbegin()->first; i++)
{
labelPopulation.push_back(labelPopulationMap[i]);
}
auto meanValueMap = labelStatsFilter->GetMeanValueMap();
std::vector<itk::VariableLengthVector<double> > meanValues;
for (int i =0; i <= meanValueMap.rbegin()->first; i++)
for (unsigned int i =0; i <= meanValueMap.rbegin()->first; i++)
{
meanValues.push_back(meanValueMap[i]);
}
//regionMergingFilter->SetLabelPopulation( labelStatsFilter->GetLabelPopulationMap() );
// Merge small segments
auto regionMergingFilter = LabelImageSmallRegionMergingFilterType::New();
regionMergingFilter->SetInputLabelImage( labelIn );
regionMergingFilter->SetLabelPopulation( labelPopulation );
regionMergingFilter->SetLabelStatistic( meanValues );
clock_t tic2 = clock();
for (unsigned int size = 1 ; size < minSize ; size++)
{
regionMergingFilter->SetSize( size );
regionMergingFilter->Update();
}
clock_t toc2 = clock();
std::cout <<"Elapsed timeaazaed : "<<(double)(toc2 - tic2) / CLOCKS_PER_SEC<<" seconds" << std::endl;
//Relabelling
auto changeLabelFilter = ChangeLabelImageFilterType::New();
changeLabelFilter->SetInput(labelIn);
auto correspondanceMap = regionMergingFilter->GetCorrespondanceMap();
/*for (auto correspondance : correspondanceMap)
{
if (correspondance.first != correspondance.second)
{
changeLabelFilter->SetChange(correspondance.first, correspondance.second);
}
}*/ //TODO
for(int i = 0; i<correspondanceMap.size(); ++i)
auto LUT = regionMergingFilter->GetLUT();
for(unsigned int i = 0; i<LUT.size(); ++i)
{
if(i!=correspondanceMap[i])
if(i!=LUT[i])
{
std::cout << i << " " << correspondanceMap[i] << std::endl;
changeLabelFilter->SetChange(i,correspondanceMap[i]);
std::cout << i << " " << LUT[i] << std::endl;
changeLabelFilter->SetChange(i,LUT[i]);
}
}
SetParameterOutputImage("out", changeLabelFilter->GetOutput());
......@@ -217,6 +194,7 @@ private:
otbAppLogINFO(<<"Elapsed time: "<<(double)(toc - tic) / CLOCKS_PER_SEC<<" seconds");
}
};
}
}
......
......@@ -21,19 +21,13 @@
#ifndef otbLabelImageSmallRegionMergingFilter_h
#define otbLabelImageSmallRegionMergingFilter_h
#include "otbImage.h"
#include "otbVectorImage.h"
#include "itkImageToImageFilter.h"
#include "otbPersistentImageFilter.h"
#include "otbPersistentFilterStreamingDecorator.h"
#include <set>
namespace otb
{
/** \class PersistentLabelImageSmallRegionMergingFilter
*
*
* This class merges regions in the input label image according to the input
* image of spectral values and the RangeBandwidth parameter.
......@@ -73,92 +67,64 @@ public:
typedef TInputLabelImage InputLabelImageType;
typedef typename InputLabelImageType::PixelType InputLabelType;
typedef TInputSpectralImage InputSpectralImageType;
typedef typename TInputSpectralImage::PixelType SpectralPixelType;
typedef itk::VariableLengthVector<double> RealVectorPixelType;
//typedef std::map<InputLabelType, double> LabelPopulationMapType;
typedef std::vector<double> LabelPopulationMapType;
typedef std::map<InputLabelType, std::set<InputLabelType> > NeigboursMapType;
//typedef std::map<InputLabelType, RealVectorPixelType > LabelStatisticMapType;
typedef std::vector<RealVectorPixelType > LabelStatisticMapType;
//typedef std::map<InputLabelType, InputLabelType> CorrespondanceMapType;
typedef std::vector<double> CorrespondanceMapType;
/** Sets the input image where the value of a pixel is the region id */
void SetInputLabelImage( const InputLabelImageType * labelImage);
/** Sets the input image representing spectral values */
void SetInputSpectralImage( const InputSpectralImageType * spectralImage);
/** Returns input label image */
InputLabelImageType * GetInputLabelImage();
/** Returns input spectral image */
InputSpectralImageType * GetInputSpectralImage();
typedef std::vector<RealVectorPixelType > LabelStatisticType;
typedef std::vector<double> LabelPopulationType;
typedef std::vector<InputLabelType> LUTType;
/** Set/Get size of polygon to be merged */
itkGetMacro(Size , unsigned int);
itkSetMacro(Size , unsigned int);
/** Set/Get the Label population map and initialize the correspondance map*/
/*void SetLabelPopulation( LabelPopulationMapType const & labelPopulation )
{
m_LabelPopulation = labelPopulation;
// Initialize m_CorrespondingMap to the identity (i.e. m[label] = label)
for (auto label : labelPopulation)
{
m_CorrespondanceMap[ label.first ] = label.first;
}
}
*/
void SetLabelPopulation( LabelPopulationMapType const & labelPopulation )
/** Set the Label population and initialize the LUT */
void SetLabelPopulation( LabelPopulationType const & labelPopulation )
{
m_LabelPopulation = labelPopulation;
// Initialize m_CorrespondingMap to the identity (i.e. m[label] = label)
m_CorrespondanceMap.resize( labelPopulation.size() );
for (int i =0; i <labelPopulation.size(); i++)
m_LUT.resize( labelPopulation.size() );
for (unsigned int i =0; i <labelPopulation.size(); i++)
{
m_CorrespondanceMap[ i ] = i;
m_LUT[ i ] = i;
}
}
LabelPopulationMapType const & GetLabelPopulation() const
/** Get the Label population */
LabelPopulationType const & GetLabelPopulation() const
{
return m_LabelPopulation;
}
void SetLabelStatistic( LabelStatisticMapType const & labelStatistic )
/** Set the label statistic */
void SetLabelStatistic( LabelStatisticType const & labelStatistic )
{
m_LabelStatistic = labelStatistic;
}
LabelStatisticMapType const & GetLabelStatistic() const
/** Get the label statistic */
LabelStatisticType const & GetLabelStatistic() const
{
return m_LabelStatistic;
}
CorrespondanceMapType const & GetCorrespondanceMap() const
/** Get the LUT */
LUTType const & GetLUT() const
{
return m_CorrespondanceMap;
return m_LUT;
}
virtual void Reset(void);
virtual void Synthetize(void);
protected:
//void EnlargeOutputRequestedRegion( itk::DataObject *output ) override;
void GenerateOutputInformation(void) override;
void ThreadedGenerateData(const RegionType&
outputRegionForThread, itk::ThreadIdType threadId) override;
// Use m_CorrespondanceMap recurively to find the label corresponding to the input label
// Use m_LUT recurively to find the label corresponding to the input label
InputLabelType FindCorrespondingLabel( InputLabelType label);
/** Constructor */
......@@ -175,15 +141,18 @@ private:
void operator =(const Self&) = delete;
unsigned int m_Size;
LabelPopulationMapType m_LabelPopulation;
LabelStatisticMapType m_LabelStatistic;
/** Vector containing at position i the population of the segment labelled i */
LabelPopulationType m_LabelPopulation;
/** Vector containing at position i the population of mean of element of the segment labelled i*/
LabelStatisticType m_LabelStatistic;
// Neigbours maps for each thread
/** Neigbours maps for each thread */
std::vector <NeigboursMapType > m_NeighboursMapsTmp;
CorrespondanceMapType m_CorrespondanceMap;
//NeigboursMapType m_NeighboursMap;
/** LUT giving correspondance between labels in the original segmentation and the merged labels */
LUTType m_LUT;
};
/** \class LabelImageSmallRegionMergingFilter
......@@ -218,75 +187,61 @@ public:
typedef PersistentLabelImageSmallRegionMergingFilter<TInputLabelImage, TInputSpectralImage> PersistentFilterType;
typedef typename PersistentFilterType::InputLabelImageType InputLabelImageType;
typedef typename PersistentFilterType::InputSpectralImageType InputSpectralImageType;
typedef typename PersistentFilterType::LabelPopulationMapType LabelPopulationMapType;
typedef typename PersistentFilterType::LabelStatisticMapType LabelStatisticMapType;
typedef typename PersistentFilterType::CorrespondanceMapType CorrespondanceMapType;
typedef typename PersistentFilterType::LabelPopulationType LabelPopulationType;
typedef typename PersistentFilterType::LabelStatisticType LabelStatisticType;
typedef typename PersistentFilterType::LUTType LUTType;
/** Sets the input image where the value of a pixel is the region id */
void SetInputLabelImage( const InputLabelImageType * labelImage)
{
this->GetFilter()->SetInputLabelImage( labelImage );
}
/** Sets the input image representing spectral values */
void SetInputSpectralImage( const InputSpectralImageType * spectralImage)
{
this->GetFilter()->SetInputSpectralImage( spectralImage );
this->GetFilter()->SetInput( labelImage );
}
/** Returns input label image */
InputLabelImageType * GetInputLabelImage()
{
return this->GetFilter()->GetInputLabelImage();
}
/** Returns input spectral image */
InputSpectralImageType * GetInputSpectralImage()
{
return this->GetFilter()->GetInputSpectralImage();
return this->GetFilter()->GetInput();
}
/** Set size of polygon to be merged */
/** Set size of segments to be merged */
void SetSize(unsigned int size)
{
this->GetFilter()->SetSize( size );
}
/** Get size of polygon to be merged */
/** Get size of segments to be merged */
unsigned int GetSize()
{
return this->GetFilter()->GetSize();
}
/** Set the Label population map */
void SetLabelPopulation( LabelPopulationMapType const & labelPopulation )
void SetLabelPopulation( LabelPopulationType const & labelPopulation )
{
this->GetFilter()->SetLabelPopulation( labelPopulation );
}
/** Get the Label population map */
LabelPopulationMapType const & GetLabelPopulation( ) const
LabelPopulationType const & GetLabelPopulation( ) const
{
return this->GetFilter()->GetLabelPopulation();
}
/** Set the Label statistic map */
void SetLabelStatistic( LabelStatisticMapType const & labelStatistic )
void SetLabelStatistic( LabelStatisticType const & labelStatistic )
{
this->GetFilter()->SetLabelStatistic( labelStatistic );
}
/** Get the Label statistic map */
LabelStatisticMapType const & GetLabelStatistic( ) const
LabelStatisticType const & GetLabelStatistic( ) const
{
return this->GetFilter()->GetLabelStatistic();
}
CorrespondanceMapType const & GetCorrespondanceMap() const
LUTType const & GetLUT() const
{
return this->GetFilter()->GetCorrespondanceMap();
return this->GetFilter()->GetLUT();
}
......
......@@ -36,45 +36,10 @@ PersistentLabelImageSmallRegionMergingFilter<TInputLabelImage, TInputSpectralIma
{
}
template <class TInputLabelImage, class TInputSpectralImage>
void
PersistentLabelImageSmallRegionMergingFilter<TInputLabelImage, TInputSpectralImage>
::SetInputLabelImage( const TInputLabelImage * labelImage)
{
// Process object is not const-correct so the const casting is required.
this->SetNthInput(0, const_cast<TInputLabelImage *>( labelImage ));
}
template <class TInputLabelImage, class TInputSpectralImage>
void
PersistentLabelImageSmallRegionMergingFilter<TInputLabelImage, TInputSpectralImage>
::SetInputSpectralImage( const TInputSpectralImage * spectralImage)
{
// Process object is not const-correct so the const casting is required.
this->SetNthInput(1, const_cast<TInputSpectralImage *>( spectralImage ));
}
template <class TInputLabelImage, class TInputSpectralImage>
TInputLabelImage *
PersistentLabelImageSmallRegionMergingFilter<TInputLabelImage, TInputSpectralImage>
::GetInputLabelImage()
{
return dynamic_cast<TInputLabelImage*>(itk::ProcessObject::GetInput(0));
}
template <class TInputLabelImage, class TInputSpectralImage>
TInputSpectralImage *
PersistentLabelImageSmallRegionMergingFilter<TInputLabelImage, TInputSpectralImage>
::GetInputSpectralImage()
{
return dynamic_cast<TInputSpectralImage*>(itk::ProcessObject::GetInput(1));
}
template <class TInputLabelImage, class TInputSpectralImage>
PersistentLabelImageSmallRegionMergingFilter<TInputLabelImage, TInputSpectralImage>
::~PersistentLabelImageSmallRegionMergingFilter()
{
}
......@@ -93,7 +58,6 @@ void
PersistentLabelImageSmallRegionMergingFilter<TInputLabelImage, TInputSpectralImage>
::Synthetize()
{
clock_t tic = clock();
NeigboursMapType neighboursMap;
// Merge the neighbours maps from all threads
for( unsigned int threadId = 0; threadId < this->GetNumberOfThreads(); threadId++)
......@@ -118,11 +82,10 @@ PersistentLabelImageSmallRegionMergingFilter<TInputLabelImage, TInputSpectralIma
auto statsNeighbour = m_LabelStatistic[ neighbour ];
assert( statsLabel.Size() == statsNeighbour.Size() );
double distance = 0;
for (int i = 0 ; i < statsLabel.Size(); i++)
for (unsigned int i = 0 ; i < statsLabel.Size(); i++)
{
distance += pow( statsLabel[i] - statsNeighbour[i] , 2);
}
//std::cout << label << " " << neighbour << " " << distance << " " << m_LabelStatistic[ neighbour ] <<std::endl;
if (distance < proximity)
{
proximity = distance;
......@@ -133,51 +96,40 @@ PersistentLabelImageSmallRegionMergingFilter<TInputLabelImage, TInputSpectralIma
auto curLabelLUT = label;
auto adjLabelLUT = closestNeighbour;
std::cout << label << " " << closestNeighbour;
while(m_CorrespondanceMap[curLabelLUT] != curLabelLUT)
while(m_LUT[curLabelLUT] != curLabelLUT)
{
curLabelLUT = m_CorrespondanceMap[curLabelLUT];
curLabelLUT = m_LUT[curLabelLUT];
}
while(m_CorrespondanceMap[adjLabelLUT] != adjLabelLUT)
while(m_LUT[adjLabelLUT] != adjLabelLUT)
{
adjLabelLUT = m_CorrespondanceMap[adjLabelLUT];
adjLabelLUT = m_LUT[adjLabelLUT];
}
if(curLabelLUT < adjLabelLUT)
{
m_CorrespondanceMap[adjLabelLUT] = curLabelLUT;
m_LUT[adjLabelLUT] = curLabelLUT;
}
else
{
m_CorrespondanceMap[m_CorrespondanceMap[curLabelLUT]] = adjLabelLUT;
m_CorrespondanceMap[curLabelLUT] = adjLabelLUT;
m_LUT[m_LUT[curLabelLUT]] = adjLabelLUT;
m_LUT[curLabelLUT] = adjLabelLUT;
}
//m_CorrespondanceMap[label] = closestNeighbour;
// Update Stats
/*m_LabelStatistic[closestNeighbour] = (m_LabelStatistic[closestNeighbour]*m_LabelPopulation[closestNeighbour] +
m_LabelStatistic[label]*m_LabelPopulation[label] ) / (m_LabelPopulation[label]+m_LabelPopulation[closestNeighbour]);
m_LabelPopulation[closestNeighbour] += m_LabelPopulation[label];*/
}
for(InputLabelType label = 0; label < m_CorrespondanceMap.size(); ++label)
for(InputLabelType label = 0; label < m_LUT.size(); ++label)
{
InputLabelType can = label;
while(m_CorrespondanceMap[can] != can)
while(m_LUT[can] != can)
{
can = m_CorrespondanceMap[can];
can = m_LUT[can];
}
m_CorrespondanceMap[label] = can;
m_LUT[label] = can;
}
for(InputLabelType label = 0; label < m_CorrespondanceMap.size(); ++label)
for(InputLabelType label = 0; label < m_LUT.size(); ++label)
{
InputLabelType correspondingLabel = m_CorrespondanceMap[label];
InputLabelType correspondingLabel = m_LUT[label];
if((m_LabelPopulation[label]!=0) && (correspondingLabel != label))
{
......@@ -188,16 +140,6 @@ PersistentLabelImageSmallRegionMergingFilter<TInputLabelImage, TInputSpectralIma
}
}
/*
// We have to update corresponding label to propagate the correspondance between the labels.
for (auto & corres : m_CorrespondanceMap)
{
corres = FindCorrespondingLabel(corres);
// corres.second = FindCorrespondingLabel(corres.second); //TODO
}*/
clock_t toc = clock();
std::cout << "Synthetize : " << (double)(toc - tic) / CLOCKS_PER_SEC << std::endl;
}
template <class TInputLabelImage, class TInputSpectralImage>
......@@ -206,11 +148,11 @@ PersistentLabelImageSmallRegionMergingFilter<TInputLabelImage, TInputSpectralIma
::FindCorrespondingLabel( typename PersistentLabelImageSmallRegionMergingFilter<TInputLabelImage, TInputSpectralImage>
::InputLabelType label)
{
auto correspondingLabel = m_CorrespondanceMap[label];
auto correspondingLabel = m_LUT[label];
while (label != correspondingLabel)
{
label = correspondingLabel;
correspondingLabel = m_CorrespondanceMap[correspondingLabel];
correspondingLabel = m_LUT[correspondingLabel];
}
return correspondingLabel;
}
......@@ -230,17 +172,13 @@ void
PersistentLabelImageSmallRegionMergingFilter<TInputLabelImage, TInputSpectralImage>
::ThreadedGenerateData(const RegionType& outputRegionForThread, itk::ThreadIdType threadId )
{
clock_t tic = clock();
using IteratorType = itk::ImageRegionConstIterator< TInputLabelImage >;
using NeighborhoodIteratorType = itk::ConstShapedNeighborhoodIterator< TInputLabelImage >;
typename NeighborhoodIteratorType::RadiusType radius;
radius.Fill(1);
auto labelImage = this->GetInputLabelImage();
auto labelImage = this->GetInput();
IteratorType it(labelImage, outputRegionForThread);
NeighborhoodIteratorType itN(radius, labelImage, outputRegionForThread);
......@@ -260,25 +198,16 @@ PersistentLabelImageSmallRegionMergingFilter<TInputLabelImage, TInputSpectralIma
assert( !itN.IsAtEnd() );
int currentLabel = FindCorrespondingLabel(it.Get());
//if ( it.Get() == m_Size )
if ( m_LabelPopulation[currentLabel] == m_Size )
{
for (auto ci = itN.Begin() ; !ci.IsAtEnd(); ci++)
{
//int neighbourLabel = ci.Get();
int neighbourLabel = FindCorrespondingLabel(ci.Get() );
//if (neighbourLabel != it.Get() && m_LabelPopulation[neighbourLabel] > m_Size)
if (neighbourLabel != currentLabel)
m_NeighboursMapsTmp[threadId][ currentLabel ].insert( neighbourLabel );
}
}
}
clock_t toc = clock();
if (threadId==0)
std::cout << threadId << " " << this->GetNumberOfThreads() << " Elapsed time : " << (double)(toc - tic) / CLOCKS_PER_SEC << std::endl;
}
template <class TInputLabelImage, class TInputSpectralImage>
......