/*========================================================================= * * Copyright NumFOCUS * * 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 * * https://www.apache.org/licenses/LICENSE-2.0.txt * * 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. * *=========================================================================*/ /*========================================================================= * * Portions of this file are subject to the VTK Toolkit Version 3 copyright. * * Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen * * For complete copyright, license and disclaimer of warranty information * please refer to the NOTICE file at the top of the ITK source tree. * *=========================================================================*/ #ifndef itkImageTransformer_h #define itkImageTransformer_h #include "itkProcessObject.h" #include "itkImage.h" namespace itk { /** * \class ImageTransformer * \brief Base class for all process objects that transform an image into something else. * * ImageTransformer is the base class for all process objects that transform an * image data. Specifically, this class defines the SetInput() method * that takes a pointer to the input image. The class also defines * some internal private data members that are used to manage streaming * of data. * * Memory management in an ImageTransformer is slightly different than a * standard ProcessObject. ProcessObject's always release the bulk * data associated with their output prior to GenerateData() being * called. ImageTransformers default to not releasing the bulk data incase * that particular memory block is large enough to hold the new output * values. This avoids unnecessary deallocation/allocation * sequences. ImageTransformer's can be forced to use a memory management * model similar to the default ProcessObject behaviour by calling * ProcessObject::ReleaseDataBeforeUpdateFlagOn(). A user may want to * set this flag to limit peak memory usage during a pipeline update. * * \ingroup ITKDeprecated */ template class ITK_TEMPLATE_EXPORT ImageTransformer : public ProcessObject { public: ITK_DISALLOW_COPY_AND_MOVE(ImageTransformer); /** Standard class type aliases. */ using Self = ImageTransformer; using Superclass = ProcessObject; using Pointer = SmartPointer; using ConstPointer = SmartPointer; /** Smart Pointer type to a DataObject. */ using DataObjectPointer = DataObject::Pointer; /** \see LightObject::GetNameOfClass() */ itkOverrideGetNameOfClassMacro(ImageTransformer); /** Some convenient type alias. */ using InputImageType = TInputImage; using InputImagePointer = typename InputImageType::Pointer; using InputImageRegionType = typename InputImageType::RegionType; using InputImagePixelType = typename InputImageType::PixelType; /** ImageDimension constant */ static constexpr unsigned int InputImageDimension = TInputImage::ImageDimension; /** Set/Get the image input of this process object. */ using Superclass::SetInput; virtual void SetInput(const InputImageType * image); virtual void SetInput(unsigned int, const TInputImage * image); const InputImageType * GetInput() const; InputImageType * GetInput(); const InputImageType * GetInput(unsigned int idx) const; /** Push/Pop the input of this process object. These methods allow a * filter to model its input vector as a queue or stack. These * routines may not be appropriate for all filters, especially * filters with different types of inputs. These routines follow * the semantics of STL. * * The routines are useful for applications that need to process * "rolling" sets of images. For instance, if an application has 10 * images and they need to run a filter on images 1, 2, 3, 4, then * run the filter on images 2, 3, 4, 5, then run the filter on * images 3, 4, 5, 6, the application can accomplish this by popping * an input off the front of the input list and push a new image * onto the back of input list. Again, this only makes sense for * filters that single type of input. * * Other uses are also possible. For a single input filter, pushing * and popping inputs allow the application to temporarily replace * an input to a filter. */ virtual void PushBackInput(const InputImageType * image); void PopBackInput() override; virtual void PushFrontInput(const InputImageType * image); void PopFrontInput() override; protected: ImageTransformer(); ~ImageTransformer() override = default; /** The image transformer is assumed to need the whole input. * * This implementation of GenerateInputRequestedRegion() only * processes the inputs that are a subclass of the * ImageBase. If an input is another type of * DataObject (including an Image of a different dimension), they * are skipped by this method. The subclasses of ImageToImageFilter * are responsible for providing an implementation of * GenerateInputRequestedRegion() when there are multiple inputs of * different types. * * \sa ProcessObject::GenerateInputRequestedRegion(), * ImageSource::GenerateInputRequestedRegion() */ void GenerateInputRequestedRegion() override; /** A version of GenerateData() specific for image processing * filters. This implementation will split the processing across * multiple threads. The buffer is allocated by this method. Then * the BeforeThreadedGenerateData() method is called (if * provided). Then, a series of threads are spawned each calling * ThreadedGenerateData(). After all the threads have completed * processing, the AfterThreadedGenerateData() method is called (if * provided). If an image processing filter cannot be threaded, the * filter should provide an implementation of GenerateData(). That * implementation is responsible for allocating the output buffer. * If a filter can be threaded, it should NOT provide a * GenerateData() method but should provide a ThreadedGenerateData() * instead. * * \sa ThreadedGenerateData() */ void GenerateData() override; /** If an imaging filter can be implemented as a multithreaded * algorithm, the filter will provide an implementation of * ThreadedGenerateData(). This superclass will automatically split * the output image into a number of pieces, spawn multiple threads, * and call ThreadedGenerateData() in each thread. Prior to spawning * threads, the BeforeThreadedGenerateData() method is called. After * all the threads have completed, the AfterThreadedGenerateData() * method is called. If an image processing filter cannot support * threading, that filter should provide an implementation of the * GenerateData() method instead of providing an implementation of * ThreadedGenerateData(). If a filter provides a GenerateData() * method as its implementation, then the filter is responsible for * allocating the output data. If a filter provides a * ThreadedGenerateData() method as its implementation, then the * output memory will allocated automatically by this superclass. * The ThreadedGenerateData() method should only produce the output * specified by "inputThreadRegion" * parameter. ThreadedGenerateData() cannot write to any other * portion of the output image (as this is responsibility of a * different thread). * * \sa GenerateData(), SplitRequestedRegion() */ virtual void ThreadedGenerateData(const InputImageRegionType & inputRegionForThread, ThreadIdType threadId); /** Many filters do special management of image buffer and threading, * so this method provides just the multi-threaded invocation part * of GenerateData() method. */ void ClassicMultiThread(ThreadFunctionType callbackFunction); /** The GenerateData method normally allocates the buffers for all of the * outputs of a filter. Some filters may want to override this default * behavior. For example, a filter may have multiple outputs with * varying resolution. Or a filter may want to process data in place by * grafting its input to its output. */ virtual void AllocateOutputs(); /** If an imaging filter needs to perform processing after the buffer * has been allocated but before threads are spawned, the filter can * can provide an implementation for BeforeThreadedGenerateData(). The * execution flow in the default GenerateData() method will be: * 1) Allocate the output buffer * 2) Call BeforeThreadedGenerateData() * 3) Spawn threads, calling ThreadedGenerateData() in each thread. * 4) Call AfterThreadedGenerateData() * Note that this flow of control is only available if a filter provides * a ThreadedGenerateData() method and NOT a GenerateData() method. */ virtual void BeforeThreadedGenerateData() {} /** If an imaging filter needs to perform processing after all * processing threads have completed, the filter can can provide an * implementation for AfterThreadedGenerateData(). The execution * flow in the default GenerateData() method will be: * 1) Allocate the output buffer * 2) Call BeforeThreadedGenerateData() * 3) Spawn threads, calling ThreadedGenerateData() in each thread. * 4) Call AfterThreadedGenerateData() * Note that this flow of control is only available if a filter provides * a ThreadedGenerateData() method and NOT a GenerateData() method. */ virtual void AfterThreadedGenerateData() {} /** Split the input's RequestedRegion into "num" pieces, returning * region "i" as "splitRegion". This method is called "num" times. The * regions must not overlap. The method returns the number of pieces that * the routine is capable of splitting the input RequestedRegion, * i.e. return value is less than or equal to "num". */ virtual unsigned int SplitRequestedRegion(unsigned int i, unsigned int num, InputImageRegionType & splitRegion); /** Static function used as a "callback" by the MultiThreader. The threading * library will call this routine for each thread, which will delegate the * control to ThreadedGenerateData(). */ static ITK_THREAD_RETURN_FUNCTION_CALL_CONVENTION ThreaderCallback(void * arg); /** * PushBackInput(), PushFrontInput() in the public section force the * input to be the type expected by an ImageTransformer. However, * these methods end up "hiding" the versions from the superclass * (ProcessObject) whose arguments are DataObjects. Here, we re-expose * the versions from ProcessObject to avoid warnings about hiding * methods from the superclass. * NOTE: The same code resides in ImageToImageFilter */ using Superclass::PushBackInput; using Superclass::PushFrontInput; /** Internal structure used for passing image data into the threading library */ struct ThreadStruct { Pointer Filter; }; }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION # include "itkImageTransformer.hxx" #endif #endif