1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef itkExtractImageFilter_h
19 #define itkExtractImageFilter_h
20 
21 #include "itkInPlaceImageFilter.h"
22 #include "itkSmartPointer.h"
23 #include "itkExtractImageFilterRegionCopier.h"
24 
25 namespace itk
26 {
27 /** \class ExtractImageFilter
28  * \brief Decrease the image size by cropping the image to the selected
29  * region bounds.
30  *
31  * ExtractImageFilter changes the image boundary of an image by removing
32  * pixels outside the target region.  The target region must be specified.
33  *
34  * ExtractImageFilter also collapses dimensions so that the input image
35  * may have more dimensions than the output image (i.e. 4-D input image
36  * to a 3-D output image).  To specify what dimensions to collapse,
37  * the ExtractionRegion must be specified.  For any dimension dim where
38  * ExtractionRegion.Size[dim] = 0, that dimension is collapsed.  The
39  * index to collapse on is specified by ExtractionRegion.Index[dim].
40  * For example, we have a image 4D = a 4x4x4x4 image, and we want
41  * to get a 3D image, 3D = a 4x4x4 image, specified as [x,y,z,2] from 4D
42  * (i.e. the 3rd "time" slice from 4D).  The ExtractionRegion.Size =
43  * [4,4,4,0] and ExtractionRegion.Index = [0,0,0,2].
44  *
45  * The number of dimension in ExtractionRegion.Size and Index must =
46  * InputImageDimension.  The number of non-zero dimensions in
47  * ExtractionRegion.Size must = OutputImageDimension.
48  *
49  * The output image produced by this filter will have the same origin as the
50  * input image, while the ImageRegion of the output image will start at the
51  * starting index value provided in the ExtractRegion parameter.  If you are
52  * looking for a filter that will re-compute the origin of the output image,
53  * and provide an output image region whose index is set to zeros, then you may
54  * want to use the RegionOfInterestImageFilter.  The output spacing is is
55  * simply the collapsed version of the input spacing.
56  *
57  * Determining the direction of the collapsed output image from an larger
58  * dimensional input space is an ill defined problem in general.  It is
59  * required that the application developer select the desired transformation
60  * strategy for collapsing direction cosines.  It is REQUIRED that a strategy
61  * be explicitly requested (i.e. there is no working default).
62  * Direction Collapsing Strategies:
63  *    1)  DirectionCollapseToUnknown();
64  *            This is the default and the filter can not run when this is set.
65  *            The reason is to explicitly force the application developer to
66  *            define their desired behavior.
67  *    1)  DirectionCollapseToIdentity();
68  *            Output has identity direction no matter what
69  *    2)  DirectionCollapseToSubmatrix();
70  *            Output direction is the sub-matrix if it is positive definite, else throw an exception.
71  *
72  * This filter is implemented as a multithreaded filter.  It provides a
73  * DynamicThreadedGenerateData() method for its implementation.
74  *
75  * \note This filter is derived from InPlaceImageFilter. When the
76  * input to this filter matched the output requirested region, like
77  * with streaming filter for input, then setting this filter to run
78  * in-place will result in no copying of the bulk pixel data.
79  *
80  * \sa CropImageFilter
81  * \ingroup GeometricTransform
82  * \ingroup ITKCommon
83  *
84  * \wiki
85  * \wikiexample{ImageProcessing/ExtractImageFilter,Crop an image by specifying the region to keep}
86  * \endwiki
87  */
88 
89 template< typename TInputImage, typename TOutputImage >
90 class ITK_TEMPLATE_EXPORT ExtractImageFilter:
91   public InPlaceImageFilter< TInputImage, TOutputImage >
92 {
93 public:
94   ITK_DISALLOW_COPY_AND_ASSIGN(ExtractImageFilter);
95 
96   /** Standard class type aliases. */
97   using Self = ExtractImageFilter;
98   using Superclass = InPlaceImageFilter< TInputImage, TOutputImage >;
99   using Pointer = SmartPointer< Self >;
100   using ConstPointer = SmartPointer< const Self >;
101 
102   /** Method for creation through the object factory. */
103   itkNewMacro(Self);
104 
105   /** Run-time type information (and related methods). */
106   itkTypeMacro(ExtractImageFilter, InPlaceImageFilter);
107 
108   /** Image type information. */
109   using InputImageType = TInputImage;
110   using OutputImageType = TOutputImage;
111 
112   /** Typedef to describe the output and input image region types. */
113   using OutputImageRegionType = typename TOutputImage::RegionType;
114   using InputImageRegionType = typename TInputImage::RegionType;
115 
116   /** Typedef to describe the type of pixel. */
117   using OutputImagePixelType = typename TOutputImage::PixelType;
118   using InputImagePixelType = typename TInputImage::PixelType;
119 
120   /** Typedef to describe the output and input image index and size types. */
121   using OutputImageIndexType = typename TOutputImage::IndexType;
122   using InputImageIndexType = typename TInputImage::IndexType;
123   using OutputImageSizeType = typename TOutputImage::SizeType;
124   using InputImageSizeType = typename TInputImage::SizeType;
125 
126   typedef enum DirectionCollapseStrategyEnum {
127     DIRECTIONCOLLAPSETOUNKOWN=0,
128     DIRECTIONCOLLAPSETOIDENTITY=1,
129     DIRECTIONCOLLAPSETOSUBMATRIX=2,
130     DIRECTIONCOLLAPSETOGUESS=3
131   } DIRECTIONCOLLAPSESTRATEGY;
132 
133 
134   /**
135    * Set the strategy to be used to collapse physical space dimensions.
136    *
137    * itk::itkExtractImageFilter::DIRECTIONCOLLAPSETOIDENTITY
138    * Set the strategy so that all collapsed images have an identity direction.
139    * Use this strategy when you know that retention of the physical space
140    * orientation of the collapsed image is not important.
141    *
142    * itk::itkExtractImageFilter::DIRECTIONCOLLAPSETOGUESS
143    * Set the strategy so that all collapsed images where
144    * output direction is the sub-matrix if it is positive definite, else
145    * return identity. This is backwards compatible with ITKv3, but
146    * is highly discouraged because the results are difficult to
147    * anticipate under differing data scenerios.
148    *
149    * itk::itkExtractImageFilter::DIRECTIONCOLLAPSETOSUBMATRIX
150    * Set the strategy so that all collapsed images where
151    * output direction is the sub-matrix if it is positive definite,
152    * else throw an exception.  Use this strategy when it is known
153    * that properly identified physical space sub-volumes can be
154    * reliably extracted from a higher dimensional space.  For
155    * example when the application programmer knows that a 4D image
156    * is 3D+time, and that the 3D sub-space is properly defined.
157    */
SetDirectionCollapseToStrategy(const DIRECTIONCOLLAPSESTRATEGY choosenStrategy)158   void SetDirectionCollapseToStrategy(const DIRECTIONCOLLAPSESTRATEGY choosenStrategy)
159     {
160     switch(choosenStrategy)
161       {
162     case DIRECTIONCOLLAPSETOGUESS:
163     case DIRECTIONCOLLAPSETOIDENTITY:
164     case DIRECTIONCOLLAPSETOSUBMATRIX:
165       break;
166     case DIRECTIONCOLLAPSETOUNKOWN:
167     default:
168       itkExceptionMacro( << "Invalid Strategy Chosen for itk::ExtractImageFilter" );
169       }
170 
171     this->m_DirectionCollapseStrategy=choosenStrategy;
172     this->Modified();
173     }
174 
175   /** NOTE:  The SetDirectionCollapseToUknown is explicitly not defined.
176    * It is a state that a filter can be in only when it is first instantiate
177    * prior to being initialized.
178    */
179 
180   /**
181    * Get the currently set strategy for collapsing directions of physical space.
182    */
GetDirectionCollapseToStrategy()183   DIRECTIONCOLLAPSESTRATEGY GetDirectionCollapseToStrategy() const
184     {
185     return this->m_DirectionCollapseStrategy;
186     }
187 
188   /** \sa SetDirectionCollapseToStrategy */
SetDirectionCollapseToGuess()189   void SetDirectionCollapseToGuess()
190     {
191     this->SetDirectionCollapseToStrategy(DIRECTIONCOLLAPSETOGUESS);
192     }
193 
194   /** \sa SetDirectionCollapseToStrategy */
SetDirectionCollapseToIdentity()195   void SetDirectionCollapseToIdentity()
196     {
197     this->SetDirectionCollapseToStrategy(DIRECTIONCOLLAPSETOIDENTITY);
198     }
199 
200   /** \sa SetDirectionCollapseToStrategy */
SetDirectionCollapseToSubmatrix()201   void SetDirectionCollapseToSubmatrix()
202     {
203     this->SetDirectionCollapseToStrategy(DIRECTIONCOLLAPSETOSUBMATRIX);
204     }
205 
206 
207   /** ImageDimension enumeration */
208   static constexpr unsigned int InputImageDimension = TInputImage::ImageDimension;
209   static constexpr unsigned int OutputImageDimension = TOutputImage::ImageDimension;
210 
211   using ExtractImageFilterRegionCopierType = ImageToImageFilterDetail::ExtractImageFilterRegionCopier<
212     Self::InputImageDimension,
213     Self::OutputImageDimension >;
214 
215   /** Set/Get the output image region.
216    *  If any of the ExtractionRegion.Size = 0 for any particular dimension dim,
217    *  we have to collapse dimension dim.  This means the output image will have
218    *  'c' dimensions less than the input image, where c = number of
219    *  ExtractionRegion.Size = 0. */
220   void SetExtractionRegion(InputImageRegionType extractRegion);
221   itkGetConstMacro(ExtractionRegion, InputImageRegionType);
222 
223 #ifdef ITK_USE_CONCEPT_CHECKING
224   // Begin concept checking
225   itkConceptMacro( InputCovertibleToOutputCheck,
226                    ( Concept::Convertible< InputImagePixelType, OutputImagePixelType > ) );
227   // End concept checking
228 #endif
229 
230 protected:
231   ExtractImageFilter();
232   ~ExtractImageFilter() override = default;
233   void PrintSelf(std::ostream & os, Indent indent) const override;
234 
235   /** ExtractImageFilter can produce an image which is a different
236    * resolution than its input image.  As such, ExtractImageFilter
237    * needs to provide an implementation for
238    * GenerateOutputInformation() in order to inform the pipeline
239    * execution model.  The original documentation of this method is
240    * below.
241    *
242    * \sa ProcessObject::GenerateOutputInformaton()  */
243   void GenerateOutputInformation() override;
244 
245   /** This function calls the actual region copier to do the mapping from
246    * output image space to input image space.  It uses a
247    * Function object used for dispatching to various routines to
248    * copy an output region (start index and size) to an input region.
249    * For most filters, this is a trivial copy because most filters
250    * require the input dimension to match the output dimension.
251    * However, some filters like itk::ExtractImageFilter can
252    * support output images of a lower dimension that the input.
253    *
254    * \sa ImageToImageFilter::CallCopyRegion() */
255   void CallCopyOutputRegionToInputRegion(InputImageRegionType & destRegion,
256                                          const OutputImageRegionType & srcRegion) override;
257 
258   /** ExtractImageFilter can be implemented as a multithreaded filter.
259    * Therefore, this implementation provides a DynamicThreadedGenerateData()
260    * routine which is called for each processing thread. The output
261    * image data is allocated automatically by the superclass prior to
262    * calling DynamicThreadedGenerateData().  DynamicThreadedGenerateData can only
263    * write to the portion of the output image specified by the
264    * parameter "outputRegionForThread"
265    * \sa ImageToImageFilter::ThreadedGenerateData(),
266    *     ImageToImageFilter::GenerateData()  */
267   void DynamicThreadedGenerateData(const OutputImageRegionType & outputRegionForThread) override;
268 
269   /** Overridden to check if there is no work to be done, before
270    * calling superclass' implementation.  */
271   void GenerateData() override;
272 
273   InputImageRegionType m_ExtractionRegion;
274 
275   OutputImageRegionType m_OutputImageRegion;
276 
277 private:
278   DIRECTIONCOLLAPSESTRATEGY m_DirectionCollapseStrategy;
279 };
280 } // end namespace itk
281 
282 #ifndef ITK_MANUAL_INSTANTIATION
283 #include "itkExtractImageFilter.hxx"
284 #endif
285 
286 #endif
287