Skip to content
Snippets Groups Projects
Commit 1a8588c2 authored by Jordi Inglada's avatar Jordi Inglada
Browse files

Merge branch 'majority-voting-isolated-pixels' into develop

parents 9e365928 d2b8698a
No related branches found
No related tags found
No related merge requests found
......@@ -99,6 +99,13 @@ private:
SetParameterDescription("ip.undecidedlabel", "Label for the Undecided class. By default, 'ip.undecidedlabel = 0'.");
SetDefaultParameterInt("ip.undecidedlabel", 0.0);
AddParameter(ParameterType_Empty, "ip.onlyisolatedpixels", "Process isolated pixels only");
SetParameterDescription("ip.onlyisolatedpixels", "Only pixels whose label is unique in the neighbordhood will be processed. By default, 'ip.onlyisolatedpixels = false'.");
AddParameter(ParameterType_Int, "ip.isolatedthreshold", "Threshold for isolated pixels");
SetParameterDescription("ip.isolatedthreshold", "Maximum number of neighbours with the same label as the center pixel to consider that it is an isolated pixel. By default, 'ip.isolatedthreshold = 1'.");
SetDefaultParameterInt("ip.isolatedthreshold", 1);
AddRAMParameter();
......@@ -107,6 +114,7 @@ private:
SetDocExampleParameterValue("io.out", "clLabeledImageQB123_1_CMR_r2_nodl_10_undl_7.tif");
SetDocExampleParameterValue("ip.radius", "2");
SetDocExampleParameterValue("ip.suvbool", "true");
SetDocExampleParameterValue("ip.onlyisolatedpixels", "true");
SetDocExampleParameterValue("ip.nodatalabel", "10");
SetDocExampleParameterValue("ip.undecidedlabel", "7");
}
......@@ -149,6 +157,17 @@ private:
m_NeighMajVotingFilter->SetKeepOriginalLabelBool(true);
}
// Process isolated pixels only
if (IsParameterEnabled("ip.onlyisolatedpixels"))
{
m_NeighMajVotingFilter->SetOnlyIsolatedPixels(true);
m_NeighMajVotingFilter->SetIsolatedThreshold(GetParameterInt("ip.isolatedthreshold"));
}
else
{
m_NeighMajVotingFilter->SetOnlyIsolatedPixels(false);
}
/** REGULARIZATION OF CLASSIFICATION */
SetParameterOutputImage<IOLabelImageType>("io.out", m_NeighMajVotingFilter->GetOutput());
......
......@@ -149,6 +149,10 @@ public:
//Creates a SetKeepOriginalLabelBool method
itkSetMacro(KeepOriginalLabelBool, bool);
//Process only isolated pixels
itkSetMacro(OnlyIsolatedPixels, bool);
itkSetMacro(IsolatedThreshold, unsigned int);
protected:
NeighborhoodMajorityVotingImageFilter();
......@@ -166,6 +170,31 @@ protected:
void GenerateOutputInformation() ITK_OVERRIDE;
//Type to store the useful information from the label histogram
struct HistoSummary
{
unsigned int freqCenterLabel;
PixelType majorityLabel;
bool majorityUnique;
};
struct CompareHistoFequencies
{
typedef std::pair<PixelType, unsigned int> HistoValueType;
bool operator()(const HistoValueType& a, const HistoValueType& b)
{
return a.second > b.second;
}
};
//Get a histogram of frequencies of labels with the 2 highest
// frequencies sorted in decreasing order and return the frequency
// of the label of the center pixel
const HistoSummary ComputeNeighborhoodHistogramSummary(const NeighborhoodIteratorType &nit,
const KernelIteratorType kernelBegin,
const KernelIteratorType kernelEnd) const;
private:
NeighborhoodMajorityVotingImageFilter(const Self&); //purposely not implemented
void operator=(const Self&); //purposely not implemented
......@@ -177,6 +206,12 @@ private:
PixelType m_LabelForUndecidedPixels;
bool m_KeepOriginalLabelBool;
//Choose to filter only isolated pixels
bool m_OnlyIsolatedPixels;
//The center pixel is isolated if there are fewer neighbours than
//this threshold with the same label
unsigned int m_IsolatedThreshold;
}; // end of class
} // end namespace otb
......
......@@ -38,87 +38,93 @@ NeighborhoodMajorityVotingImageFilter<TInputImage, TOutputImage, TKernel>::Neigh
this->SetLabelForNoDataPixels(itk::NumericTraits<PixelType>::NonpositiveMin()); //m_LabelForNoDataPixels = 0
this->SetLabelForUndecidedPixels(itk::NumericTraits<PixelType>::NonpositiveMin()); //m_LabelForUndecidedPixels = 0
this->SetKeepOriginalLabelBool(true); //m_KeepOriginalLabelBool = true
this->SetOnlyIsolatedPixels(false); //process all pixels
this->SetIsolatedThreshold(1);
}
template<class TInputImage, class TOutputImage, class TKernel>
typename NeighborhoodMajorityVotingImageFilter<TInputImage, TOutputImage,
TKernel>::PixelType NeighborhoodMajorityVotingImageFilter<TInputImage,
TOutputImage, TKernel>::Evaluate(const NeighborhoodIteratorType &nit,
const KernelIteratorType kernelBegin,
const KernelIteratorType kernelEnd)
TKernel>::PixelType
NeighborhoodMajorityVotingImageFilter<TInputImage,
TOutputImage, TKernel>::Evaluate(const NeighborhoodIteratorType &nit,
const KernelIteratorType kernelBegin,
const KernelIteratorType kernelEnd)
{
PixelType majorityLabel = 0; //Value of the more representative pixels in the neighborhood
unsigned int majorityFreq = 0; //Number of pixels with the more representative value (majorityLabel) in the neighborhood
unsigned int i;
KernelIteratorType kernel_it;
std::map<PixelType, unsigned int> histoNeigh;
PixelType centerPixel = nit.GetCenterPixel();
if (centerPixel != m_LabelForNoDataPixels)
{
for (i = 0, kernel_it = kernelBegin; kernel_it < kernelEnd; ++kernel_it, ++i)
const PixelType centerPixel = nit.GetCenterPixel();
if (centerPixel == m_LabelForNoDataPixels)
{
// if structuring element is positive, use the pixel under that element
// in the image
PixelType label = nit.GetPixel(i);
if ((*kernel_it > itk::NumericTraits<KernelPixelType>::Zero) && (label != m_LabelForNoDataPixels))
return m_LabelForNoDataPixels;
}
else
{
//Get a histogram of label frequencies where the 2 highest are at the beginning and sorted
const HistoSummary histoSummary =
this->ComputeNeighborhoodHistogramSummary(nit, kernelBegin, kernelEnd);
if(m_OnlyIsolatedPixels &&
histoSummary.freqCenterLabel > m_IsolatedThreshold)
{
// note we use GetPixel() on the SmartNeighborhoodIterator to
// respect boundary conditions
//If the current label has already been added to the histogram histoNeigh
if (histoNeigh.count(label) > 0)
//If we want to filter only isolated pixels, keep the label if
//there are enough pixels with the center label to consider that
//it is not isolated
return centerPixel;
}
else
{
//If the majorityLabel is NOT unique in the neighborhood
if(!histoSummary.majorityUnique)
{
histoNeigh[label]++;
}
if (m_KeepOriginalLabelBool == true)
{
return centerPixel;
}
else
{
histoNeigh[label] = 1;
{
return m_LabelForUndecidedPixels;
}
}
//Extraction of the more representative Label in the neighborhood (majorityLabel)
return histoSummary.majorityLabel;
}
}
//Extraction of the more representative Label in the neighborhood (majorityLabel) and its Frequency (majorityFreq)
typename std::map<PixelType, unsigned int>::iterator histoIt;
for (histoIt = histoNeigh.begin(); histoIt != histoNeigh.end(); ++histoIt)
{
if (histoIt->second > majorityFreq)
{
majorityFreq = histoIt->second; //Frequency
majorityLabel = histoIt->first; //Label
}
}
}//END if (centerPixel != m_LabelForNoDataPixels)
}
//If the majorityLabel is NOT unique in the neighborhood
for (histoIt = histoNeigh.begin(); histoIt != histoNeigh.end(); ++histoIt)
template<class TInputImage, class TOutputImage, class TKernel>
const typename NeighborhoodMajorityVotingImageFilter<TInputImage, TOutputImage,
TKernel>::HistoSummary
NeighborhoodMajorityVotingImageFilter<TInputImage, TOutputImage,
TKernel>::ComputeNeighborhoodHistogramSummary(const NeighborhoodIteratorType &nit,
const KernelIteratorType kernelBegin,
const KernelIteratorType kernelEnd) const
{
typedef std::map<PixelType, unsigned int> HistogramType;
typedef std::vector<std::pair<PixelType, unsigned int> > HistoAsVectorType;
HistogramType histoNeigh;
unsigned int i = 0;
for (KernelIteratorType kernel_it = kernelBegin;
kernel_it < kernelEnd; ++kernel_it, ++i)
{
if ( (histoIt->second == majorityFreq) && (histoIt->first != majorityLabel) )
// if structuring element is positive, use the pixel under that element
// in the image
// note we use GetPixel() on the SmartNeighborhoodIterator to
// respect boundary conditions
const PixelType label = nit.GetPixel(i);
if ((*kernel_it > itk::NumericTraits<KernelPixelType>::Zero) &&
(label != m_LabelForNoDataPixels))
{
if (m_KeepOriginalLabelBool == true)
{
majorityLabel = centerPixel;
}
else
{
majorityLabel = m_LabelForUndecidedPixels;
}
break;
histoNeigh[label] += 1;
}
}
}//END if (centerPixel != m_LabelForNoDataPixels)
//If (centerPixel == m_LabelForNoDataPixels)
else
{
majorityLabel = m_LabelForNoDataPixels;
}
return majorityLabel;
HistoAsVectorType histoNeighVec(histoNeigh.begin(), histoNeigh.end());
//Sort the 2 max elements to the beginning
std::nth_element(histoNeighVec.begin(), histoNeighVec.begin()+1,
histoNeighVec.end(), CompareHistoFequencies());
typename NeighborhoodMajorityVotingImageFilter<TInputImage, TOutputImage,
TKernel>::HistoSummary result;
result.freqCenterLabel = histoNeigh[nit.GetCenterPixel()];
result.majorityLabel = histoNeighVec[0].first;
result.majorityUnique = (histoNeighVec[0].second != histoNeighVec[1].second);
return result;
}
template<class TInputImage, class TOutputImage, class TKernel>
......
......@@ -27,6 +27,11 @@ otb_add_test(NAME leTvNeighborhoodMajorityVotingImageFilterTest COMMAND otbMajor
5 #yRadius
10 #LabelForNoDataPixels
7 #LabelForUndecidedPixels
0 #OnlyIsolatedPixels
)
otb_add_test(NAME leTvNeighborhoodMajorityVotingIsolThresPixTest COMMAND otbMajorityVotingTestDriver
otbNeighborhoodMajorityVotingImageFilterIsolatedTest
)
otb_add_test(NAME leTvSVMImageClassificationFilterWithNeighborhoodMajorityVoting COMMAND otbMajorityVotingTestDriver
......
......@@ -3,4 +3,5 @@ void RegisterTests()
{
REGISTER_TEST(otbNeighborhoodMajorityVotingImageFilterNew);
REGISTER_TEST(otbNeighborhoodMajorityVotingImageFilterTest);
REGISTER_TEST(otbNeighborhoodMajorityVotingImageFilterIsolatedTest);
}
......@@ -100,6 +100,11 @@ int otbNeighborhoodMajorityVotingImageFilterTest(int argc, char* argv[])
seBall.CreateStructuringElement();
NeighMajVotingFilter->SetKernel(seBall);
if(argc==9)
{
NeighMajVotingFilter->SetOnlyIsolatedPixels(static_cast<bool>(atoi(argv[8])));
}
WriterType::Pointer writer = WriterType::New();
writer->SetFileName(outputFileName);
writer->SetInput(NeighMajVotingFilter->GetOutput());
......@@ -107,3 +112,96 @@ int otbNeighborhoodMajorityVotingImageFilterTest(int argc, char* argv[])
return EXIT_SUCCESS;
}
int otbNeighborhoodMajorityVotingImageFilterIsolatedTest(int itkNotUsed(argc), char* itkNotUsed(argv)[])
{
typedef unsigned char PixelType; // 8 bits
const unsigned int Dimension = 2;
typedef otb::Image<PixelType, Dimension> ImageType;
ImageType::Pointer image = ImageType::New();
ImageType::IndexType start;
start[0] = 0;
start[1] = 0;
ImageType::SizeType size;
size[0] = 100;
size[1] = 100;
ImageType::RegionType region;
region.SetSize(size);
region.SetIndex(start);
image->SetRegions(region);
image->Allocate();
image->FillBuffer(itk::NumericTraits<PixelType>::Zero);
// Neighborhood majority voting filter type
typedef otb::NeighborhoodMajorityVotingImageFilter<ImageType> NeighborhoodMajorityVotingFilterType;
// Binary ball Structuring Element type
typedef NeighborhoodMajorityVotingFilterType::KernelType StructuringType;
typedef StructuringType::RadiusType RadiusType;
// Neighborhood majority voting filter
NeighborhoodMajorityVotingFilterType::Pointer NeighMajVotingFilter;
NeighMajVotingFilter = NeighborhoodMajorityVotingFilterType::New();
NeighMajVotingFilter->SetInput(image);
StructuringType seBall;
RadiusType rad;
NeighMajVotingFilter->SetKeepOriginalLabelBool(true);
rad[0] = 1;
rad[1] = 1;
NeighMajVotingFilter->SetLabelForNoDataPixels(10);
NeighMajVotingFilter->SetLabelForUndecidedPixels(7);
seBall.SetRadius(rad);
seBall.CreateStructuringElement();
NeighMajVotingFilter->SetKernel(seBall);
NeighMajVotingFilter->SetOnlyIsolatedPixels(true);
PixelType value = 255;
ImageType::IndexType coordinate;
coordinate[0] = 10;
coordinate[1] = 10;
image->SetPixel(coordinate, value);
image->Update();
NeighMajVotingFilter->SetIsolatedThreshold(1);
NeighMajVotingFilter->Update();
PixelType result = NeighMajVotingFilter->GetOutput()->GetPixel(coordinate);
//Should be filtered
if(result == value)
{
std::cout << "one pixel\n";
return EXIT_FAILURE;
}
coordinate[0] = 10;
coordinate[1] = 11;
image->SetPixel(coordinate, value);
image->Update();
NeighMajVotingFilter->Modified(); //needed for the filter to be updated
NeighMajVotingFilter->Update();
result = NeighMajVotingFilter->GetOutput()->GetPixel(coordinate);
// Should not be filtered
if( result != value)
{
std::cout << "2 pixels thres = 1 result = " << int(result) << '\n';
return EXIT_FAILURE;
}
NeighMajVotingFilter->SetIsolatedThreshold(3);
NeighMajVotingFilter->Update();
result = NeighMajVotingFilter->GetOutput()->GetPixel(coordinate);
//Should be filtered
if(result == value)
{
std::cout << "2 pixels thres = 2" << '\n';
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment