22 #ifndef otbImageFileWriter_hxx
23 #define otbImageFileWriter_hxx
26 #include "itkImageFileWriter.h"
28 #include "itkObjectFactoryBase.h"
30 #include "itkImageRegionMultidimensionalSplitter.h"
33 #include "itkImageRegionIterator.h"
35 #include "itkMetaDataObject.h"
39 #include "otbConfigure.h"
53 #include "itkProgressTransformer.h"
61 template <
class TInputImage>
63 : m_NumberOfDivisions(0),
65 m_DivisionProgress(0.0),
66 m_UserSpecifiedImageIO(true),
67 m_UserSpecifiedIORegion(false),
68 m_FactorySpecifiedImageIO(false),
69 m_UseCompression(false),
70 m_UseInputMetaDataDictionary(false),
71 m_WriteGeomFile(false),
90 template <
class TInputImage>
95 template <
class TInputImage>
99 typename NumberOfDivisionsStrippedStreamingManagerType::Pointer streamingManager = NumberOfDivisionsStrippedStreamingManagerType::New();
100 streamingManager->SetNumberOfDivisions(nbDivisions);
101 m_StreamingManager = streamingManager;
104 template <
class TInputImage>
108 typename NumberOfDivisionsTiledStreamingManagerType::Pointer streamingManager = NumberOfDivisionsTiledStreamingManagerType::New();
109 streamingManager->SetNumberOfDivisions(nbDivisions);
110 m_StreamingManager = streamingManager;
113 template <
class TInputImage>
117 typename NumberOfLinesStrippedStreamingManagerType::Pointer streamingManager = NumberOfLinesStrippedStreamingManagerType::New();
118 streamingManager->SetNumberOfLinesPerStrip(nbLinesPerStrip);
119 m_StreamingManager = streamingManager;
122 template <
class TInputImage>
126 typename RAMDrivenStrippedStreamingManagerType::Pointer streamingManager = RAMDrivenStrippedStreamingManagerType::New();
127 streamingManager->SetAvailableRAMInMB(availableRAM);
128 streamingManager->SetBias(bias);
129 m_StreamingManager = streamingManager;
132 template <
class TInputImage>
136 typename TileDimensionTiledStreamingManagerType::Pointer streamingManager = TileDimensionTiledStreamingManagerType::New();
137 streamingManager->SetTileDimension(tileDimension);
138 m_StreamingManager = streamingManager;
141 template <
class TInputImage>
145 typename RAMDrivenTiledStreamingManagerType::Pointer streamingManager = RAMDrivenTiledStreamingManagerType::New();
146 streamingManager->SetAvailableRAMInMB(availableRAM);
147 streamingManager->SetBias(bias);
148 m_StreamingManager = streamingManager;
151 template <
class TInputImage>
155 typename RAMDrivenAdaptativeStreamingManagerType::Pointer streamingManager = RAMDrivenAdaptativeStreamingManagerType::New();
156 streamingManager->SetAvailableRAMInMB(availableRAM);
157 streamingManager->SetBias(bias);
158 m_StreamingManager = streamingManager;
164 template <
class TInputImage>
167 Superclass::PrintSelf(os, indent);
169 os << indent <<
"File Name: " << (m_FileName.data() ? m_FileName.data() :
"(none)") << std::endl;
171 os << indent <<
"Image IO: ";
172 if (m_ImageIO.IsNull())
178 os << m_ImageIO <<
"\n";
181 os << indent <<
"IO Region: " << m_IORegion <<
"\n";
183 if (m_UseCompression)
185 os << indent <<
"Compression: On\n";
189 os << indent <<
"Compression: Off\n";
192 if (m_UseInputMetaDataDictionary)
194 os << indent <<
"UseInputMetaDataDictionary: On\n";
198 os << indent <<
"UseInputMetaDataDictionary: Off\n";
201 if (m_FactorySpecifiedImageIO)
203 os << indent <<
"FactorySpecifiedmageIO: On\n";
207 os << indent <<
"FactorySpecifiedmageIO: Off\n";
212 template <
class TInputImage>
215 if (m_IORegion != region)
219 m_UserSpecifiedIORegion =
true;
223 template <
class TInputImage>
226 this->ProcessObject::SetNthInput(0,
const_cast<InputImageType*
>(input));
229 template <
class TInputImage>
232 if (this->GetNumberOfInputs() < 1)
237 return static_cast<const InputImageType*
>(this->ProcessObject::GetInput(0));
241 template <
class TInputImage>
248 if (inputPtr.IsNull())
250 itkExceptionMacro(<<
"No input to writer");
256 if (m_FilenameHelper->StreamingTypeIsSet())
260 <<
"Streaming configuration through extended filename is used. Any previous streaming configuration (ram value, streaming mode ...) will be ignored.");
262 std::string type = m_FilenameHelper->GetStreamingType();
264 std::string sizemode =
"auto";
266 if (m_FilenameHelper->StreamingSizeModeIsSet())
268 sizemode = m_FilenameHelper->GetStreamingSizeMode();
271 unsigned int sizevalue = 0;
273 unsigned int oldDefaultRAM = m_StreamingManager->GetDefaultRAM();
274 if (sizemode ==
"auto")
276 sizevalue = oldDefaultRAM;
279 if (m_FilenameHelper->StreamingSizeValueIsSet())
281 sizevalue =
static_cast<unsigned int>(m_FilenameHelper->GetStreamingSizeValue());
286 if (sizemode !=
"auto")
288 otbLogMacro(Warning, <<
"In auto streaming type, the sizemode option will be ignored.");
292 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 "
293 "the default value");
295 this->SetAutomaticAdaptativeStreaming(sizevalue);
297 else if (type ==
"tiled")
299 if (sizemode ==
"auto")
303 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 "
304 "use the default value");
306 this->SetAutomaticTiledStreaming(sizevalue);
308 else if (sizemode ==
"nbsplits")
312 otbLogMacro(Warning, <<
"Streaming sizemode is set to nbsplits but sizevalue is 0. This will result in undefined behaviour. Please consider setting "
313 "the sizevalue by using &streaming:sizevalue=x.");
315 this->SetNumberOfDivisionsTiledStreaming(sizevalue);
317 else if (sizemode ==
"height")
321 otbLogMacro(Warning, <<
"Streaming sizemode is set to height but sizevalue is 0. This will result in undefined behaviour. Please consider setting "
322 "the sizevalue by using &streaming:sizevalue=x.");
325 this->SetTileDimensionTiledStreaming(sizevalue);
328 else if (type ==
"stripped")
330 if (sizemode ==
"auto")
335 Warning, <<
"sizemode is auto but sizevalue is 0. Value will be fetched from configuration file if any, or from cmake configuration otherwise.");
338 this->SetAutomaticStrippedStreaming(sizevalue);
340 else if (sizemode ==
"nbsplits")
344 otbLogMacro(Warning, <<
"Streaming sizemode is set to nbsplits but sizevalue is 0. This will result in undefined behaviour. Please consider setting "
345 "the sizevalue by using &streaming:sizevalue=x.");
347 this->SetNumberOfDivisionsStrippedStreaming(sizevalue);
349 else if (sizemode ==
"height")
353 otbLogMacro(Warning, <<
"Streaming sizemode is set to height but sizevalue is 0. This will result in undefined behaviour. Please consider setting "
354 "the sizevalue by using &streaming:sizevalue=x.");
356 this->SetNumberOfLinesStrippedStreaming(sizevalue);
359 else if (type ==
"none")
361 if (sizemode !=
"" || sizevalue != 0)
363 otbLogMacro(Warning, <<
"Streaming is explicitly disabled, sizemode and sizevalue will be ignored.");
365 this->SetNumberOfDivisionsTiledStreaming(0);
370 m_StreamingManager->SetDefaultRAM(oldDefaultRAM);
374 if (m_FilenameHelper->StreamingSizeValueIsSet() || m_FilenameHelper->StreamingSizeModeIsSet())
376 otbLogMacro(Warning, <<
"No streaming type is set, streaming sizemode and sizevalue will be ignored.");
382 if (m_FileName ==
"")
385 itkExceptionMacro(<<
"No filename was specified");
395 if (m_ImageIO.IsNull())
399 m_FactorySpecifiedImageIO =
true;
403 if (!m_ImageIO->CanWriteFile(m_FileName.c_str()))
405 if (m_FactorySpecifiedImageIO)
408 m_FactorySpecifiedImageIO =
true;
413 if (m_ImageIO.IsNull())
415 itk::ImageFileWriterException e(__FILE__, __LINE__);
416 std::ostringstream msg;
417 msg <<
"Cannot write image " << m_FileName <<
". Probably unsupported format or incorrect filename extension.";
418 e.SetDescription(msg.str());
419 e.SetLocation(ITK_LOCATION);
424 if ((strcmp(m_ImageIO->GetNameOfClass(),
"GDALImageIO") == 0) &&
425 (m_FilenameHelper->gdalCreationOptionsIsSet() || m_FilenameHelper->WriteRPCTagsIsSet() || m_FilenameHelper->NoDataValueIsSet() || m_FilenameHelper->SrsValueIsSet()))
429 if (imageIO.IsNull())
431 itk::ImageFileWriterException e(__FILE__, __LINE__);
432 std::ostringstream msg;
433 msg <<
" ImageIO is of kind GDALImageIO, but fails to dynamic_cast (this should never happen)." << std::endl;
434 e.SetDescription(msg.str());
438 imageIO->SetOptions(m_FilenameHelper->GetgdalCreationOptions());
439 imageIO->SetWriteRPCTags(m_FilenameHelper->GetWriteRPCTags());
440 if (m_FilenameHelper->NoDataValueIsSet())
441 imageIO->SetNoDataList(m_FilenameHelper->GetNoDataList());
442 if (m_FilenameHelper->SrsValueIsSet())
443 imageIO->SetEpsgCode(m_FilenameHelper->GetSrsValue());
455 if (m_FilenameHelper->BoxIsSet())
457 std::vector<unsigned int> boxVector;
461 if (boxVector.size() != 4)
463 itk::ImageFileWriterException e(__FILE__, __LINE__);
464 std::ostringstream msg;
465 msg <<
"Invalid box option " << m_FilenameHelper->GetBox() <<
". The box should contains four elements: startx:starty:sizex:sizey";
466 e.SetDescription(msg.str());
467 e.SetLocation(ITK_LOCATION);
471 typename InputImageRegionType::IndexType start;
472 typename InputImageRegionType::SizeType size;
473 start[0] = boxVector[0];
474 start[1] = boxVector[1];
475 size[0] = boxVector[2];
476 size[1] = boxVector[3];
478 inputRegion.SetSize(size);
479 inputRegion.SetIndex(start);
481 if (!inputRegion.Crop(inputPtr->GetLargestPossibleRegion()))
487 itk::InvalidRequestedRegionError e(__FILE__, __LINE__);
488 e.SetLocation(ITK_LOCATION);
489 e.SetDescription(
"Requested box region is (at least partially) outside the largest possible region.");
490 e.SetDataObject(inputPtr);
493 otbLogMacro(Info, <<
"Writing user defined region [" << start[0] <<
", " << start[0] + size[0] - 1 <<
"]x[" << start[1] <<
", " << start[1] + size[1]
496 m_ShiftOutputIndex = inputRegion.GetIndex();
505 if (m_ImageIO->CanStreamWrite() ==
false)
507 otbLogMacro(Warning, <<
"The file format of " << m_FileName <<
" does not support streaming. All data will be loaded to memory");
508 this->SetNumberOfDivisionsStrippedStreaming(1);
515 else if (inputPtr->GetBufferedRegion() == inputRegion)
517 otbLogMacro(Debug, <<
"Buffered region is the largest possible region, there is no need for streaming.");
518 this->SetNumberOfDivisionsStrippedStreaming(1);
520 m_StreamingManager->PrepareStreaming(inputPtr, inputRegion);
521 m_NumberOfDivisions = m_StreamingManager->GetNumberOfSplits();
524 const auto firstSplitSize = m_StreamingManager->GetSplit(0).GetSize();
525 otbLogMacro(Info, <<
"File " << m_FileName <<
" will be written in " << m_NumberOfDivisions <<
" blocks of " << firstSplitSize[0] <<
"x" << firstSplitSize[1]
531 typename TInputImage::PointType origin;
532 inputPtr->TransformIndexToPhysicalPoint(inputRegion.GetIndex(), origin);
533 const typename TInputImage::SpacingType& spacing = inputPtr->GetSpacing();
534 const typename TInputImage::DirectionType& direction = inputPtr->GetDirection();
535 m_ImageIO->SetNumberOfDimensions(TInputImage::ImageDimension);
536 int direction_sign(0);
537 for (
unsigned int i = 0; i < TInputImage::ImageDimension; ++i)
539 if (direction[i][i] < 0)
544 m_ImageIO->SetDimensions(i, inputRegion.GetSize(i));
545 m_ImageIO->SetSpacing(i, direction_sign * spacing[i]);
546 m_ImageIO->SetOrigin(i, origin[i]);
548 vnl_vector<double> axisDirection(TInputImage::ImageDimension);
551 for (
unsigned int j = 0; j < TInputImage::ImageDimension; ++j)
553 axisDirection[j] = direction_sign * direction[j][i];
555 m_ImageIO->SetDirection(i, axisDirection);
558 m_ImageIO->SetUseCompression(m_UseCompression);
559 m_ImageIO->SetMetaDataDictionary(inputPtr->GetMetaDataDictionary());
562 if (img_common !=
nullptr)
570 m_ImageIO->SetFileName(m_FileName);
572 m_ImageIO->WriteImageInformation();
578 template <
class TInputImage>
581 this->UpdateOutputInformation();
583 this->SetAbortGenerateData(0);
584 this->SetProgress(0.0);
586 itk::ProgressTransformer pt( 0.0f, 1.0f,
this );
590 this->InvokeEvent(itk::StartEvent());
592 pt.GetProcessObject();
593 m_CurrentDivision = 0;
594 m_DivisionProgress = 0;
598 itk::ProcessObject* source = inputPtr->GetSource();
599 m_IsObserving =
false;
605 typedef itk::MemberCommand<Self> CommandType;
606 typedef typename CommandType::Pointer CommandPointerType;
608 CommandPointerType command = CommandType::New();
609 command->SetCallbackFunction(
this, &Self::ObserveSourceFilterProgress);
611 m_ObserverID = source->AddObserver(itk::ProgressEvent(), command);
612 m_IsObserving =
true;
616 otbLogMacro(Warning, <<
"Could not get the source process object. Progress report might be buggy");
625 for (m_CurrentDivision = 0; m_CurrentDivision < m_NumberOfDivisions && !this->GetAbortGenerateData();
626 m_CurrentDivision++, m_DivisionProgress = 0, pt.GetProcessObject())
628 streamRegion = m_StreamingManager->GetSplit(m_CurrentDivision);
630 inputPtr->SetRequestedRegion(streamRegion);
631 inputPtr->PropagateRequestedRegion();
632 inputPtr->UpdateOutputData();
635 itk::ImageIORegion ioRegion(TInputImage::ImageDimension);
636 for (
unsigned int i = 0; i < TInputImage::ImageDimension; ++i)
638 ioRegion.SetSize(i, streamRegion.GetSize(i));
640 ioRegion.SetIndex(i, streamRegion.GetIndex(i) - m_ShiftOutputIndex[i]);
642 this->SetIORegion(ioRegion);
643 m_ImageIO->SetIORegion(m_IORegion);
646 this->GenerateData();
653 if (!this->GetAbortGenerateData())
655 this->UpdateProgress(1.0);
659 itk::ProcessAborted e(__FILE__, __LINE__);
660 e.SetLocation(ITK_LOCATION);
661 e.SetDescription(
"Image writing has been aborted");
667 this->InvokeEvent(itk::EndEvent());
671 m_IsObserving =
false;
672 source->RemoveObserver(m_ObserverID);
678 this->ReleaseInputs();
682 m_ShiftOutputIndex = inputPtr->GetLargestPossibleRegion().GetIndex();
689 template <
class TInputImage>
700 if (strcmp(input->GetNameOfClass(),
"VectorImage") == 0)
702 typedef typename InputImageType::InternalPixelType VectorImagePixelType;
703 m_ImageIO->SetPixelTypeInfo(
typeid(VectorImagePixelType));
705 typedef typename InputImageType::AccessorFunctorType AccessorFunctorType;
706 m_ImageIO->SetNumberOfComponents(AccessorFunctorType::GetVectorLength(input));
708 m_IOComponents = m_ImageIO->GetNumberOfComponents();
710 if (m_FilenameHelper->BandRangeIsSet())
713 bool retBandRange = m_FilenameHelper->ResolveBandRange(m_FilenameHelper->GetBandRange(), m_IOComponents, m_BandList);
714 if (retBandRange ==
false || m_BandList.empty())
717 itkGenericExceptionMacro(
"The given band range is either empty or invalid for a " << m_IOComponents <<
" bands input image!");
730 const void* dataPtr = (
const void*)input->GetBufferPointer();
737 itk::ImageIORegionAdaptor<TInputImage::ImageDimension>::Convert(m_ImageIO->GetIORegion(), ioRegion, m_ShiftOutputIndex);
742 if ((bufferedRegion != ioRegion) || (m_FilenameHelper->BandRangeIsSet() && (m_IOComponents < m_BandList.size())))
744 if (m_NumberOfDivisions > 1 || m_UserSpecifiedIORegion)
746 cacheImage = InputImageType::New();
747 cacheImage->CopyInformation(input);
750 if (m_FilenameHelper->BandRangeIsSet() && (m_IOComponents < m_BandList.size()))
752 cacheImage->SetNumberOfComponentsPerPixel(m_BandList.size());
755 cacheImage->SetBufferedRegion(ioRegion);
756 cacheImage->Allocate();
759 if (m_FilenameHelper->BandRangeIsSet() && (m_IOComponents < m_BandList.size()))
761 cacheImage->SetNumberOfComponentsPerPixel(m_IOComponents);
764 typedef itk::ImageRegionConstIterator<TInputImage> ConstIteratorType;
765 typedef itk::ImageRegionIterator<TInputImage> IteratorType;
767 ConstIteratorType in(input, ioRegion);
768 IteratorType out(cacheImage, ioRegion);
771 for (in.GoToBegin(), out.GoToBegin(); !in.IsAtEnd(); ++in, ++out)
776 dataPtr = (
const void*)cacheImage->GetBufferPointer();
780 itk::ImageFileWriterException e(__FILE__, __LINE__);
781 std::ostringstream msg;
782 msg <<
"Did not get requested region!" << std::endl;
783 msg <<
"Requested:" << std::endl;
785 msg <<
"Actual:" << std::endl;
786 msg << bufferedRegion;
787 e.SetDescription(msg.str());
788 e.SetLocation(ITK_LOCATION);
793 if (m_FilenameHelper->BandRangeIsSet() && (!m_BandList.empty()))
797 m_ImageIO->DoMapBuffer(
const_cast<void*
>(dataPtr), bufferedRegion.GetNumberOfPixels(), this->m_BandList);
798 m_ImageIO->SetNumberOfComponents(m_BandList.size());
801 m_ImageIO->Write(dataPtr);
804 template <
class TInputImage>
807 this->m_FilenameHelper->SetExtendedFileName(extendedFileName);
808 m_FileName = this->m_FilenameHelper->GetSimpleFileName();
813 template <
class TInputImage>
816 return this->m_FilenameHelper->GetSimpleFileName();
819 template <
class TInputImage>
822 std::lock_guard<std::mutex> mutexHolder(m_Lock);
824 bool ret = Superclass::GetAbortGenerateData();
830 template <
class TInputImage>
833 std::lock_guard<std::mutex> mutexHolder(m_Lock);
834 Superclass::SetAbortGenerateData(val);
ImageIO object for reading and writing images with GDAL.
itk::SmartPointer< Self > Pointer
const ImageMetadata & GetImageMetadata() const
void SetImageMetadata(ImageMetadata imd)
void SetIORegion(const itk::ImageIORegion ®ion)
void SetAbortGenerateData(const bool val) override
void PrintSelf(std::ostream &os, itk::Indent indent) const override
~ImageFileWriter() override
TInputImage InputImageType
InputImageType::RegionType InputImageRegionType
void SetNumberOfLinesStrippedStreaming(unsigned int nbLinesPerStrip)
virtual void SetInput(const InputImageType *input)
InputImageType::Pointer InputImagePointer
void SetAutomaticTiledStreaming(unsigned int availableRAM=0, double bias=1.0)
InputIndexType m_ShiftOutputIndex
const bool & GetAbortGenerateData() const override
void SetAutomaticStrippedStreaming(unsigned int availableRAM=0, double bias=1.0)
void SetNumberOfDivisionsStrippedStreaming(unsigned int nbDivisions)
virtual void SetFileName(const std::string &extendedFileName)
FNameHelperType::Pointer m_FilenameHelper
void SetTileDimensionTiledStreaming(unsigned int tileDimension)
void SetNumberOfDivisionsTiledStreaming(unsigned int nbDivisions)
void GenerateOutputInformation(void) override
virtual const char * GetFileName() const
void SetAutomaticAdaptativeStreaming(unsigned int availableRAM=0, double bias=1.0)
const InputImageType * GetInput()
void GenerateData(void) override
static ImageIOBasePointer CreateImageIO(const char *path, FileModeType mode)
static Logger * Instance()
This class computes the divisions needed to stream an image by strips, driven by a user-defined numbe...
This class computes the divisions needed to stream an image by strips, driven by a user-defined numbe...
This class computes the divisions needed to stream an image by strips, driven by a user-defined desir...
This class computes the divisions needed to stream an image according to the input image tiling schem...
This class computes the divisions needed to stream an image by strips, according to a user-defined av...
This class computes the divisions needed to stream an image in square tiles, according to a user-defi...
This class computes the divisions needed to stream an image in square tiles, driven by a user-defined...
OTBCommon_EXPORT bool const FalseConstant
void ConvertStringToVector(std::string const &str, T &ret, std::string const &errmsg, const char *delims=" ")
OTBCommon_EXPORT bool const TrueConstant
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.
#define otbLogMacro(level, msg)