Commit 6e820e55 authored by Cédric Traizet's avatar Cédric Traizet

Merge branch 'app_multi_writer_take3' into 'develop'

Integration of the multiImageFileWriter in the application engine

See merge request !618
parents 832879c3 8761954e
Pipeline #3349 passed with stages
in 16 minutes and 46 seconds
......@@ -364,6 +364,17 @@ def render_deprecation_string(app):
else:
return ""
def render_multiwriting_string(app):
if app.IsMultiWritingEnabled():
return ("This application has several output images and supports \"multi-writing\". Instead of computing and writing each "
"image independently, the streamed image blocks are written in a synchronous way for each output. The output images will "
"be computed strip by strip, using the available RAM to compute the strip size, and a user defined streaming mode can be specified "
"using the streaming extended filenames (type, mode and value). Note that multi-writing can be disabled using the multi-write extended "
"filename option: &multiwrite=false, in this case the output images will be written one by one. Note that multi-writing is not supported for "
"MPI writers.")
else:
return ""
def render_application(appname, allapps):
"Render app to rst"
......@@ -378,6 +389,7 @@ def render_application(appname, allapps):
output = template_application.format(
label=appname,
deprecation_string=render_deprecation_string(app),
multiwriting_string=render_multiwriting_string(app),
heading=rst_section(app.GetName(), '='),
description=app.GetDescription(),
longdescription=make_links(app.GetDocLongDescription(), allapps),
......
......@@ -321,6 +321,16 @@ The available syntax for boolean options are:
- It is important to note that the band numbering in the nodata writer option follows the GDAL convention and starts at 1.
-----------------------------------------------
::
&multiwrite==<(bool)false>
- To desactivate multi-writing. This option will only be used in application supporting multi-writing (applications with several output images). Instead of computing and writing each image independently, the streamed image blocks are written in a synchronous way for each output. In applications, the default streaming mode is to compute the images strip by strip, with a strip size automatically computed using the available RAM. The streaming mode can be modified using the streaming options (see above), but be aware that the auto and tiled based streaming using RAM might not work properly.
- true by default
OGR DataSource options
^^^^^^^^^^^^^^^^^^^^^^^
......
......@@ -11,6 +11,8 @@ Description
{longdescription}
{multiwriting_string}
Parameters
----------
......
......@@ -148,8 +148,11 @@ private:
"This is only implemented for the Shark Random Forest classifier at this point.");
SetDefaultOutputPixelType("probamap", ImagePixelType_uint16);
MandatoryOff("probamap");
AddRAMParameter();
SetMultiWriting(true);
AddParameter(ParameterType_Int, "nbclasses", "Number of classes in the model");
SetDefaultParameterInt("nbclasses", 20);
SetParameterDescription("nbclasses", "The number of classes is required by the output of the probability map in order to set the number of output bands.");
......
......@@ -191,6 +191,8 @@ private:
AddRAMParameter();
SetMultiWriting(true);
// Doc example parameter settings
SetDocExampleParameterValue("in", "cupriteSubHsi.tif");
SetDocExampleParameterValue("out", "FilterOutput.tif");
......
......@@ -144,6 +144,7 @@ private:
SetMinimumParameterIntValue("levels", 1);
AddRAMParameter();
SetMultiWriting(true);
SetDocExampleParameterValue("in", "ROI_IKO_PAN_LesHalles.tif");
SetDocExampleParameterValue("structype", "ball");
......@@ -174,13 +175,13 @@ private:
itkExceptionMacro(<< "The specified channel index for input image is invalid.");
}
m_ExtractorFilter = ExtractorFilterType::New();
m_ExtractorFilter->SetInput(inImage);
m_ExtractorFilter->SetStartX(static_cast<unsigned int>(inImage->GetLargestPossibleRegion().GetIndex(0)));
m_ExtractorFilter->SetStartY(static_cast<unsigned int>(inImage->GetLargestPossibleRegion().GetIndex(1)));
m_ExtractorFilter->SetSizeX(inImage->GetLargestPossibleRegion().GetSize(0));
m_ExtractorFilter->SetSizeY(inImage->GetLargestPossibleRegion().GetSize(1));
m_ExtractorFilter->SetChannel(static_cast<unsigned int>(GetParameterInt("channel")));
auto extractorFilter = ExtractorFilterType::New();
extractorFilter->SetInput(inImage);
extractorFilter->SetStartX(static_cast<unsigned int>(inImage->GetLargestPossibleRegion().GetIndex(0)));
extractorFilter->SetStartY(static_cast<unsigned int>(inImage->GetLargestPossibleRegion().GetIndex(1)));
extractorFilter->SetSizeX(inImage->GetLargestPossibleRegion().GetSize(0));
extractorFilter->SetSizeY(inImage->GetLargestPossibleRegion().GetSize(1));
extractorFilter->SetChannel(static_cast<unsigned int>(GetParameterInt("channel")));
unsigned int numberOfLevels = static_cast<unsigned int>(GetParameterInt("levels"));
unsigned int initValue = static_cast<unsigned int>(GetParameterInt("radius"));
......@@ -189,16 +190,16 @@ private:
if (GetParameterString("structype") == "ball")
{
performDecomposition<BallStructuringElementType>(numberOfLevels, step, initValue);
performDecomposition<BallStructuringElementType>(extractorFilter->GetOutput(), numberOfLevels, step, initValue);
}
else // Cross
{
performDecomposition<CrossStructuringElementType>(numberOfLevels, step, initValue);
performDecomposition<CrossStructuringElementType>(extractorFilter->GetOutput(), numberOfLevels, step, initValue);
}
}
template <typename StructuringElement>
void performDecomposition(unsigned int numberOfLevels, unsigned int step, unsigned int initValue)
void performDecomposition(FloatImageType* input, unsigned int numberOfLevels, unsigned int step, unsigned int initValue)
{
typedef otb::GeodesicMorphologyIterativeDecompositionImageFilter<FloatImageType, StructuringElement> TDecompositionImageFilter;
......@@ -207,7 +208,7 @@ private:
typename TDecompositionImageFilter::Pointer decompositionImageFilter;
decompositionImageFilter = TDecompositionImageFilter::New();
decompositionImageFilter->SetInput(m_ExtractorFilter->GetOutput());
decompositionImageFilter->SetInput(input);
decompositionImageFilter->SetNumberOfIterations(numberOfLevels);
decompositionImageFilter->SetInitialValue(initValue);
decompositionImageFilter->SetStep(step);
......@@ -229,9 +230,8 @@ private:
convexListToVectorImageFilter->SetInput(decompositionImageFilter->GetConvexOutput());
convexListToVectorImageFilter->Update();
SetParameterOutputImage("outconvex", convexListToVectorImageFilter->GetOutput());
RegisterPipeline();
}
ExtractorFilterType::Pointer m_ExtractorFilter;
};
}
}
......
......@@ -89,6 +89,7 @@ private:
"the imaginary part of the input complex image.");
AddRAMParameter();
SetMultiWriting(true);
// Doc example parameter settings
SetDocExampleParameterValue("in", "monobandComplexFloat.tif");
......
......@@ -198,6 +198,8 @@ private:
SetDocExampleParameterValue("inms", "maur_labelled.tif");
SetDocExampleParameterValue("outgt", "maur_colored_GT.tif uint8");
SetMultiWriting(true);
SetOfficialDocLink();
}
......
......@@ -176,6 +176,7 @@ private:
"the result will slightly depend on thread number and the results will not be stable (see [4] for more details).");
AddRAMParameter();
SetMultiWriting(true);
// Doc example parameter settings
SetDocExampleParameterValue("in", "maur_rgb.png");
......
......@@ -419,10 +419,11 @@ private:
SetDefaultParameterInt("bm.initdisp.maps.vrad", 0);
DisableParameter("bm.initdisp.maps.vrad");
// this->DebugOn();
AddRAMParameter();
SetMultiWriting(true);
// Doc example parameter settings
SetDocExampleParameterValue("io.inleft", "StereoFixed.png");
SetDocExampleParameterValue("io.inright", "StereoMoving.png");
......
......@@ -114,9 +114,7 @@ private:
"X and Y offsets, as well as the metric value. A sub-pixel accuracy can "
"be expected. The input images should have the same size and same "
"physical space.");
SetDocLimitations(
"If the 'warp' option is activated, the pipeline will be "
"executed twice.");
SetDocLimitations("None");
SetDocAuthors("OTB-Team");
SetDocSeeAlso(" ");
......@@ -257,6 +255,8 @@ private:
AddRAMParameter();
SetMultiWriting(true);
// Doc example parameter settings
SetDocExampleParameterValue("ref", "StereoFixed.png");
SetDocExampleParameterValue("sec", "StereoMoving.png");
......
......@@ -261,6 +261,8 @@ private:
SetDocExampleParameterValue("io.outleft", "wv2_xs_left_epi_field.tif");
SetDocExampleParameterValue("io.outright", "wv2_xs_right_epi_field.tif");
SetDocExampleParameterValue("epi.elevation.default", "400");
SetMultiWriting(true);
SetOfficialDocLink();
}
......
......@@ -69,6 +69,7 @@ public:
std::pair<bool, std::string> simpleFileName;
std::pair<bool, bool> writeGEOMFile;
std::pair<bool, bool> writeRPCTags;
std::pair<bool, bool> multiWrite;
std::pair<bool, GDALCOType> gdalCreationOptions;
std::pair<bool, std::string> streamingType;
std::pair<bool, std::string> streamingSizeMode;
......@@ -93,6 +94,7 @@ public:
bool NoDataValueIsSet() const;
bool WriteGEOMFileIsSet() const;
bool WriteRPCTagsIsSet() const;
bool GetMultiWrite() const;
NoDataListType GetNoDataList() const
{
return m_NoDataList;
......
......@@ -36,6 +36,9 @@ ExtendedFilenameToWriterOptions::ExtendedFilenameToWriterOptions() : ExtendedFil
m_Options.writeGEOMFile.first = false;
m_Options.writeGEOMFile.second = true;
m_Options.multiWrite.first = false;
m_Options.multiWrite.second = true;
m_Options.writeRPCTags.first = false;
m_Options.writeRPCTags.second = false;
......@@ -49,7 +52,8 @@ ExtendedFilenameToWriterOptions::ExtendedFilenameToWriterOptions() : ExtendedFil
m_Options.bandRange.first = false;
m_Options.bandRange.second = "";
m_Options.optionList = {"writegeom", "writerpctags", "streaming:type", "streaming:sizemode", "streaming:sizevalue", "nodata", "box", "bands"};
m_Options.optionList = {"writegeom", "writerpctags", "multiwrite", "streaming:type",
"streaming:sizemode", "streaming:sizevalue", "nodata", "box", "bands"};
}
void ExtendedFilenameToWriterOptions::SetExtendedFileName(const char* extFname)
......@@ -88,8 +92,8 @@ void ExtendedFilenameToWriterOptions::SetExtendedFileName(const std::string& ext
if (!map["writegeom"].empty())
{
m_Options.writeGEOMFile.first = true;
if (map["writegeom"] == "Off" || map["writegeom"] == "off" || map["writegeom"] == "OFF" || map["writegeom"] == "false" || map["writegeom"] == "False" ||
map["writegeom"] == "0")
if (map["writegeom"] == "Off" || map["writegeom"] == "off" || map["writegeom"] == "OFF" ||
map["writegeom"] == "false" || map["writegeom"] == "False" || map["writegeom"] == "0")
{
m_Options.writeGEOMFile.second = false;
}
......@@ -127,16 +131,27 @@ void ExtendedFilenameToWriterOptions::SetExtendedFileName(const std::string& ext
if (!map["writerpctags"].empty())
{
m_Options.writeRPCTags.first = true;
if (map["writerpctags"] == "On" || map["writerpctags"] == "on" || map["writerpctags"] == "ON" || map["writerpctags"] == "true" ||
map["writerpctags"] == "True" || map["writerpctags"] == "1")
if (map["writerpctags"] == "On" || map["writerpctags"] == "on" || map["writerpctags"] == "ON" ||
map["writerpctags"] == "true" || map["writerpctags"] == "True" || map["writerpctags"] == "1")
{
m_Options.writeRPCTags.second = true;
}
}
if (!map["multiwrite"].empty())
{
m_Options.multiWrite.first = true;
if (map["multiwrite"] == "Off" || map["multiwrite"] == "off" || map["multiwrite"] == "OFF" ||
map["multiwrite"] == "false" || map["multiwrite"] == "False" || map["multiwrite"] == "0")
{
m_Options.multiWrite.second = false;
}
}
if (!map["streaming:type"].empty())
{
if (map["streaming:type"] == "auto" || map["streaming:type"] == "tiled" || map["streaming:type"] == "stripped" || map["streaming:type"] == "none")
if (map["streaming:type"] == "auto" || map["streaming:type"] == "tiled" ||
map["streaming:type"] == "stripped" || map["streaming:type"] == "none")
{
m_Options.streamingType.first = true;
m_Options.streamingType.second = map["streaming:type"];
......@@ -252,6 +267,11 @@ bool ExtendedFilenameToWriterOptions::GetWriteGEOMFile() const
return m_Options.writeGEOMFile.second;
}
bool ExtendedFilenameToWriterOptions::GetMultiWrite() const
{
return m_Options.multiWrite.second;
}
bool ExtendedFilenameToWriterOptions::GetWriteRPCTags() const
{
return m_Options.writeRPCTags.second;
......
......@@ -200,6 +200,8 @@ public:
itkGetObjectMacro(ImageIO, otb::ImageIOBase);
itkGetConstObjectMacro(ImageIO, otb::ImageIOBase);
itkGetConstObjectMacro(FilenameHelper, FNameHelperType);
/** This override doesn't return a const ref on the actual boolean */
const bool& GetAbortGenerateData() const override;
......
......@@ -308,7 +308,7 @@ void ImageFileWriter<TInputImage>::GenerateOutputInformation(void)
{
if (sizevalue == 0)
{
otbLogMacro(Warning, << "Streaming sizemode is set to nbsplits but sizevalue is 0. This will result in upredicted behaviour. Please consider setting "
otbLogMacro(Warning, << "Streaming sizemode is set to nbsplits but sizevalue is 0. This will result in undefined behaviour. Please consider setting "
"the sizevalue by using &streaming:sizevalue=x.");
}
this->SetNumberOfDivisionsTiledStreaming(sizevalue);
......@@ -317,7 +317,7 @@ void ImageFileWriter<TInputImage>::GenerateOutputInformation(void)
{
if (sizevalue == 0)
{
otbLogMacro(Warning, << "Streaming sizemode is set to height but sizevalue is 0. This will result in upredicted behaviour. Please consider setting "
otbLogMacro(Warning, << "Streaming sizemode is set to height but sizevalue is 0. This will result in undefined behaviour. Please consider setting "
"the sizevalue by using &streaming:sizevalue=x.");
}
......@@ -340,7 +340,7 @@ void ImageFileWriter<TInputImage>::GenerateOutputInformation(void)
{
if (sizevalue == 0)
{
otbLogMacro(Warning, << "Streaming sizemode is set to nbsplits but sizevalue is 0. This will result in upredicted behaviour. Please consider setting "
otbLogMacro(Warning, << "Streaming sizemode is set to nbsplits but sizevalue is 0. This will result in undefined behaviour. Please consider setting "
"the sizevalue by using &streaming:sizevalue=x.");
}
this->SetNumberOfDivisionsStrippedStreaming(sizevalue);
......@@ -349,7 +349,7 @@ void ImageFileWriter<TInputImage>::GenerateOutputInformation(void)
{
if (sizevalue == 0)
{
otbLogMacro(Warning, << "Streaming sizemode is set to height but sizevalue is 0. This will result in upredicted behaviour. Please consider setting "
otbLogMacro(Warning, << "Streaming sizemode is set to height but sizevalue is 0. This will result in undefined behaviour. Please consider setting "
"the sizevalue by using &streaming:sizevalue=x.");
}
this->SetNumberOfLinesStrippedStreaming(sizevalue);
......@@ -451,16 +451,26 @@ void ImageFileWriter<TInputImage>::GenerateOutputInformation(void)
/** Parse region size modes */
if (m_FilenameHelper->BoxIsSet())
{
std::vector<int> boxVector;
std::vector<unsigned int> boxVector;
Utils::ConvertStringToVector(m_FilenameHelper->GetBox(), boxVector, "ExtendedFileName:box", ":");
if (boxVector.size() != 4)
{
itk::ImageFileWriterException e(__FILE__, __LINE__);
std::ostringstream msg;
msg << "Invalid box option " << m_FilenameHelper->GetBox() << ". The box should contains four elements: startx:starty:sizex:sizey";
e.SetDescription(msg.str());
e.SetLocation(ITK_LOCATION);
throw e;
}
typename InputImageRegionType::IndexType start;
typename InputImageRegionType::SizeType size;
start[0] = boxVector[0]; // first index on X
start[1] = boxVector[1]; // first index on Y
size[0] = boxVector[2]; // size along X
size[1] = boxVector[3]; // size along Y
inputRegion.SetSize(size);
inputRegion.SetIndex(start);
......
......@@ -126,25 +126,14 @@ public:
* You may specify top and bottom margins that will be removed from the input image, according to its largest possible region.
*/
template <class TImage>
void AddInputImage(const TImage* inputPtr, const std::string& fileName)
{
Sink<TImage>* sink = new Sink<TImage>(inputPtr, fileName);
m_SinkList.push_back(SinkBase::Pointer(sink));
unsigned int size = m_SinkList.size();
this->SetNthInput(size - 1, const_cast<itk::DataObject*>(dynamic_cast<const itk::DataObject*>(inputPtr)));
}
void AddInputImage(const TImage* inputPtr, const std::string& fileName);
/** Add a new ImageFileWriter to the multi-writer. This is an alternative method
* when you already have an instanciated writer.
*/
template <class TWriter>
void AddInputWriter(const TWriter* writer)
{
Sink<typename TWriter::InputImageType>* sink = new Sink<typename TWriter::InputImageType>(writer);
m_SinkList.push_back(SinkBase::Pointer(sink));
unsigned int size = m_SinkList.size();
this->SetNthInput(size - 1, const_cast<itk::DataObject*>(dynamic_cast<const itk::DataObject*>(writer->GetInput())));
}
void AddInputWriter(typename TWriter::Pointer writer);
virtual void UpdateOutputInformation() override;
......@@ -244,9 +233,12 @@ private:
}
virtual void WriteImageInformation() = 0;
virtual void Write(const RegionType& streamRegion) = 0;
virtual bool CanStreamWrite() = 0;
virtual bool CanStreamWrite() const = 0;
typedef boost::shared_ptr<SinkBase> Pointer;
virtual itk::ImageRegion<2> GetRegionToWrite() const = 0;
protected:
/** The image on which streaming is performed */
ImageBaseType::ConstPointer m_InputImage;
......@@ -265,17 +257,22 @@ private:
{
}
Sink(typename TImage::ConstPointer inputImage, const std::string& filename);
Sink(typename otb::ImageFileWriter<TImage>::ConstPointer writer);
Sink(typename otb::ImageFileWriter<TImage>::Pointer writer);
virtual ~Sink()
{
}
virtual void WriteImageInformation();
virtual void Write(const RegionType& streamRegion);
virtual bool CanStreamWrite();
void WriteImageInformation() override;
void Write(const RegionType& streamRegion) override;
bool CanStreamWrite() const override;
typedef boost::shared_ptr<Sink> Pointer;
/** Get the region that should be written. By default this is the largest possible region
* of the input image, but this might be overriden by the box extended filename parameter of
* the input writer */
itk::ImageRegion<2> GetRegionToWrite() const override;
private:
/** Actual writer for this image */
typename otb::ImageFileWriter<TImage>::Pointer m_Writer;
......
......@@ -37,13 +37,13 @@ MultiImageFileWriter::Sink<TImage>::Sink(typename TImage::ConstPointer inputImag
}
template <class TImage>
MultiImageFileWriter::Sink<TImage>::Sink(typename otb::ImageFileWriter<TImage>::ConstPointer writer)
: SinkBase(dynamic_cast<const ImageBaseType*>(writer->GetInput()->GetPointer())), m_Writer(writer), m_ImageIO(NULL)
MultiImageFileWriter::Sink<TImage>::Sink(typename otb::ImageFileWriter<TImage>::Pointer writer)
: SinkBase(dynamic_cast<const ImageBaseType*>(writer->GetInput())), m_Writer(writer), m_ImageIO(NULL)
{
}
template <class TImage>
bool MultiImageFileWriter::Sink<TImage>::CanStreamWrite()
bool MultiImageFileWriter::Sink<TImage>::CanStreamWrite() const
{
if (m_ImageIO.IsNull())
return false;
......@@ -71,6 +71,179 @@ void MultiImageFileWriter::Sink<TImage>::Write(const RegionType& streamRegion)
m_Writer->UpdateOutputData(nullptr);
}
template <class TImage>
itk::ImageRegion<2>
MultiImageFileWriter::Sink<TImage>::GetRegionToWrite() const
{
auto fnameHelper = m_Writer->GetFilenameHelper();
if (fnameHelper->BoxIsSet())
{
std::vector<unsigned int> boxVector;
Utils::ConvertStringToVector(fnameHelper->GetBox(), boxVector, "ExtendedFileName:box", ":");
if (boxVector.size() != 4)
{
itk::ImageFileWriterException e(__FILE__, __LINE__);
std::ostringstream msg;
msg << "Invalid box option " << fnameHelper->GetBox() << ". The box should contains four elements: startx:starty:sizex:sizey";
e.SetDescription(msg.str());
e.SetLocation(ITK_LOCATION);
throw e;
}
typename itk::ImageRegion<2>::IndexType start {{boxVector[0], boxVector[1]}};
typename itk::ImageRegion<2>::SizeType size {{boxVector[2], boxVector[3]}};
itk::ImageRegion<2> regionToWrite {start , size};
regionToWrite.Crop(m_InputImage->GetLargestPossibleRegion());
return regionToWrite;
}
else
{
return m_InputImage->GetLargestPossibleRegion();
}
}
template <class TWriter>
void MultiImageFileWriter::AddInputWriter(typename TWriter::Pointer writer)
{
Sink<typename TWriter::InputImageType>* sink = new Sink<typename TWriter::InputImageType>(writer);
m_SinkList.push_back(SinkBase::Pointer(sink));
unsigned int size = m_SinkList.size();
this->SetNthInput(size - 1, const_cast<itk::DataObject*>(dynamic_cast<const itk::DataObject*>(writer->GetInput())));
/** Parse streaming modes */
auto filenameHelper = writer->GetFilenameHelper();
if (filenameHelper->StreamingTypeIsSet())
{
otbLogMacro(
Warning,
<< "Streaming configuration through extended filename is used. Any previous streaming configuration (ram value, streaming mode ...) will be ignored.");
std::string type = filenameHelper->GetStreamingType();
std::string sizemode = "auto";
if (filenameHelper->StreamingSizeModeIsSet())
{
sizemode = filenameHelper->GetStreamingSizeMode();
}
unsigned int sizevalue = 0;
// Save the DefaultRAM value for later
unsigned int oldDefaultRAM = m_StreamingManager->GetDefaultRAM();
if (sizemode == "auto")
{
sizevalue = oldDefaultRAM;
}
if (filenameHelper->StreamingSizeValueIsSet())
{
sizevalue = static_cast<unsigned int>(filenameHelper->GetStreamingSizeValue());
}
if (type == "auto")
{
if (sizemode != "auto")
{
otbLogMacro(Warning, << "In auto streaming type, the sizemode option will be ignored.");
}
if (sizevalue == 0)
{
otbLogMacro(Warning, << "sizemode is auto but sizevalue is 0. Value will be fetched from the OTB_MAX_RAM_HINT environment variable if set, or else use "
"the default value");
}
this->SetAutomaticAdaptativeStreaming(sizevalue);
}
else if (type == "tiled")
{
if (sizemode == "auto")
{
if (sizevalue == 0)
{
otbLogMacro(Warning, << "sizemode is auto but sizevalue is 0. Value will be fetched from the OTB_MAX_RAM_HINT environment variable if set, or else "
"use the default value");
}
this->SetAutomaticTiledStreaming(sizevalue);
}
else if (sizemode == "nbsplits")
{
if (sizevalue == 0)
{
otbLogMacro(Warning, << "Streaming sizemode is set to nbsplits but sizevalue is 0. This will result in undefined behaviour. Please consider setting "
"the sizevalue by using &streaming:sizevalue=x.");
}
this->SetNumberOfDivisionsTiledStreaming(sizevalue);
}
else if (sizemode == "height")
{
if (sizevalue == 0)
{
otbLogMacro(Warning, << "Streaming sizemode is set to height but sizevalue is 0. This will result in undefined behaviour. Please consider setting "
"the sizevalue by using &streaming:sizevalue=x.");
}
this->SetTileDimensionTiledStreaming(sizevalue);
}
}
else if (type == "stripped")
{
if (sizemode == "auto")
{
if (sizevalue == 0)
{
otbLogMacro(
Warning, << "sizemode is auto but sizevalue is 0. Value will be fetched from configuration file if any, or from cmake configuration otherwise.");
}
this->SetAutomaticStrippedStreaming(sizevalue);
}
else if (sizemode == "nbsplits")
{
if (sizevalue == 0)