Commit d1d6e2d1 authored by Manuel Grizonnet's avatar Manuel Grizonnet

Merge branch 'develop' into warnings_shadow_declaration

parents 12ad27b0 e80f1451
......@@ -37,9 +37,11 @@ List or link documentation modifications that were made (doxygen, example, Softw
The copyright owner is *COPYRIGHT OWNER (OR OWNER'S AGENT)* and has signed the ORFEO ToolBox Contributor License Agreement.
<hr>
***Check before merging:***
- All discussions are resolved
- At least 2 :thumbsup: votes from core developers, no :thumbsdown: vote.
- The feature branch is (reasonably) up-to-date with the base branch
- Dashboard is green
- Copyright owner has signed the ORFEO ToolBox Contributor License Agreement
\ No newline at end of file
- Copyright owner has signed the ORFEO ToolBox Contributor License Agreement
......@@ -156,16 +156,16 @@ if(NOT OTB_INSTALL_INCLUDE_DIR)
set(OTB_INSTALL_INCLUDE_DIR include/OTB-${OTB_VERSION_MAJOR}.${OTB_VERSION_MINOR})
endif()
if(NOT OTB_INSTALL_APP_DIR)
set(OTB_INSTALL_APP_DIR "lib/otb/applications")
set(OTB_INSTALL_APP_DIR "${OTB_INSTALL_LIBRARY_DIR}/otb/applications")
endif()
if(NOT OTB_INSTALL_PYTHON_DIR)
set(OTB_INSTALL_PYTHON_DIR "lib/otb/python")
set(OTB_INSTALL_PYTHON_DIR "${OTB_INSTALL_LIBRARY_DIR}/otb/python")
endif()
if(NOT OTB_INSTALL_PYTHON3_DIR)
set(OTB_INSTALL_PYTHON3_DIR "lib/otb/python3")
set(OTB_INSTALL_PYTHON3_DIR "${OTB_INSTALL_LIBRARY_DIR}/otb/python3")
endif()
if(NOT OTB_INSTALL_JAVA_DIR)
set(OTB_INSTALL_JAVA_DIR "lib/otb/java")
set(OTB_INSTALL_JAVA_DIR "${OTB_INSTALL_LIBRARY_DIR}/otb/java")
endif()
if(NOT OTB_INSTALL_DATA_DIR)
set(OTB_INSTALL_DATA_DIR "share/otb")
......
......@@ -25,7 +25,7 @@ Syntax: first elements
The default prefix name for variables related to the ith input is
*im(i+1)* (note the indexing from 1 to N, for N inputs). The user has
the possibility to change this default behaviour by setting its own
the possibility of changing this default behaviour by setting its own
prefix.
::
......@@ -90,7 +90,7 @@ represents a pixel of an image made of only one band:
.. math:: im1+1
A scalar can’t be added to a vector. The right formula is instead (one
can notice the way that muParserX allows to define vectors on the fly):
can notice the way that muParserX allows vectors to be defined on the fly):
.. math:: im1+\{ 1 \}
......@@ -205,8 +205,8 @@ ones. For instance:
.. math:: im1 ~ mlt ~ 2.0
Note that the operator ’\*’ could have been used instead of ’pw’ one.
But ’pw’ is a little bit more permisive, and can tolerate
one-dimensional vector as right element.
But ’pw’ is a little bit more permisive, and can tolerate a
one-dimensional vector as the right operand.
**Operators pow and pw** The first operator allows the definition of an
element-wise exponentiation of two vectors (and even matrices), provided
......
......@@ -4,10 +4,10 @@ Enhance local contrast
Principles
~~~~~~~~~~
Sensor images have often a wide dynamic range. Whereas it is helpful to have
high precision to do complex processing, it is pretty hard to display high
Sensor images often have a wide dynamic range. While it is helpful to have
high precision for complex processing, it is generally difficult to display high
dynamic images, even on modern screen as the dynamic range for basic screen is
of 8 bits while images can be encoded on 12 or 16 bits (or even more!).
of 8 bits while images can be encoded using 12 or 16 bits (or even more!).
.. _Figure1:
......@@ -41,24 +41,24 @@ You can apply this transformation with the *ContrastEnhancement* application:
-out output_image.tif
-spatial global
It allows to compress the dynamic without losing details and contrast.
It compresses the dynamic without losing details and contrast.
Advanced parameters
~~~~~~~~~~~~~~~~~~~
The *ContrastEnhancement* provides different options to configure the contrast
enhancement method. Let us see what there are for.
enhancement method. Let us see what they are for:
First what you want to equalize. Two modes are available:
* **luminance:** on 3 bands image, the equalization will be done on a single
* **luminance:** on 3 band images, the equalization will be done on a single
band which will be a composition of the original bands. The computed gain will
then be applied on the different bands. The classical use of this method is to
conserve ratio between the different color, conserve the hue.
* **channel:** each bands are equalized independently.
then be applied to the different bands. The classical use of this method is to
conserve the ratio between the different colors and conserve the hue.
* **channel:** each band is equalized independently.
The other option is the local equalization. You can choose a window size that
will be use to split the image in tiles and histograms will be computed over
will be used to split the image into tiles and histograms will be computed over
those tiles. Gain will be interpolated between the adjacent tiles in order to
give a smooth result.
......@@ -69,9 +69,9 @@ give a smooth result.
-spatial.local.w 500
-mode lum
The *ContrastEnhancement* application also offers a way to limit contrast by
adjusting original histogram with the **hfact** parameter. The limitation factor
represents the limit height that can have any bucket of the histogram; the
The *ContrastEnhancement* application also offers a way of limiting the contrast by
adjusting the original histogram with the **hfact** parameter. The limitation factor
represents the limit height that any bucket of the histogram can have; the
application computes the height of the flat histogram and the maximal height is
the limitation factor time this "flat height".
......@@ -80,7 +80,7 @@ the limitation factor time this "flat height".
|image4|
Finally, you can ignore a particular value with the **nodata** parameter, and
also set manually your minimum and maximum value. Any value out of bound will be
also manually set your minimum and maximum value. Any value out of bound will be
ignored.
......
......@@ -114,17 +114,17 @@ temporary file.
In-memory connection
--------------------
Applications are often use as parts of larger processing
workflow. Chaining applications currently requires to write/read back
Applications are often used as part of larger processing
workflows. Chaining applications currently requires to write/read back
images between applications, resulting in heavy I/O operations and a
significant amount of time dedicated to writing temporary files.
Since OTB 5.8, it is possible to connect an output image parameter
from one application to the input image parameter of the next
parameter. This results in the wiring of the internal ITK/OTB
pipelines together, allowing to perform image streaming between the
applications. There is therefore no more writing of temporary
images. The last application of the processing chain is responsible
pipelines together, permitting image streaming between the
applications. Consequently, this removes the need of writing temporary
images and improves performance. Only the last application of the processing chain is responsible
for writing the final result images.
In-memory connection between applications is available both at the C++
......@@ -180,8 +180,8 @@ Interactions with OTB pipeline
The application framework has been extended in order to provide ways to
interact with the pipelines inside each application. It applies only to
applications that use input or output images. Let's check what are the
functions added to the ``Application`` class. There are a lot of getter
applications that use input or output images. Let's check which
functions are available in the ``Application`` class. There are lots of getter
functions:
+---------------------------------+---------------------------------------+
......@@ -221,11 +221,11 @@ There is also a function to send orders to the pipeline:
can be used to measure the requested portion of input images necessary to produce
an extract of the full output.
Note: a requested region (like other regions in the C++ API of otb::Image) is
just a pair of an image index and a size, that define a rectangular extract of
Note: a requested region (like other regions in the C++ API of otb::Image) consists
of an image index and a size, which defines a rectangular extract of
the full image.
This set of function has been used to enhance the bridge between OTB images
This set of functions has been used to enhance the bridge between OTB images
and Numpy arrays. There are now import and export functions available in
Python that preserve the metadata of the image during conversions to Numpy
arrays:
......@@ -257,7 +257,7 @@ Now some basic Q&A about this interface:
A: The first one is here for Applications that expect a monoband otb::Image.
In most cases, you will use the second one: ImportVectorImage.
Q: What kind of object are there in this dictionary export?
Q: What kind of objects are there in this dictionary export?
A: The array is a numpy.ndarray. The other fields are wrapped
objects from the OTB library but you can interact with them in a
Python way: they support ``len()`` and ``str()`` operator, as well as
......@@ -265,7 +265,7 @@ Now some basic Q&A about this interface:
dictionaries.
This interface allows you to export OTB images (or extracts) to Numpy array,
process them by other means, and re-import them with preserved metadatas. Please
process them by other means, and re-import them with preserved metadata. Please
note that this is different from an in-memory connection.
Here is a small example of what can be done:
......@@ -368,9 +368,9 @@ arrays. For instance, when converting from OTB to NumPy array:
* The pixel buffer is copied into a ``numpy.array``
As you can see, there is no export of the metadata, such as origin, spacing,
geographic projection. It means that if you want to import back a NumPy array into OTB,
the image won't have any of these metadata. It can be a problem for applications
doing geometry, projections, and also calibration.
geographic projection. It means that if you want to re-import a NumPy array back into OTB,
the image won't have any of these metadata. This can pose problems for applications
that relate to geometry, projections, and also calibration.
Future developments will probably offer a more adapted structure to import and
export images between OTB and the Python world.
......
......@@ -4,20 +4,20 @@
\label{chapter:Installation}
\index{Installation}
There are two ways to install OTB library on your system: installing from a binary distribution or compiling from sources.
There are two ways to install OTB on your system: installing from a binary distribution or compiling from sources.
You can find information about the installation of binary packages for OTB and Monteverdi in the OTB-Cookbook.
This chapter covers compilation of OTB library from source. Note that it covers
also the compilation of Monteverdi which is integrated as an OTB module since
This chapter covers the compilation of OTB from source. Note that it also includes
the compilation of Monteverdi which is integrated as an OTB module since
version 5.8.
OTB has been developed and tested across different combinations of operating
systems, compilers, and hardware platforms including Windows, Linux and Mac OSX.
systems, compilers, and hardware platforms including Windows, GNU/Linux and macOS.
It is known to work with the following compilers in 32/64 bit:
\begin{itemize}
\item Visual Studio 2015 on Windows
\item GCC 4.x,5.x or CLang 3.x on GNU/Linux
\item AppleClang on Mac~OS~X (10.8 or higher)
\item AppleClang on macOS (10.8 or higher)
\end{itemize}
Since release version 6.2.0, OTB is compiled using the C++14 standard by default.
......@@ -29,13 +29,13 @@ configuration files. CMake generates native makefiles and workspaces that can b
your choice. CMake is quite sophisticated: it supports complex environments requiring system configuration, compiler
feature testing, and code generation.
CMake supports several generators to produce the compilation scripts, dependending on the platform and compiler. It can use :
CMake supports several generators to produce the compilation scripts, dependending on the platform and compiler. It can use:
\begin{itemize}
\item Makefiles for Unix systems
\item Visual Studio workspaces for Windows
\item NMake Makefiles for Windows
\item Ninja scripts
\item and many more ...
\item and many more...
\end{itemize}
The information used by CMake is provided by \code{CMakeLists.txt} files that
are present in every directory of the OTB source tree. These files contain information that the user provides to CMake
......@@ -54,7 +54,7 @@ configuration. This is the easiest way to start.
\end{itemize}
As shown in figure \ref{fig:CMakeGUI}, CMake has a different interfaces according to your system.
Refer to section~\ref{sec:compiling-linux} for Linux and Mac~OS~X build instructions
Refer to section~\ref{sec:compiling-linux} for GNU/Linux and macOS build instructions
and \ref{sec:compiling-windows} for Windows.
\begin{figure}[tpb]
......@@ -144,7 +144,7 @@ See table \ref{tab:otb-dependencies} for the full list of dependencies.
\end{tiny}
\end{center}
\section{Linux and Mac OS X}
\section{GNU/Linux and macOS}
\label{sec:compiling-linux}
\subsection{Setting up the build environment}
......@@ -293,20 +293,20 @@ want to build) :
\url{https://www.orfeo-toolbox.org/packages}
\end{center}
Qt library: Unlike other dependencies building Qt5 on all platform is not trivial task but
OTB SuperBuild makes best effort to make it easier for you. So there is still
Qt library: Unlike other dependencies, building Qt5 on all platforms is not a trivial task but
OTB SuperBuild does its level best to facilitate this for the user. So there is still
some additional package installation, one has to do as a pre-requistie for SuperBuild
On a GNU/Linux you must have Qt X11 dependencies installed.
See Qt 5 documentation for list of packages that needs to be installed
See Qt 5 documentation for the list of packages that need to be installed
before starting superbuild. https://doc.qt.io/qt-5/linux-requirements.html.
For a Debian 8.1 system, I installed all Qt5 dependencies with below 'apt-get install'
For a Debian 8.1 system, all Qt5 dependencies can be installed with the following 'apt-get install' command:
\texttt{apt-get install libx11-dev libxext-dev libxt-dev libxi-dev libxrandr-dev
libgl-dev libglu-dev libxinerama-dev libxcursor-dev}
You can also deactivate QT5 and skip this by passing \texttt{-DOTB\_USE\_QT=OFF} to cmake.
This will give you OTB install without monteverdi, mapla and gui application launchers.
You can also deactivate Qt5 and skip this by passing \texttt{-DOTB\_USE\_QT=OFF} to cmake, but
this will install OTB without Monteverdi, Mapla and the GUI application launchers.
For Mac OSX you need to install XCode and Windows 7,8.1,10 requires MSVC 2015 or higher.
For macOS you need to install XCode and Windows 7,8.1,10 requires MSVC 2015 or higher.
You are now ready to compile OTB!
Simply use the make command (other targets can be generated with CMake's \texttt{-G} option):
......@@ -328,19 +328,20 @@ while:
\end{verbatim}
will launch the graphical version.
To be able to use your OTB build from everywhere, we recommend the following.
First, add \texttt{bin/} directory to your PATH for easy access:
In order to ensure access to your OTB build from anywhere within your system, we recommend setting the following
environment variables.
Firstly, add \texttt{bin/} directory to your PATH for easy access:
\begin{verbatim}
export PATH=$PATH:~/OTB/install/bin
\end{verbatim}
Second, add the \texttt{lib/} directory to your LD\_LIBRARY\_PATH:
Secondly, add the \texttt{lib/} directory to your LD\_LIBRARY\_PATH:
\begin{verbatim}
export LD_LIBRARY_PATH=~/OTB/install/lib:$LD_LIBRARY_PATH
\end{verbatim}
Monteverdi is integrated as an OTB module since release 5.8 and it is compiled
by the SuperBuild (as long as GLEW, GLUT, OPENGL, Qt and QWT modules are
by the SuperBuild (provided that GLEW, GLUT, OPENGL, Qt and QWT modules are
activated).
To use OTB applications from within Monteverdi you will need to define the
......@@ -377,8 +378,8 @@ off the CMake variable OTB\_BUILD\_DEFAULT\_MODULES, configure, and then switch
off each \texttt{Module\_module\_name} variable. To provide an overview on how
things work, the option \texttt{COMPONENTS} of the CMake command find\_package
is used in order to only load the requested modules. This module-specific list
prevent CMake from performing a blind search; it is also a convienent way to
monitor the dependencies of each module.
prevents CMake from performing a blind search; it is also a convienent way of
monitoring the dependencies of each module.
\begin{verbatim}
find_package(OTB COMPONENTS OTBCommon OTBTransform [...])
\end{verbatim}
......@@ -454,30 +455,5 @@ Everything that is needed for OTB development on Windows, including compiling fr
\section{Known issues}
\label{sec:knownissues}
\begin{itemize}
\item openjpeg/ITK
\end{itemize}
It is important to know that the OpenJpeg library doesn't support name mangling since version 2.0.
As a consequence, if other libraries linked by your project already contain OpenJpeg, there may be a symbol conflict at run-time.
For instance, this was observed with OTB build on a recent ITK version (ver. 4).
The ITK library already had a version of OpenJpeg in libitkopenjpeg-*.so, which contained the OpenJpeg symbols un-wrapped.
These symbols were also loaded by the GDAL driver but only the first ones were used, which caused a crash.
Hopefully, thanks to the modular architecture of ITK, the library libitkopenjpeg-*.so is not imported anymore inside OTB.
However the OpenJPEG headers may be present in ITK include directory. As the current architecture doesn't allow to tune
include order between modules, the OpenJPEG header from ITK can be included before your own OpenJPEG install. There are
two ways to avoid this situation :
\begin{itemize}
\item Use an ITK without GDCM nor ITKReview (only these modules depend on OpenJPEG)
\item Hide the header openjpeg.h in the ITK include directory.
\end{itemize}
More information can be found here : \url{http://wiki.orfeo-toolbox.org/index.php/JPEG2000_with_GDAL_OpenJpeg_plugin}
\begin{itemize}
\item libkml / Ubuntu 12.04
\end{itemize}
Another issue is related to the official package of libkml under Ubuntu 12.04.
Users of this plateform should disable the option OTB\_USE\_KML, so that OTB won't be built with this third-party.
Please check \url{https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb/issues} with
an updated list of known issues (tag bug).
......@@ -52,8 +52,9 @@ public:
"validation sets per class and per image.\n Several classifier parameters can be set depending on the chosen classifier. In the "
"validation process, the confusion matrix is organized the following way: rows = reference labels, columns = produced labels. "
"In the header of the optional confusion matrix output file, the validation (reference) and predicted (produced) class labels"
" are ordered according to the rows/columns of the confusion matrix.\n This application is based on LibSVM and OpenCV Machine Learning "
"(2.3.1 and later)." );
" are ordered according to the rows/columns of the confusion matrix.\n This application is based on LibSVM, OpenCV Machine Learning "
"(2.3.1 and later), and Shark ML. The output of this application is a text model file, whose format corresponds to the "
"ML model type chosen. There is no image nor vector data output." );
SetDocLimitations( "None" );
SetDocAuthors( "OTB-Team" );
SetDocSeeAlso( "OpenCV documentation for machine learning http://docs.opencv.org/modules/ml/doc/ml.html " );
......
......@@ -63,7 +63,10 @@ protected:
SetDocName( "Train Vector Classifier" );
SetDocLongDescription( "This application trains a classifier based on "
"labeled geometries and a list of features to consider for "
"classification." );
"classification.\nThis application is based on LibSVM, OpenCV Machine "
"Learning (2.3.1 and later), and Shark ML The output of this application "
"is a text model file, whose format corresponds to the ML model type "
"chosen. There is no image nor vector data output.");
SetDocLimitations( " " );
SetDocAuthors( "OTB Team" );
SetDocSeeAlso( " " );
......
......@@ -138,7 +138,7 @@ LearningApplicationBase<TInputValue,TOutputValue>
RGBAPixelConverter<int,int>::Pointer dummyFilter =
RGBAPixelConverter<int,int>::New();
dummyFilter->SetProgress(0.0f);
this->AddProcess(dummyFilter,"Classify...");
this->AddProcess(dummyFilter,"Validation...");
dummyFilter->InvokeEvent(itk::StartEvent());
// load a machine learning model from file and predict the input sample list
......@@ -169,6 +169,7 @@ LearningApplicationBase<TInputValue,TOutputValue>
typename TargetListSampleType::Pointer trainingLabeledListSample,
std::string modelPath)
{
otbAppLogINFO("Computing model file : "<<modelPath);
// Setup fake reporter
RGBAPixelConverter<int,int>::Pointer dummyFilter =
RGBAPixelConverter<int,int>::New();
......
......@@ -129,7 +129,7 @@ namespace otb
{ \
std::ostringstream message; \
message << "otb::ERROR Unknown error while running " << # command << " (catch(...) )"; \
::itk::ExceptionObject e_(__FILE__, __LINE__, message.str().c_str(), ITK_LOCATION); \
::itk::ExceptionObject e_(__FILE__, __LINE__, message.str(), ITK_LOCATION); \
throw e_; \
} \
std::cout << " Checking valid command " << # command " ok." << std::endl; \
......@@ -160,14 +160,14 @@ namespace otb
{ \
std::ostringstream message; \
message << "otb::ERROR Unknown error while running " << # command << " (catch(...) )"; \
::itk::ExceptionObject e_(__FILE__, __LINE__, message.str().c_str(), ITK_LOCATION); \
::itk::ExceptionObject e_(__FILE__, __LINE__, message.str(), ITK_LOCATION); \
throw e_; \
} \
if (result == 1) \
{ \
std::ostringstream message; \
message << "otb::ERROR: " << # command << " should be throwing an exception."; \
::itk::ExceptionObject e_(__FILE__, __LINE__, message.str().c_str(), ITK_LOCATION); \
::itk::ExceptionObject e_(__FILE__, __LINE__, message.str(), ITK_LOCATION); \
throw e_; \
} \
}
......
......@@ -140,7 +140,7 @@ ObjectListToObjectListFilter<TInputList, TOutputList>
std::ostringstream message;
message << "itk::ERROR: " << this->GetNameOfClass()
<< "(" << this << "): " << "Subclass should override this method!!!";
itk::ExceptionObject e_(__FILE__, __LINE__, message.str().c_str(), ITK_LOCATION);
itk::ExceptionObject e_(__FILE__, __LINE__, message.str(), ITK_LOCATION);
throw e_;
}
......
......@@ -265,7 +265,7 @@ ImageToPointSetFilter<TInputImage, TOutputPointSet>
std::ostringstream message;
message << "itk::ERROR: " << this->GetNameOfClass()
<< "(" << this << "): " << "Subclass should override this method!!!";
itk::ExceptionObject e_(__FILE__, __LINE__, message.str().c_str(), ITK_LOCATION);
itk::ExceptionObject e_(__FILE__, __LINE__, message.str(), ITK_LOCATION);
throw e_;
}
......
......@@ -54,36 +54,42 @@ class StatisticsAccumulator
{
public:
typedef typename TRealVectorPixelType::ValueType RealValueType;
typedef typename TRealVectorPixelType::ValueType RealValueType;
typedef uint64_t PixelCountType;
typedef itk::VariableLengthVector<PixelCountType> PixelCountVectorType;
// Constructor (default)
StatisticsAccumulator(){}
StatisticsAccumulator() : m_Count(), m_NoDataValue(), m_UseNoDataValue() {}
// Constructor (initialize the accumulator with the given pixel)
StatisticsAccumulator(const TRealVectorPixelType & pixel)
StatisticsAccumulator(RealValueType noDataValue,
bool useNoDataValue,
const TRealVectorPixelType & pixel)
: m_NoDataValue(noDataValue),
m_Count(1),
m_UseNoDataValue(useNoDataValue)
{
m_Count = 1;
m_Sum = pixel;
m_Min = pixel;
m_Max = pixel;
m_SqSum = pixel;
m_BandCount.SetSize(pixel.GetSize());
for (unsigned int band = 0 ; band < m_SqSum.GetSize() ; band++)
m_SqSum[band] *= m_SqSum[band];
}
// Constructor (other)
StatisticsAccumulator(const StatisticsAccumulator & other)
{
m_Count = other.m_Count;
m_Sum = other.m_Sum;
m_Min = other.m_Min;
m_Max = other.m_Max;
m_SqSum = other.m_SqSum;
{
auto val = pixel[band];
if (!m_UseNoDataValue || val != m_NoDataValue)
{
m_BandCount[band] = 1;
m_SqSum[band] *= m_SqSum[band];
}
else
{
m_BandCount[band] = 0;
}
}
}
// Destructor
~StatisticsAccumulator(){}
// Function update (pixel)
void Update(const TRealVectorPixelType & pixel)
{
......@@ -93,8 +99,13 @@ public:
{
const RealValueType value = pixel[band];
const RealValueType sqValue = value * value;
UpdateValues(value, sqValue, value, value,
m_Sum[band], m_SqSum[band], m_Min[band], m_Max[band]);
UpdateValues(!m_UseNoDataValue || value != m_NoDataValue,
value, sqValue,
value, value,
m_BandCount[band],
m_Sum[band], m_SqSum[band],
m_Min[band], m_Max[band]);
}
}
......@@ -105,12 +116,17 @@ public:
const unsigned int nBands = other.m_Sum.GetSize();
for (unsigned int band = 0 ; band < nBands ; band ++ )
{
UpdateValues(other.m_Sum[band], other.m_SqSum[band], other.m_Min[band], other.m_Max[band],
m_Sum[band], m_SqSum[band], m_Min[band], m_Max[band]);
UpdateValues(other.m_BandCount[band],
other.m_Sum[band], other.m_SqSum[band],
other.m_Min[band], other.m_Max[band],
m_BandCount[band],
m_Sum[band], m_SqSum[band],
m_Min[band], m_Max[band]);
}
}
// Accessors
itkGetMacro(BandCount, PixelCountVectorType);
itkGetMacro(Sum, TRealVectorPixelType);
itkGetMacro(SqSum, TRealVectorPixelType);
itkGetMacro(Min, TRealVectorPixelType);
......@@ -118,11 +134,14 @@ public:
itkGetMacro(Count, double);
private:
void UpdateValues(const RealValueType & otherSum, const RealValueType & otherSqSum,
const RealValueType & otherMin, const RealValueType & otherMax,
void UpdateValues(PixelCountType otherCount,
RealValueType otherSum, RealValueType otherSqSum,
RealValueType otherMin, RealValueType otherMax,
PixelCountType & count,
RealValueType & sum, RealValueType & sqSum,
RealValueType & min, RealValueType & max)
{
count += otherCount;
sum += otherSum;
sqSum += otherSqSum;
if (otherMin < min)
......@@ -132,11 +151,14 @@ private:
}
protected:
PixelCountVectorType m_BandCount;
TRealVectorPixelType m_Sum;
TRealVectorPixelType m_SqSum;
TRealVectorPixelType m_Min;
TRealVectorPixelType m_Max;
double m_Count;
RealValueType m_NoDataValue;
PixelCountType m_Count;
bool m_UseNoDataValue;
};
/** \class PersistentStreamingStatisticsMapFromLabelImageFilter
......@@ -198,6 +220,11 @@ public:
itkStaticConstMacro(ImageDimension, unsigned int,
TInputVectorImage::ImageDimension);
itkGetMacro(NoDataValue, VectorPixelValueType);
itkSetMacro(NoDataValue, VectorPixelValueType);
itkGetMacro(UseNoDataValue, bool);
itkSetMacro(UseNoDataValue, bool);
/** Smart Pointer type to a DataObject. */
typedef typename itk::DataObject::Pointer DataObjectPointer;
typedef itk::ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType;
......@@ -260,6 +287,9 @@ private:
PersistentStreamingStatisticsMapFromLabelImageFilter(const Self &) = delete;
void operator =(const Self&) = delete;
VectorPixelValueType m_NoDataValue;
bool m_UseNoDataValue;
AccumulatorMapCollectionType m_AccumulatorMaps;
PixelValueMapType m_MeanRadiometricValue;
......@@ -337,6 +367,9 @@ public:
typedef TInputVectorImage VectorImageType;
typedef TLabelImage LabelImageType;
typedef typename VectorImageType::PixelType VectorPixelType;
typedef typename VectorImageType::PixelType::ValueType VectorPixelValueType;
typedef typename Superclass::FilterType::PixelValueMapType PixelValueMapType;
typedef typename Superclass::FilterType::PixelValueMapObjectType PixelValueMapObjectType;
......@@ -397,6 +430,30 @@ public:
return this->GetFilter()->GetLabelPopulationMap();
}
/** Set the no data value */
void SetNoDataValue(VectorPixelValueType value)
{
this->GetFilter()->SetNoDataValue(value);
}
/** Return the no data value */
VectorPixelValueType GetNoDataValue() const
{
return this->GetFilter()->GetNoDataValue();
}
/** Configure whether no data pixels ignored, treating each band independently */
void SetUseNoDataValue(bool useNoDataValue)
{
this->GetFilter()->SetUseNoDataValue(useNoDataValue);
}
/** Return whether no data pixels are ignored */
bool GetUseNoDataValue() const
{
return this->GetFilter()->GetUseNoDataValue();
}
protected:
/** Constructor */
StreamingStatisticsMapFromLabelImageFilter() {}
......
......@@ -35,6 +35,7 @@ namespace otb
template<class TInputVectorImage, class TLabelImage>
PersistentStreamingStatisticsMapFromLabelImageFilter<TInputVectorImage, TLabelImage>
::PersistentStreamingStatisticsMapFromLabelImageFilter()
: m_UseNoDataValue()
{
// first output is a copy of the image, DataObject created by
// superclass
......@@ -155,20 +156,21 @@ PersistentStreamingStatisticsMapFromLabelImageFilter<TInputVectorImage, TLabelIm
{
// Update temporary accumulator
AccumulatorMapType outputAcc;
auto endAcc = outputAcc.end();
for (auto const& threadAccMap: m_AccumulatorMaps)
{
for(auto const& it: threadAccMap)
{
const LabelPixelType label = it.first;
if (outputAcc.count(label) <= 0)
auto label = it.first;
auto itAcc = outputAcc.find(label);
if (itAcc == endAcc)
{
AccumulatorType newAcc(it.second);
outputAcc[label] = newAcc;
outputAcc.emplace(label, it.second);
}
else
{
outputAcc[label].Update(it.second);
itAcc->second.Update(it.second);
}
}
}
......@@ -177,18 +179,20 @@ PersistentStreamingStatisticsMapFromLabelImageFilter<TInputVectorImage, TLabelIm
for(auto& it: outputAcc)
{
const LabelPixelType label = it.first;
const double count = it.second.GetCount();
const RealVectorPixelType sum = it.second.GetSum();
const RealVectorPixelType sqSum = it.second.GetSqSum();
const auto &bandCount = it.second.GetBandCount();
const auto &sum = it.second.GetSum();
const auto &sqSum = it.second.GetSqSum();
// Count
m_LabelPopulation[label] = count;
m_LabelPopulation[label] = it.second.GetCount();
// Mean & stdev
RealVectorPixelType mean (sum);
RealVectorPixelType std (sqSum);
for (unsigned int band = 0 ; band < mean.GetSize() ; band++)
{
// Number of valid pixels in band
auto count = bandCount[band];
// Mean
mean[band] /= count;
......@@ -265,28 +269,31 @@ PersistentStreamingStatisticsMapFromLabelImageFilter<TInputVectorImage, TLabelIm