Commit b9c1a36e authored by Rashad Kanavath's avatar Rashad Kanavath

Merge remote-tracking branch 'origin/develop' into update_pkg

parents 509dbaee e7fbfb5a
......@@ -75,3 +75,8 @@ otb_create_application(
NAME MeanShiftSmoothing
SOURCES otbMeanShiftSmoothing.cxx
LINK_LIBRARIES ${${otb-module}_LIBRARIES})
otb_create_application(
NAME LargeScaleMeanShift
SOURCES otbLargeScaleMeanShift.cxx
LINK_LIBRARIES ${${otb-module}_LIBRARIES})
/*
* Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
*
* This file is part of Orfeo Toolbox
*
* https://www.orfeo-toolbox.org/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "otbWrapperCompositeApplication.h"
#include "otbWrapperApplicationFactory.h"
namespace otb
{
namespace Wrapper
{
/**
* \class LargeScaleMeanShift
*
* \brief All-in-one application for the LSMS framework
*
* This application gathers the 4 steps of the large-scale MeanShift
* segmentation framework.
*
*/
class LargeScaleMeanShift : public CompositeApplication
{
public:
/** Standard class typedefs. */
typedef LargeScaleMeanShift Self;
typedef CompositeApplication Superclass;
typedef itk::SmartPointer<Self> Pointer;
typedef itk::SmartPointer<const Self> ConstPointer;
/** Standard macro */
itkNewMacro(Self);
itkTypeMacro(LargeScaleMeanShift, otb::CompositeApplication);
private:
void DoInit() ITK_OVERRIDE
{
SetName("LargeScaleMeanShift");
SetDescription("Large-scale segmentation using MeanShift");
// Documentation
SetDocName("Large-Scale MeanShift");
SetDocLongDescription("This application chains together the 4 steps of the "
"MeanShit framework, that is the MeanShiftSmoothing [1], the "
"LSMSSegmentation [2], the LSMSSmallRegionsMerging [3] and the "
"LSMSVectorization [4].\n\n"
"This application can be a preliminary step for an object-based analysis.\n\n"
"It generates a vector data file containing the regions extracted with "
"the MeanShift algorithm. The spatial and range radius parameters allow "
"to adapt the sensitivity of the algorithm depending on the image dynamic "
"and resolution. There is a step to remove small regions whose size "
"(in pixels) is less than the given 'minsize' parameter. These regions "
"are merged to a similar neighbor region. In the output vectors, there "
"are additional fields to describe each region. In particular the mean "
"and standard deviation (for each band) is computed for each region "
"using the input image as support. If an optional 'imfield' image is "
"given, it will be used as support image instead."
);
SetDocLimitations("None");
SetDocAuthors("OTB-Team");
SetDocSeeAlso("[1] MeanShiftSmoothing\n"
"[2] LSMSSegmentation\n"
"[3] LSMSSmallRegionsMerging\n"
"[4] LSMSVectorization");
AddDocTag(Tags::Segmentation);
AddDocTag("LSMS");
ClearApplications();
AddApplication("MeanShiftSmoothing", "smoothing", "Smoothing step");
AddApplication("LSMSSegmentation", "segmentation", "Segmentation step");
AddApplication("LSMSSmallRegionsMerging", "merging", "Small region merging step");
AddApplication("LSMSVectorization", "vectorization", "Vectorization step");
ShareParameter("in","smoothing.in");
ShareParameter("spatialr","smoothing.spatialr");
ShareParameter("ranger","smoothing.ranger");
ShareParameter("minsize","merging.minsize");
ShareParameter("tilesizex","segmentation.tilesizex");
ShareParameter("tilesizey","segmentation.tilesizey");
AddParameter(ParameterType_Choice, "mode","Output mode");
SetParameterDescription("mode", "Type of segmented output");
AddChoice("mode.vector", "Segmentation as vector output");
SetParameterDescription("mode.vector","In this mode, the application will "
"produce a vector file or database and compute field values for each "
"region");
AddParameter(ParameterType_InputImage, "mode.vector.imfield", "Support image for field computation");
SetParameterDescription( "mode.vector.imfield", "This is an optional support image "
"that can be used to compute field values in each region. Otherwise, the "
"input image is used as support." );
MandatoryOff("mode.vector.imfield");
ShareParameter("mode.vector.out","vectorization.out");
AddChoice("mode.raster", "Standard segmentation with labeled raster output");
SetParameterDescription("mode.raster","In this mode, the application will produce a standard labeled raster.");
ShareParameter("mode.raster.out","merging.out",
"The output raster image",
"It corresponds to the output of the small region merging step.");
AddParameter( ParameterType_Empty, "cleanup", "Temporary files cleaning" );
EnableParameter( "cleanup" );
SetParameterDescription( "cleanup",
"If activated, the application will try to clean all temporary files it created" );
MandatoryOff( "cleanup" );
// Setup RAM
ShareParameter("ram","smoothing.ram");
Connect("merging.ram","smoothing.ram");
Connect("vectorization.ram","smoothing.ram");
Connect("merging.tilesizex","segmentation.tilesizex");
Connect("merging.tilesizey","segmentation.tilesizey");
Connect("vectorization.tilesizex","segmentation.tilesizex");
Connect("vectorization.tilesizey","segmentation.tilesizey");
// TODO : this is not exactly true, we used to choose the smoothed image instead
Connect("merging.in","smoothing.in");
// Setup constant parameters
GetInternalApplication("smoothing")->SetParameterString("foutpos","foo");
GetInternalApplication("smoothing")->EnableParameter("foutpos");
// Doc example parameter settings
SetDocExampleParameterValue("in", "QB_1_ortho.tif");
SetDocExampleParameterValue("spatialr", "4");
SetDocExampleParameterValue("ranger", "80");
SetDocExampleParameterValue("minsize", "16");
SetDocExampleParameterValue("mode.vector.out", "regions.shp");
SetOfficialDocLink();
}
void DoUpdateParameters() ITK_OVERRIDE
{}
void DoExecute() ITK_OVERRIDE
{
bool isVector(GetParameterString("mode") == "vector");
std::string outPath(isVector ?
GetParameterString("mode.vector.out"):
GetParameterString("mode.raster.out"));
std::vector<std::string> tmpFilenames;
tmpFilenames.push_back(outPath+std::string("_labelmap.tif"));
tmpFilenames.push_back(outPath+std::string("_labelmap.geom"));
ExecuteInternal("smoothing");
// in-memory connexion here (saves 1 additional update for foutpos)
GetInternalApplication("segmentation")->SetParameterInputImage("in",
GetInternalApplication("smoothing")->GetParameterOutputImage("fout"));
GetInternalApplication("segmentation")->SetParameterInputImage("inpos",
GetInternalApplication("smoothing")->GetParameterOutputImage("foutpos"));
// temporary file output here
GetInternalApplication("segmentation")->SetParameterString("out",
tmpFilenames[0]);
// take half of previous radii
GetInternalApplication("segmentation")->SetParameterFloat("spatialr",
0.5 * (double)GetInternalApplication("smoothing")->GetParameterInt("spatialr"));
GetInternalApplication("segmentation")->SetParameterFloat("ranger",
0.5 * GetInternalApplication("smoothing")->GetParameterFloat("ranger"));
GetInternalApplication("segmentation")->ExecuteAndWriteOutput();
GetInternalApplication("merging")->SetParameterString("inseg",
tmpFilenames[0]);
EnableParameter("mode.raster.out");
if (isVector)
{
tmpFilenames.push_back(outPath+std::string("_labelmap_merged.tif"));
tmpFilenames.push_back(outPath+std::string("_labelmap_merged.geom"));
GetInternalApplication("merging")->SetParameterString("out",
tmpFilenames[2]);
GetInternalApplication("merging")->ExecuteAndWriteOutput();
if (IsParameterEnabled("mode.vector.imfield") &&
HasValue("mode.vector.imfield"))
{
GetInternalApplication("vectorization")->SetParameterString("in",
GetParameterString("mode.vector.imfield"));
}
else
{
GetInternalApplication("vectorization")->SetParameterString("in",
GetParameterString("in"));
}
GetInternalApplication("vectorization")->SetParameterString("inseg",
tmpFilenames[2]);
ExecuteInternal("vectorization");
}
else
{
GetInternalApplication("merging")->ExecuteAndWriteOutput();
}
DisableParameter("mode.raster.out");
if( IsParameterEnabled( "cleanup" ) )
{
otbAppLogINFO( <<"Final clean-up ..." );
for (unsigned int i=0 ; i<tmpFilenames.size() ; ++i)
{
if(itksys::SystemTools::FileExists(tmpFilenames[i].c_str()))
{
itksys::SystemTools::RemoveFile(tmpFilenames[i].c_str());
}
}
}
}
};
} // end of namespace Wrapper
} // end of namespace otb
OTB_APPLICATION_EXPORT(otb::Wrapper::LargeScaleMeanShift)
......@@ -293,3 +293,18 @@ otb_test_application(NAME apTvSeHooverCompareSegmentationTest
--ignore-lines-with 2 outgt: outms:
)
#----------- LargeScaleMeanShift TESTS ----------------
otb_test_application(NAME apTvSeLargeScaleMeanShiftTest
APP LargeScaleMeanShift
OPTIONS -in ${EXAMPLEDATA}/QB_1_ortho.tif
-spatialr 3
-ranger 80
-minsize 16
-tilesizex 100
-tilesizey 100
-mode vector
-mode.vector.out ${TEMP}/apTvSeLargeScaleMeanShiftTestOut.shp
VALID --compare-ogr ${NOTOL}
${BASELINE_FILES}/apTvSeLargeScaleMeanShiftTestOut.shp
${TEMP}/apTvSeLargeScaleMeanShiftTestOut.shp
)
......@@ -32,7 +32,7 @@ namespace otb
* Add the capability to change the number of channel when operation on
* VectorImage compared to the itk::UnaryFunctorImageFilter
*
* The number of channel is provided by the functor: TFunction::OutputSize. If
* The number of channel is provided by the functor: TFunction::GetOutputSize. If
* this number is lower or equal to zero, the behavior of the itk::UnaryFunctorImageFilter
* remains unchanged.
*
......
......@@ -36,9 +36,9 @@ bool CMP(std::vector<float> a, std::vector<float> b)
return lexicographical_compare(a.begin(), a.begin() + 2, b.begin(), b.begin() + 2);
}
int otbImageToFastSIFTKeyPointSetFilterOutputInterestPointAscii(int itkNotUsed(argc), char * argv[])
int
otbImageToFastSIFTKeyPointSetFilterOutputInterestPointAscii( int itkNotUsed( argc ), char * argv[] )
{
const char * infname = argv[1];
const char * outfname = argv[2];
......@@ -59,7 +59,7 @@ int otbImageToFastSIFTKeyPointSetFilterOutputInterestPointAscii(int itkNotUsed(a
typedef PointSetType::PointDataContainer PointDataContainerType;
typedef PointDataContainerType::Iterator PointDataIteratorType;
typedef std::vector<float> siftDataVector;
typedef std::vector< RealType > siftDataVector;
typedef std::vector<siftDataVector> ImageDataType; //Kind of PointSet with vectors
// Instantiating object
......@@ -76,10 +76,29 @@ int otbImageToFastSIFTKeyPointSetFilterOutputInterestPointAscii(int itkNotUsed(a
PointsIteratorType pIt = filter->GetOutput()->GetPoints()->Begin();
PointDataIteratorType pDataIt = filter->GetOutput()->GetPointData()->Begin();
assert(
filter->GetOutput()->GetPoints()->Size() ==
filter->GetOutput()->GetPointData()->Size() );
std::ofstream outfile(outfname);
outfile << "Number of scales: " << scales << std::endl;
outfile << "Number of SIFT key points: " << filter->GetOutput()->GetNumberOfPoints() << std::endl;
outfile << "Number of SIFT key points: "
<< filter->GetOutput()->GetNumberOfPoints()
<< std::endl;
outfile << "Number of points: "
<< filter->GetOutput()->GetPoints()->Size()
<< std::endl;
outfile << "Number of points data: "
<< filter->GetOutput()->GetPointData()->Size()
<< std::endl;
if( filter->GetOutput()->GetPoints()->Size() !=
filter->GetOutput()->GetPointData()->Size() )
return EXIT_FAILURE;
// Copy the PointSet to std::vector< std::vector >
while (pIt != filter->GetOutput()->GetPoints()->End())
......
/*=========================================================================
Program: ORFEO Toolbox
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
See OTBCopyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#ifndef otbBinaryFunctorImageFilter_h
#define otbBinaryFunctorImageFilter_h
#include "itkBinaryFunctorImageFilter.h"
namespace otb
{
/**
* \class BinaryFunctorImageFilter
* \brief Implements pixel-wise generic operation on two images.
*
* Add the capability to change the number of channel when operation on
* VectorImage compared to the itk::BinaryFunctorImageFilter
*
* The number of channel is provided by the functor: TFunction::GetOutputSize. If
* this number is lower or equal to zero, the behavior of the itk::BinaryFunctorImageFilter
* remains unchanged.
*
* \sa itk::BinaryFunctorImageFilter
*
* \ingroup OTBImageManipulation
*/
template <class TInputImage1, class TInputImage2, class TOutputImage, class TFunction>
class ITK_EXPORT BinaryFunctorImageFilter : public itk::BinaryFunctorImageFilter<TInputImage1, TInputImage2, TOutputImage, TFunction>
{
public:
/** Standard class typedefs. */
typedef BinaryFunctorImageFilter Self;
typedef itk::BinaryFunctorImageFilter<TInputImage1, TInputImage2, TOutputImage, TFunction> Superclass;
typedef itk::SmartPointer<Self> Pointer;
typedef itk::SmartPointer<const Self> ConstPointer;
/** Method for creation through the object factory. */
itkNewMacro(Self);
/** Run-time type information (and related methods). */
itkTypeMacro(BinaryFunctorImageFilter, itk::BinaryFunctorImageFilter);
protected:
BinaryFunctorImageFilter() {};
~BinaryFunctorImageFilter() ITK_OVERRIDE {}
/** BinaryFunctorImageFilter can produce an image which has a different number of bands
* than its input image. As such, BinaryFunctorImageFilter
* needs to provide an implementation for
* GenerateOutputInformation() in order to inform the pipeline
* execution model. The original documentation of this method is
* below.
*
* \sa ProcessObject::GenerateOutputInformaton() */
void GenerateOutputInformation() ITK_OVERRIDE
{
Superclass::GenerateOutputInformation();
typename Superclass::OutputImagePointer outputPtr = this->GetOutput();
outputPtr->SetNumberOfComponentsPerPixel( // propagate vector length info
this->GetFunctor().GetOutputSize());
}
private:
BinaryFunctorImageFilter(const Self &); //purposely not implemented
void operator =(const Self&); //purposely not implemented
};
} // end namespace otb
#endif
/*=========================================================================
Program: ORFEO Toolbox
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
See OTBCopyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#ifndef otbTernaryFunctorImageFilter_h
#define otbTernaryFunctorImageFilter_h
#include "itkTernaryFunctorImageFilter.h"
namespace otb
{
/**
* \class TernaryFunctorImageFilter
* \brief Implements pixel-wise generic operation on three images.
*
* Add the capability to change the number of channel when operation on
* VectorImage compared to the itk::TernaryFunctorImageFilter
*
* The number of channel is provided by the functor: TFunction::GetOutputSize. If
* this number is lower or equal to zero, the behavior of the itk::TernaryFunctorImageFilter
* remains unchanged.
*
* \sa itk::TernaryFunctorImageFilter
*
* \ingroup OTBImageManipulation
*/
template <class TInputImage1, class TInputImage2, class TInputImage3, class TOutputImage, class TFunction>
class ITK_EXPORT TernaryFunctorImageFilter : public itk::TernaryFunctorImageFilter<TInputImage1, TInputImage2, TInputImage3, TOutputImage, TFunction>
{
public:
/** Standard class typedefs. */
typedef TernaryFunctorImageFilter Self;
typedef itk::TernaryFunctorImageFilter<TInputImage1, TInputImage2, TInputImage3, TOutputImage, TFunction> Superclass;
typedef itk::SmartPointer<Self> Pointer;
typedef itk::SmartPointer<const Self> ConstPointer;
/** Method for creation through the object factory. */
itkNewMacro(Self);
/** Run-time type information (and related methods). */
itkTypeMacro(TernaryFunctorImageFilter, itk::TernaryFunctorImageFilter);
protected:
TernaryFunctorImageFilter() {};
~TernaryFunctorImageFilter() ITK_OVERRIDE {}
/** TernaryFunctorImageFilter can produce an image which has a different number of bands
* than its input image. As such, TernaryFunctorImageFilter
* needs to provide an implementation for
* GenerateOutputInformation() in order to inform the pipeline
* execution model. The original documentation of this method is
* below.
*
* \sa ProcessObject::GenerateOutputInformaton() */
void GenerateOutputInformation() ITK_OVERRIDE
{
Superclass::GenerateOutputInformation();
typename Superclass::OutputImagePointer outputPtr = this->GetOutput();
outputPtr->SetNumberOfComponentsPerPixel( // propagate vector length info
this->GetFunctor().GetOutputSize());
}
private:
TernaryFunctorImageFilter(const Self &); //purposely not implemented
void operator =(const Self&); //purposely not implemented
};
} // end namespace otb
#endif
......@@ -167,7 +167,7 @@ public:
/* Get the internal application parameter specified
*
* WARNING: this method may disappear from the API */
const Parameter* GetParameterByKey(std::string parameter) const;
const Parameter* GetParameterByKey(std::string parameter, bool follow=true) const;
/* Returns the description of a parameter */
std::string GetParameterName(std::string paramKey);
......@@ -284,8 +284,21 @@ public:
void SetParameterEmpty(std::string parameter, bool value, bool hasUserValueFlag = true);
/** Checks if the application is ready to be executed. It checks that there
* is no parameter missing
*/
bool IsApplicationReady();
/** Checks if a parameter 'key' is missing.
*
* A parameter is missing when all the following conditions are true :
* - the parameter is mandatory
* - the parameter has Role_Input
* - the parameter is not a group
* - the parameter has no value
* - the parameter ancestors are mandatory or enabled.
*/
bool IsParameterMissing(const std::string &key) const;
/* Set an default integer value, must used in the
* DoInit when setting a value by default
......@@ -695,7 +708,10 @@ public:
*/
ComplexImagePixelType GetParameterComplexOutputImagePixelType(std::string parameter);
otb::Logger* GetLogger();
otb::Logger* GetLogger() const;
/** Sets the logger instance of the application (use with caution) */
void SetLogger(otb::Logger *logger);
itk::ProcessObject* GetProgressSource() const;
......
......@@ -149,10 +149,6 @@ private:
InternalAppContainer m_AppContainer;
itk::StdStreamLogOutput::Pointer m_LogOutput;
std::ostringstream m_Oss;
AddProcessCommandType::Pointer m_AddProcessCommand;
};
......
......@@ -36,6 +36,7 @@
#include "otbWrapperInputProcessXMLParameter.h"
#include "otbWrapperRAMParameter.h"
#include "otbWrapperProxyParameter.h"
#include "otbWrapperParameterKey.h"
#include "otbWrapperAddProcessToWatchEvent.h"
......@@ -74,11 +75,19 @@ Application::~Application()
{
}
otb::Logger* Application::GetLogger()
otb::Logger* Application::GetLogger() const
{
return m_Logger;
}
void Application::SetLogger(otb::Logger *logger)
{
if (m_Logger != logger)
{
m_Logger = logger;
}
}
std::vector<std::string>
Application::GetParametersKeys(bool recursive)
{
......@@ -297,11 +306,11 @@ void Application::SetParameterUserValue(std::string paramKey, bool value)
GetParameterByKey(paramKey)->SetUserValue(value);
}
const Parameter* Application::GetParameterByKey(std::string name) const
const Parameter* Application::GetParameterByKey(std::string name, bool follow) const
{
// GetParameterList is non const...
Application* _this = const_cast<Application*>(this);
return _this->GetParameterByKey(name);
return _this->GetParameterByKey(name,follow);
}
void Application::Init()
......@@ -1599,57 +1608,50 @@ Application::IsApplicationReady()
it != paramList.end();
++it)
{
// Check all Input Parameters with Input Role
if (GetParameterByKey(*it)->GetRole() == Role_Input)
// Check all parameters
if (IsParameterMissing(*it))
{
// When a parameter is mandatory :
// return false when does not have value and:
// - The param is root
// - The param is not root and belonging to a Mandatory Group
// which is activated
if ( !this->HasValue(*it) && IsMandatory(*it) )
{
if( GetParameterByKey(*it)->IsRoot() )
{
otbDebugMacro("MISSING : "<< (*it).c_str() << " ( Is Root)");
return false;
}
else
{
// check if the parameter is linked to a root parameter with a chain of active parameters
Parameter* currentParam = GetParameterByKey(*it)->GetRoot();
if (currentParam->IsRoot())
{
otbDebugMacro("MISSING : "<< (*it).c_str() << " ( Is Level 1)");
return false;
}
int level = 1;
while (!currentParam->IsRoot())
{
if (!currentParam->GetActive())
{
// the missing parameter is not on an active branch : we can ignore it
break;
}
currentParam = currentParam->GetRoot();
level++;
ready = false;
break;
}
}
return ready;
}
if (currentParam->IsRoot())
{
// the missing parameter is on an active branch : we need it
otbDebugMacro("MISSING : "<< (*it).c_str() << " ( Is Level "<< level<<")");
return false;
}
}
}
bool
Application::IsParameterMissing(const std::string &key) const
{
bool ret(false);
const Parameter* param = GetParameterByKey(key);
if (param->GetRole() == Role_Input &&
GetParameterType(key) != ParameterType_Group &&
param->GetMandatory() &&
!param->HasValue())
{
ret = true;
ParameterKey paramKey(key);
std::vector<std::string> split = paramKey.Split();
std::string currentRoot(key);
unsigned int level = 1;
while (level < split.size())
{
currentRoot.resize(currentRoot.find_last_of("."));
param = GetParameterByKey(currentRoot);
if (!param->GetActive() && !param->GetMandatory())
{
// the missing parameter is not on an active branch : we can ignore it
ret = false;
break;
}
level++;
}
if (ret)
{
// the missing parameter is on an active branch : we need it
otbDebugMacro("MISSING : "<< key << " (Level "<< split.size()<<")");
}
}
return ready;
return ret;
}
void
......
......@@ -44,7 +44,7 @@ ChoiceParameter::AddChoice( std::string choicekey, std::string choiceName )
choice.m_AssociatedParameter->SetName(choiceName);
choice.m_AssociatedParameter->SetRoot(this);
choice.m_AssociatedParameter->SetKey(choicekey);